getConfigRegistry() {
+ return configRegistry;
+ }
+
+ /**
+ * Interface for registering your own options in the TASmod config
+ *
+ * @see com.minecrafttas.tasmod.registries.TASmodConfig TASmodConfig
+ * @author Scribble
+ */
+ public interface ConfigOptions extends Registerable {
+ /**
+ * @return The config key name that is stored in the file
+ */
+ public String getConfigKey();
+
+ /**
+ * @return The default value that is used if the config key doesn't exist yet
+ */
+ public String getDefaultValue();
+ }
+}
diff --git a/src/main/java/com/minecrafttas/mctcommon/MCTCommon.java b/src/main/java/com/minecrafttas/mctcommon/MCTCommon.java
index 718fedf4..b9451446 100644
--- a/src/main/java/com/minecrafttas/mctcommon/MCTCommon.java
+++ b/src/main/java/com/minecrafttas/mctcommon/MCTCommon.java
@@ -7,13 +7,13 @@
public class MCTCommon {
public static final Logger LOGGER = LogManager.getLogger("MCTCommon");
-
+
public static final Marker Event = MarkerManager.getMarker("Event");
-
+
public static final Marker Server = MarkerManager.getMarker("Server");
-
+
public static final Marker Client = MarkerManager.getMarker("Client");
-
+
public static final Marker Timeout = MarkerManager.getMarker("Timeout");
}
diff --git a/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java b/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java
index 774ca47f..0a42ea10 100644
--- a/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java
+++ b/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java
@@ -1,11 +1,13 @@
package com.minecrafttas.mctcommon.events;
-import org.apache.commons.lang3.ClassUtils;
-
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.ClassUtils;
/**
* Registry for making objects available to listen for events.
@@ -94,7 +96,8 @@ public static void register(EventBase eventListener) {
if (eventListener == null) {
throw new NullPointerException("Tried to register a packethandler with value null");
}
- for (Class> type : eventListener.getClass().getInterfaces()) {
+
+ for (Class> type : searchForInterfaces(eventListener.getClass())) {
if (EventBase.class.isAssignableFrom(type)) {
// If a new event type is being registered, add a new arraylist
@@ -107,6 +110,18 @@ public static void register(EventBase eventListener) {
}
}
+ private static Class>[] searchForInterfaces(Class> clazz) {
+ if (clazz == null) {
+ return new Class>[] {};
+ }
+ Class>[] interfaces = clazz.getInterfaces();
+ Class> superclass = clazz.getSuperclass();
+ if (superclass != null && superclass != Object.class) {
+ interfaces = ArrayUtils.addAll(interfaces, searchForInterfaces(superclass));
+ }
+ return interfaces;
+ }
+
/**
* Registers multiple objects to be an event listener. The objects must
* implement an event extending {@link EventBase}
@@ -119,6 +134,18 @@ public static void register(EventBase... eventListeners) {
}
}
+ /**
+ * Registers multiple objects to be an event listener. The objects must
+ * implement an event extending {@link EventBase}
+ *
+ * @param eventListeners The event listeners to register
+ */
+ public static void register(List extends EventBase> eventListeners) {
+ for (EventBase eventListener : eventListeners) {
+ register(eventListener);
+ }
+ }
+
/**
* Unregisters an object from being an event listener.
*
@@ -128,7 +155,7 @@ public static void unregister(EventBase eventListener) {
if (eventListener == null) {
throw new NullPointerException("Tried to unregister a packethandler with value null");
}
- for (Class> type : eventListener.getClass().getInterfaces()) {
+ for (Class> type : searchForInterfaces(eventListener.getClass())) {
if (EventBase.class.isAssignableFrom(type)) {
ArrayList registryList = EVENTLISTENER_REGISTRY.get(type);
if (registryList != null) {
@@ -153,6 +180,17 @@ public static void unregister(EventBase... eventListeners) {
}
}
+ /**
+ * Unregisters multiple objects from being an event listener.
+ *
+ * @param eventListener The event listeners to unregister
+ */
+ public static void unregister(List extends EventBase> eventListeners) {
+ for (EventBase eventListener : eventListeners) {
+ unregister(eventListener);
+ }
+ }
+
/**
* Fires an event without parameters
*
diff --git a/src/main/java/com/minecrafttas/mctcommon/file/AbstractDataFile.java b/src/main/java/com/minecrafttas/mctcommon/file/AbstractDataFile.java
new file mode 100644
index 00000000..9929075d
--- /dev/null
+++ b/src/main/java/com/minecrafttas/mctcommon/file/AbstractDataFile.java
@@ -0,0 +1,233 @@
+package com.minecrafttas.mctcommon.file;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Type;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.InvalidPropertiesFormatException;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import com.minecrafttas.mctcommon.MCTCommon;
+
+public abstract class AbstractDataFile {
+
+ /**
+ * The save location of this data file
+ */
+ protected final Path file;
+
+ /**
+ * The name of this data file, used in logging
+ */
+ protected final String name;
+ /**
+ * The comment stored in the data file, to help recognize the file
+ */
+ protected final String comment;
+
+ /**
+ * The properties of this data file.
+ */
+ protected Properties properties;
+
+ /**
+ * Creates an abstract data file and creates it's directory if it doesn't exist
+ * @param file The {@link #file save location} of the data file
+ * @param name The {@link #name} of the data file, used in logging
+ * @param comment The {@link #comment} in the data file
+ */
+ protected AbstractDataFile(Path file, String name, String comment) {
+ this.file = file;
+ this.name = name;
+ this.comment = comment;
+ this.properties = new Properties();
+
+ createDirectory(file);
+ }
+
+ /**
+ * Creates the directory for the file if it doesn't exist
+ * @param file The file to create the directory for
+ */
+ protected void createDirectory(Path file) {
+ try {
+ Files.createDirectories(file.getParent());
+ } catch (IOException e) {
+ MCTCommon.LOGGER.catching(e);
+ }
+ }
+
+ public void load() {
+ if (Files.exists(file)) {
+ load(file);
+ }
+ }
+
+ public void load(Path file) {
+ InputStream fis;
+ Properties newProp = new Properties();
+ try {
+ fis = Files.newInputStream(file);
+ newProp.load(fis);
+ fis.close();
+ } catch (InvalidPropertiesFormatException e) {
+ MCTCommon.LOGGER.error("The {} file could not be read", name, e);
+ return;
+ } catch (FileNotFoundException e) {
+ MCTCommon.LOGGER.warn("No {} file found: {}", name, file);
+ return;
+ } catch (IOException e) {
+ MCTCommon.LOGGER.error("An error occured while reading the {} file", file, e);
+ return;
+ }
+ this.properties = newProp;
+ }
+
+ /**
+ * Loads the xml {@link #file} into {@link #properties} if it exists
+ */
+ public void loadFromXML() {
+ if (Files.exists(file)) {
+ loadFromXML(file);
+ }
+ }
+
+ /**
+ * @param file The xml file to load into {@link #properties}
+ */
+ public void loadFromXML(Path file) {
+ InputStream fis;
+ Properties newProp = new Properties();
+ try {
+ fis = Files.newInputStream(file);
+ newProp.loadFromXML(fis);
+ fis.close();
+ } catch (InvalidPropertiesFormatException e) {
+ MCTCommon.LOGGER.error("The {} file could not be read", name, e);
+ return;
+ } catch (FileNotFoundException e) {
+ MCTCommon.LOGGER.warn("No {} file found: {}", name, file);
+ return;
+ } catch (IOException e) {
+ MCTCommon.LOGGER.error("An error occured while reading the {} file", file, e);
+ return;
+ }
+ this.properties = newProp;
+ }
+
+ public void loadFromJson() {
+ loadFromJson(file);
+ }
+
+ public void loadFromJson(Path file) {
+ //@formatter:off
+ Gson json = new GsonBuilder()
+ .registerTypeAdapter(Properties.class, new PropertiesDeserializer())
+ .create();
+ //@formatter:on
+
+ String in;
+ try {
+ in = new String(Files.readAllBytes(file));
+ } catch (IOException e) {
+ MCTCommon.LOGGER.catching(e);
+ return;
+ }
+
+ properties = json.fromJson(in, Properties.class);
+ }
+
+ public void save() {
+ this.save(file);
+ }
+
+ public void save(Path file) {
+ try {
+ OutputStream fos = Files.newOutputStream(file);
+ properties.store(fos, comment);
+ fos.close();
+ } catch (IOException e) {
+ MCTCommon.LOGGER.catching(e);
+ }
+ }
+
+ /**
+ * Saves the {@link #properties} to the {@link #file} location
+ */
+ public void saveToXML() {
+ this.saveToXML(file);
+ }
+
+ /**
+ * Saves the {@link #properties} to a specified file
+ * @param file The file to save the {@link #properties} to
+ */
+ public void saveToXML(Path file) {
+ try {
+ OutputStream fos = Files.newOutputStream(file);
+ properties.storeToXML(fos, comment, "UTF-8");
+ fos.close();
+ } catch (IOException e) {
+ MCTCommon.LOGGER.catching(e);
+ }
+ }
+
+ public void saveToJson() {
+ saveToJson(file);
+ }
+
+ public void saveToJson(Path file) {
+ //@formatter:off
+ Gson json = new GsonBuilder()
+ .registerTypeAdapter(Properties.class, new PropertiesSerializer())
+ .setPrettyPrinting()
+ .create();
+ //@formatter:on
+ try {
+ String element = json.toJson(properties);
+ Files.write(file, element.getBytes());
+ } catch (IOException e) {
+ MCTCommon.LOGGER.catching(e);
+ }
+ }
+
+ public class PropertiesSerializer implements JsonSerializer {
+
+ @Override
+ public JsonElement serialize(Properties src, Type typeOfSrc, JsonSerializationContext context) {
+ JsonObject obj = new JsonObject();
+ src.forEach((key, val) -> {
+ obj.addProperty((String) key, (String) val);
+ });
+ return obj;
+ }
+ }
+
+ public class PropertiesDeserializer implements JsonDeserializer {
+
+ @Override
+ public Properties deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+ Properties properties = new Properties();
+ JsonObject obj = json.getAsJsonObject();
+ for (Entry elem : obj.entrySet()) {
+ String key = elem.getKey();
+ String val = elem.getValue().getAsString();
+ properties.put(key, val);
+ }
+ return properties;
+ }
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java
index 57899423..a495dfad 100644
--- a/src/main/java/com/minecrafttas/tasmod/TASmod.java
+++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java
@@ -1,6 +1,5 @@
package com.minecrafttas.tasmod;
-import java.io.File;
import java.io.IOException;
import org.apache.logging.log4j.LogManager;
@@ -26,18 +25,18 @@
import com.minecrafttas.tasmod.commands.CommandSavestate;
import com.minecrafttas.tasmod.commands.CommandTickrate;
import com.minecrafttas.tasmod.commands.TabCompletionUtils;
-import com.minecrafttas.tasmod.ktrng.KillTheRNGHandler;
import com.minecrafttas.tasmod.playback.PlaybackControllerServer;
import com.minecrafttas.tasmod.playback.metadata.integrated.StartpositionMetadataExtension;
import com.minecrafttas.tasmod.registries.TASmodPackets;
import com.minecrafttas.tasmod.savestates.SavestateHandlerServer;
-import com.minecrafttas.tasmod.savestates.files.SavestateTrackerFile;
+import com.minecrafttas.tasmod.savestates.storage.SavestateMotionStorage;
import com.minecrafttas.tasmod.tickratechanger.TickrateChangerServer;
import com.minecrafttas.tasmod.ticksync.TickSyncServer;
import com.minecrafttas.tasmod.util.LoggerMarkers;
import com.minecrafttas.tasmod.util.Scheduler;
import net.fabricmc.api.ModInitializer;
+import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.impl.FabricLoaderImpl;
import net.minecraft.server.MinecraftServer;
@@ -48,21 +47,24 @@
*/
public class TASmod implements ModInitializer, EventServerInit, EventServerStop {
- private static MinecraftServer serverInstance;
-
public static final Logger LOGGER = LogManager.getLogger("TASmod");
+ public static String version = "dev";
+
+ private static MinecraftServer serverInstance;
+
public static PlaybackControllerServer playbackControllerServer = new PlaybackControllerServer();;
public static SavestateHandlerServer savestateHandlerServer;
- public static KillTheRNGHandler ktrngHandler;
+ // public static KillTheRNGHandler ktrngHandler;
public static TickrateChangerServer tickratechanger;
public static TickSyncServer ticksyncServer;
public static final Scheduler tickSchedulerServer = new Scheduler();
+ public static final Scheduler gameLoopSchedulerServer = new Scheduler();
public static Server server;
@@ -81,12 +83,18 @@ public void onInitialize() {
LOGGER.info("Initializing TASmod");
+ String modVersion = FabricLoader.getInstance().getModContainer("tasmod").get().getMetadata().getVersion().getFriendlyString();
+
+ if (!"${mod_version}".equals(modVersion)) {
+ version = modVersion;
+ }
+
// Start ticksync
ticksyncServer = new TickSyncServer();
// Initilize KillTheRNG
LOGGER.info("Testing connection with KillTheRNG");
- ktrngHandler = new KillTheRNGHandler(FabricLoaderImpl.INSTANCE.isModLoaded("killtherng"));
+ // ktrngHandler = new KillTheRNGHandler(FabricLoaderImpl.INSTANCE.isModLoaded("killtherng"));
// Initialize TickrateChanger
tickratechanger = new TickrateChangerServer(LOGGER);
@@ -95,17 +103,20 @@ public void onInitialize() {
EventListenerRegistry.register(this);
EventListenerRegistry.register(ticksyncServer);
EventListenerRegistry.register(tickratechanger);
- EventListenerRegistry.register(ktrngHandler);
+ // EventListenerRegistry.register(ktrngHandler);
// Register packet handlers
LOGGER.info(LoggerMarkers.Networking, "Registering network handlers");
PacketHandlerRegistry.register(ticksyncServer);
PacketHandlerRegistry.register(tickratechanger);
- PacketHandlerRegistry.register(ktrngHandler);
+ // PacketHandlerRegistry.register(ktrngHandler);
PacketHandlerRegistry.register(playbackControllerServer);
PacketHandlerRegistry.register(startPositionMetadataExtension);
PacketHandlerRegistry.register(tabCompletionUtils);
PacketHandlerRegistry.register(commandFileCommand);
+ SavestateMotionStorage motionStorage = new SavestateMotionStorage();
+ PacketHandlerRegistry.register(motionStorage);
+ EventListenerRegistry.register(motionStorage);
}
@Override
@@ -129,16 +140,9 @@ public void onServerInit(MinecraftServer server) {
CommandRegistry.registerServerCommand(new CommandPlayUntil(), server);
CommandRegistry.registerServerCommand(commandFileCommand, server);
- // Save Loadstate Count
- File savestateDirectory = new File(server.getDataDirectory() + File.separator + "saves" + File.separator + "savestates" + File.separator);
- try {
- new SavestateTrackerFile(new File(savestateDirectory, server.getFolderName() + "-info.txt")); // TODO Ew, remove
- } catch (IOException e) {
- e.printStackTrace();
- }
-
savestateHandlerServer = new SavestateHandlerServer(server, LOGGER);
PacketHandlerRegistry.register(savestateHandlerServer);
+ PacketHandlerRegistry.register(savestateHandlerServer.getPlayerHandler());
if (!server.isDedicatedServer()) {
TASmod.tickratechanger.ticksPerSecond = 0F;
@@ -169,6 +173,8 @@ public void onServerStop(MinecraftServer mcserver) {
if (savestateHandlerServer != null) {
PacketHandlerRegistry.unregister(savestateHandlerServer); // Unregistering the savestatehandler, as a new instance is registered in onServerStart()
+ PacketHandlerRegistry.unregister(savestateHandlerServer.getPlayerHandler());
+
savestateHandlerServer = null;
}
}
diff --git a/src/main/java/com/minecrafttas/tasmod/TASmodClient.java b/src/main/java/com/minecrafttas/tasmod/TASmodClient.java
index b8aaa122..04382371 100644
--- a/src/main/java/com/minecrafttas/tasmod/TASmodClient.java
+++ b/src/main/java/com/minecrafttas/tasmod/TASmodClient.java
@@ -4,11 +4,14 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
import org.apache.logging.log4j.Level;
import com.minecrafttas.mctcommon.Configuration;
+import com.minecrafttas.mctcommon.ConfigurationRegistry;
import com.minecrafttas.mctcommon.KeybindManager;
import com.minecrafttas.mctcommon.LanguageManager;
import com.minecrafttas.mctcommon.events.EventClient.EventClientInit;
@@ -33,6 +36,7 @@
import com.minecrafttas.tasmod.registries.TASmodKeybinds;
import com.minecrafttas.tasmod.registries.TASmodPackets;
import com.minecrafttas.tasmod.savestates.SavestateHandlerClient;
+import com.minecrafttas.tasmod.savestates.handlers.SavestatePlayerHandler;
import com.minecrafttas.tasmod.tickratechanger.TickrateChangerClient;
import com.minecrafttas.tasmod.ticksync.TickSyncClient;
import com.minecrafttas.tasmod.util.LoggerMarkers;
@@ -50,41 +54,40 @@
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.server.MinecraftServer;
-public class TASmodClient implements ClientModInitializer, EventClientInit, EventPlayerJoinedClientSide, EventOpenGui{
-
+public class TASmodClient implements ClientModInitializer, EventClientInit, EventPlayerJoinedClientSide, EventOpenGui {
public static VirtualInput virtual;
public static TickSyncClient ticksyncClient;
-
+
public static final String tasdirectory = Minecraft.getMinecraft().mcDataDir.getAbsolutePath() + File.separator + "saves" + File.separator + "tasfiles";
public static final String savestatedirectory = Minecraft.getMinecraft().mcDataDir.getAbsolutePath() + File.separator + "saves" + File.separator + "savestates";
public static InfoHud hud;
-
+
public static ShieldDownloader shieldDownloader;
-
+
public static TickrateChangerClient tickratechanger = new TickrateChangerClient();
-
+
public static Scheduler gameLoopSchedulerClient = new Scheduler();
-
+
public static Scheduler tickSchedulerClient = new Scheduler();
-
+
public static Scheduler openMainMenuScheduler = new Scheduler();
-
+
public static Configuration config;
-
+
public static LoadingScreenHandler loadingScreenHandler;
-
+
public static KeybindManager keybindManager;
-
+
public static SavestateHandlerClient savestateHandlerClient = new SavestateHandlerClient();
-
+
public static Client client;
-
+
public static CreditsMetadataExtension creditsMetadataExtension = new CreditsMetadataExtension();
-
+
public static StartpositionMetadataExtension startpositionMetadataExtension = new StartpositionMetadataExtension();
/**
* The container where all inputs get stored during recording or stored and
@@ -93,28 +96,30 @@ public class TASmodClient implements ClientModInitializer, EventClientInit, Even
public static PlaybackControllerClient controller = new PlaybackControllerClient();
public static void createTASDir() {
- File tasDir=new File(tasdirectory);
- if(!tasDir.exists()) {
+ File tasDir = new File(tasdirectory);
+ if (!tasDir.exists()) {
tasDir.mkdir();
}
}
-
+
public static void createSavestatesDir() {
- File savestateDir=new File(savestatedirectory);
- if(!savestateDir.exists()) {
+ File savestateDir = new File(savestatedirectory);
+ if (!savestateDir.exists()) {
savestateDir.mkdir();
}
}
@Override
public void onInitializeClient() {
-
+
LanguageManager.registerMod("tasmod");
+ registerConfigValues();
+
loadConfig(Minecraft.getMinecraft());
-
- virtual=new VirtualInput(LOGGER);
-
+
+ virtual = new VirtualInput(LOGGER);
+
// Initialize InfoHud
hud = new InfoHud();
// Initialize shield downloader
@@ -125,27 +130,28 @@ public void onInitializeClient() {
ticksyncClient = new TickSyncClient();
// Initialize keybind manager
keybindManager = new KeybindManager(VirtualKeybindings::isKeyDownExceptTextfield);
-
+
registerEventListeners();
-
+
registerNetworkPacketHandlers();
-
+
// Starting local server instance
try {
- TASmod.server = new Server(TASmod.networkingport-1, TASmodPackets.values());
+ TASmod.server = new Server(TASmod.networkingport - 1, TASmodPackets.values());
} catch (Exception e) {
LOGGER.error("Unable to launch TASmod server: {}", e.getMessage());
}
-
+
}
-
+
private void registerNetworkPacketHandlers() {
// Register packet handlers
LOGGER.info(LoggerMarkers.Networking, "Registering network handlers on client");
PacketHandlerRegistry.register(controller);
PacketHandlerRegistry.register(ticksyncClient);
PacketHandlerRegistry.register(tickratechanger);
- PacketHandlerRegistry.register(savestateHandlerClient);
+ PacketHandlerRegistry.register(savestateHandlerClient);
+ PacketHandlerRegistry.register(new SavestatePlayerHandler(null));
}
private void registerEventListeners() {
@@ -155,8 +161,8 @@ private void registerEventListeners() {
EventListenerRegistry.register(loadingScreenHandler);
EventListenerRegistry.register(ticksyncClient);
EventListenerRegistry.register(keybindManager);
- EventListenerRegistry.register((EventOpenGui)(gui -> {
- if(gui instanceof GuiMainMenu) {
+ EventListenerRegistry.register((EventOpenGui) (gui -> {
+ if (gui instanceof GuiMainMenu) {
openMainMenuScheduler.runAllTasks();
}
return gui;
@@ -164,26 +170,28 @@ private void registerEventListeners() {
EventListenerRegistry.register(controller);
EventListenerRegistry.register(creditsMetadataExtension);
EventListenerRegistry.register(startpositionMetadataExtension);
-
+
EventListenerRegistry.register(desyncMonitorFileCommandExtension);
-
+
EventListenerRegistry.register(TASmodAPIRegistry.PLAYBACK_METADATA);
EventListenerRegistry.register(TASmodAPIRegistry.PLAYBACK_FILE_COMMAND);
+ EventListenerRegistry.register(new LoggerMarkers());
+ EventListenerRegistry.register(savestateHandlerClient);
}
-
+
@Override
public void onClientInit(Minecraft mc) {
registerKeybindings(mc);
registerPlaybackMetadata(mc);
registerSerialiserFlavors(mc);
registerFileCommands();
-
+
createTASDir();
createSavestatesDir();
}
boolean waszero;
-
+
boolean isLoading;
@Override
@@ -191,29 +199,28 @@ public void onPlayerJoinedClientSide(EntityPlayerSP player) {
Minecraft mc = Minecraft.getMinecraft();
ServerData data = mc.getCurrentServerData();
MinecraftServer server = TASmod.getServerInstance();
-
+
String ip = null;
int port;
boolean local;
- if(server!=null) {
+ if (server != null) {
ip = "localhost";
- port = TASmod.networkingport-1;
+ port = TASmod.networkingport - 1;
local = true;
} else {
ip = data.serverIP.split(":")[0];
port = TASmod.networkingport;
local = false;
}
-
+
String connectedIP = null;
try {
connectedIP = client.getRemote();
} catch (IOException e) {
e.printStackTrace();
}
-
-
- if(!(ip+":"+port).equals(connectedIP)) { // TODO Clean this up. Make TASmodNetworkHandler out of this... Maybe with Permission system?
+
+ if (!(ip + ":" + port).equals(connectedIP)) { // TODO Clean this up. Make TASmodNetworkHandler out of this... Maybe with Permission system?
try {
LOGGER.info("Closing client connection: {}", client.getRemote());
client.disconnect();
@@ -222,7 +229,7 @@ public void onPlayerJoinedClientSide(EntityPlayerSP player) {
}
final String IP = ip;
final int PORT = port;
- gameLoopSchedulerClient.add(()->{
+ gameLoopSchedulerClient.add(() -> {
try {
// connect to server and authenticate
client = new Client(IP, PORT, TASmodPackets.values(), mc.getSession().getUsername(), local);
@@ -253,17 +260,17 @@ public GuiScreen onOpenGui(GuiScreen gui) {
}
return gui;
}
-
+
private void initializeCustomPacketHandler() {
if (client == null) {
Minecraft mc = Minecraft.getMinecraft();
String IP = "localhost";
int PORT = TASmod.networkingport - 1;
-
+
// Get the connection on startup from config
String configAddress = config.get(TASmodConfig.ServerConnection);
- if(configAddress != null && !configAddress.isEmpty()) {
+ if (configAddress != null && !configAddress.isEmpty()) {
String[] ipSplit = configAddress.split(":");
IP = ipSplit[0];
try {
@@ -274,7 +281,7 @@ private void initializeCustomPacketHandler() {
PORT = TASmod.networkingport - 1;
}
}
-
+
try {
// connect to server and authenticate
client = new Client(IP, PORT, TASmodPackets.values(), mc.getSession().getUsername(), true);
@@ -282,45 +289,54 @@ private void initializeCustomPacketHandler() {
LOGGER.error("Unable to connect TASmod client: {}", e);
}
ticksyncClient.setEnabled(true);
- }
+ }
}
-
+
private void registerKeybindings(Minecraft mc) {
Arrays.stream(TASmodKeybinds.valuesKeybind()).forEach(keybindManager::registerKeybind);
Arrays.stream(TASmodKeybinds.valuesVanillaKeybind()).forEach(VirtualKeybindings::registerBlockedKeyBinding);
}
-
+
private void registerPlaybackMetadata(Minecraft mc) {
TASmodAPIRegistry.PLAYBACK_METADATA.register(creditsMetadataExtension);
TASmodAPIRegistry.PLAYBACK_METADATA.register(startpositionMetadataExtension);
}
-
+
public static Beta1Flavor betaFlavor = new Beta1Flavor();
-
+
private void registerSerialiserFlavors(Minecraft mc) {
TASmodAPIRegistry.SERIALISER_FLAVOR.register(betaFlavor);
}
-
+
public static DesyncMonitorFileCommandExtension desyncMonitorFileCommandExtension = new DesyncMonitorFileCommandExtension();
public static OptionsFileCommandExtension optionsFileCommandExtension = new OptionsFileCommandExtension();
public static LabelFileCommandExtension labelFileCommandExtension = new LabelFileCommandExtension();
-
+
private void registerFileCommands() {
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.register(desyncMonitorFileCommandExtension);
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.register(optionsFileCommandExtension);
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.register(labelFileCommandExtension);
-
+
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.setConfig(config);
}
-
+
+ private static final ConfigurationRegistry CONFIG_REGISTRY = new ConfigurationRegistry();
+
+ private void registerConfigValues() {
+ CONFIG_REGISTRY.register(TASmodConfig.values());
+ }
+
private void loadConfig(Minecraft mc) {
- File configDir = new File(mc.mcDataDir, "config");
- if(!configDir.exists()) {
- configDir.mkdir();
+ Path configDir = mc.mcDataDir.toPath().resolve("config");
+ if (!Files.exists(configDir)) {
+ try {
+ Files.createDirectory(configDir);
+ } catch (IOException e) {
+ LOGGER.catching(e);
+ }
}
- config = new Configuration("TASmod configuration", new File(configDir, "tasmod.cfg"));
- config.register(TASmodConfig.values());
- config.load();
- config.save();
+ config = new Configuration("TASmod configuration", configDir.resolve("tasmod.cfg"), CONFIG_REGISTRY);
+ config.loadFromXML();
+ config.saveToXML();
}
}
diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandRecord.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandRecord.java
index 56f58e36..7934574f 100644
--- a/src/main/java/com/minecrafttas/tasmod/commands/CommandRecord.java
+++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandRecord.java
@@ -43,9 +43,9 @@ public void execute(MinecraftServer server, ICommandSender sender, String[] args
}
if (args.length < 1) {
TASmod.playbackControllerServer.toggleRecording();
- TASmod.tickSchedulerServer.add(() ->{
- TASmod.ktrngHandler.broadcastStartSeed();
- });
+// TASmod.tickSchedulerServer.add(() ->{
+// TASmod.ktrngHandler.broadcastStartSeed();
+// });
} else if (args.length > 1) {
sender.sendMessage(new TextComponentString(TextFormatting.RED + "Too many arguments. " + getUsage(sender)));
}
diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandSavestate.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandSavestate.java
index 0d997da9..7abd7317 100644
--- a/src/main/java/com/minecrafttas/tasmod/commands/CommandSavestate.java
+++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandSavestate.java
@@ -37,7 +37,6 @@ public int getRequiredPermissionLevel() {
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException {
- sender.sendMessage(new TextComponentString("Savestates might not work correctly at the moment... rewriting a lot of core features, which might break this..."));
if (args.length == 0) {
sendHelp(sender);
} else if (args.length >= 1) {
@@ -63,7 +62,7 @@ public void execute(MinecraftServer server, ICommandSender sender, String[] args
} else if (args.length == 3) {
int args1 = processIndex(args[1]);
int args2 = processIndex(args[2]);
- int count = (args2+1) - args1;
+ int count = (args2 + 1) - args1;
TextComponentString confirm = new TextComponentString(TextFormatting.YELLOW + "Are you sure you want to delete " + count + (count == 1 ? " savestate? " : " savestates? ") + TextFormatting.GREEN + "[YES]");
confirm.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/savestate deletDis %s %s", args[1], args[2])));
sender.sendMessage(confirm);
@@ -105,22 +104,21 @@ private void sendHelp(ICommandSender sender, int i) throws CommandException {
if (i > 3) {
throw new CommandException("This help page doesn't exist (yet?)", new Object[] {});
}
- if(i==1) {
- sender.sendMessage(new TextComponentString(TextFormatting.GOLD+"-------------------Savestate Help 1--------------------\n"+TextFormatting.RESET
- + "Makes a backup of the minecraft world you are currently playing.\n\n"
- + "The mod will keep track of the number of savestates you made in the 'current index' number which is currently "+TextFormatting.AQUA+currentIndex+TextFormatting.RESET
- + String.format(". If you make a new savestate via %s/savestate save%s or by pressing %sJ%s by default, ", TextFormatting.AQUA, TextFormatting.RESET, TextFormatting.AQUA, TextFormatting.RESET)
- + "the current index will increase by one. "
- + String.format("If you load a savestate with %s/savestate load%s or %sK%s by default, it will load the savestate at the current index.\n", TextFormatting.AQUA, TextFormatting.RESET, TextFormatting.AQUA, TextFormatting.RESET)));
- }else if(i==2) {
+ if (i == 1) {
+ sender.sendMessage(new TextComponentString(TextFormatting.GOLD + "-------------------Savestate Help 1--------------------\n" + TextFormatting.RESET
+ + "Makes a backup of the minecraft world you are currently playing.\n\n"
+ + "The mod will keep track of the number of savestates you made in the 'current index' number which is currently " + TextFormatting.AQUA + currentIndex + TextFormatting.RESET
+ + String.format(". If you make a new savestate via %s/savestate save%s or by pressing %sJ%s by default, ", TextFormatting.AQUA, TextFormatting.RESET, TextFormatting.AQUA, TextFormatting.RESET)
+ + "the current index will increase by one. "
+ + String.format("If you load a savestate with %s/savestate load%s or %sK%s by default, it will load the savestate at the current index.\n", TextFormatting.AQUA, TextFormatting.RESET, TextFormatting.AQUA, TextFormatting.RESET)));
+ } else if (i == 2) {
sender.sendMessage(new TextComponentString(String.format("%1$s-------------------Savestate Help 2--------------------\n"
+ "You can load or save savestates in different indexes by specifying the index: %3$s/savestate %4$s %5$s%2$s\n"
+ "This will change the %5$scurrent index%2$s to the index you specified.\n\n"
+ "So, if you have the savestates %3$s1, 2, 3%2$s and your %5$scurrent index%2$s is %3$s3%2$s, %3$s/savestate %4$sload %5$s2%2$s will load the second savestate and will set the %5$scurrent index%2$s to %3$s2%2$s.\n"
+ "But if you savestate again you will OVERWRITE the third savestate, so keep that in mind!!\n\n"
- + "The savestate at index 0 will be the savestate when you started the TAS recording and can't be deleted or overwritten with this command"
- , /*1*/TextFormatting.GOLD, /*2*/TextFormatting.RESET, /*3*/TextFormatting.AQUA, /*4*/TextFormatting.GREEN, /*5*/TextFormatting.YELLOW)));
- }else if(i==3) {
+ + "The savestate at index 0 will be the savestate when you started the TAS recording and can't be deleted or overwritten with this command", /*1*/TextFormatting.GOLD, /*2*/TextFormatting.RESET, /*3*/TextFormatting.AQUA, /*4*/TextFormatting.GREEN, /*5*/TextFormatting.YELLOW)));
+ } else if (i == 3) {
sender.sendMessage(new TextComponentString(String.format("%1$s-------------------Savestate Help 3--------------------\n%2$s"
+ "%3$s/savestate %4$ssave%2$s - Make a savestate at the next index\n"
+ "%3$s/savestate %4$ssave%5$s %2$s - Make a savestate at the specified index\n"
@@ -133,21 +131,21 @@ private void sendHelp(ICommandSender sender, int i) throws CommandException {
/*1*/TextFormatting.GOLD, /*2*/TextFormatting.RESET, /*3*/TextFormatting.AQUA, /*4*/TextFormatting.GREEN, /*5*/TextFormatting.YELLOW, /*6*/(currentIndex - 1))));
return;
}
- TextComponentString nextPage=new TextComponentString(TextFormatting.GOLD+"Click here to go to the next help page ("+(i+1)+")\n");
- nextPage.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/savestate help "+(i+1)+""));
+ TextComponentString nextPage = new TextComponentString(TextFormatting.GOLD + "Click here to go to the next help page (" + (i + 1) + ")\n");
+ nextPage.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/savestate help " + (i + 1) + ""));
sender.sendMessage(nextPage);
}
@Override
public List getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) {
if (args.length == 1) {
- return getListOfStringsMatchingLastWord(args, new String[] { "save", "load", "delete", "list", "help"});
+ return getListOfStringsMatchingLastWord(args, new String[] { "save", "load", "delete", "list", "help" });
} else if (args.length == 2 && !"list".equals(args[0])) {
sender.sendMessage(new TextComponentString("Available indexes: " + TextFormatting.AQUA + TASmod.savestateHandlerServer.getIndexesAsString()));
}
return super.getTabCompletions(server, sender, args, targetPos);
}
-
+
// ======================================================================
private void saveLatest() throws CommandException {
diff --git a/src/main/java/com/minecrafttas/tasmod/events/EventClient.java b/src/main/java/com/minecrafttas/tasmod/events/EventClient.java
index 8cc771e4..fdd53517 100644
--- a/src/main/java/com/minecrafttas/tasmod/events/EventClient.java
+++ b/src/main/java/com/minecrafttas/tasmod/events/EventClient.java
@@ -22,6 +22,17 @@ public static interface EventDrawHotbar extends EventBase {
public void onDrawHotbar();
}
+ /**
+ * Fired when drawing something on screen. Ignores F1
+ */
+ @FunctionalInterface
+ public static interface EventDrawHotbarAlways extends EventBase {
+ /**
+ * Fired when the gui is drawn on screen. Ignores F1
+ */
+ public void onDrawHotbarAlways();
+ }
+
/**
* Fired at the end of a client tick
*/
diff --git a/src/main/java/com/minecrafttas/tasmod/events/EventNBT.java b/src/main/java/com/minecrafttas/tasmod/events/EventNBT.java
new file mode 100644
index 00000000..b2c7ad01
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/events/EventNBT.java
@@ -0,0 +1,30 @@
+package com.minecrafttas.tasmod.events;
+
+import com.minecrafttas.mctcommon.events.EventListenerRegistry.EventBase;
+
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.storage.WorldInfo;
+
+public interface EventNBT {
+
+ @FunctionalInterface
+ public interface EventPlayerRead extends EventBase {
+ public void onPlayerReadNBT(NBTTagCompound compound, EntityPlayerMP player);
+ }
+
+ @FunctionalInterface
+ public interface EventPlayerWrite extends EventBase {
+ public void onPlayerWriteNBT(NBTTagCompound compound, EntityPlayerMP player);
+ }
+
+ @FunctionalInterface
+ public interface EventWorldRead extends EventBase {
+ public void onWorldReadNBT(NBTTagCompound worldCompound);
+ }
+
+ @FunctionalInterface
+ public interface EventWorldWrite extends EventBase {
+ public NBTTagCompound onWorldWriteNBT(NBTTagCompound compound, WorldInfo worldInfo);
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/events/EventSavestate.java b/src/main/java/com/minecrafttas/tasmod/events/EventSavestate.java
index 58791881..70fde1f8 100644
--- a/src/main/java/com/minecrafttas/tasmod/events/EventSavestate.java
+++ b/src/main/java/com/minecrafttas/tasmod/events/EventSavestate.java
@@ -1,9 +1,12 @@
package com.minecrafttas.tasmod.events;
-import java.io.File;
+import java.nio.file.Path;
import com.minecrafttas.mctcommon.events.EventListenerRegistry.EventBase;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.server.MinecraftServer;
+
public interface EventSavestate {
/**
@@ -19,7 +22,7 @@ interface EventServerSavestate extends EventBase {
* @param target Target folder, where the savestate is copied to
* @param current The current folder that will be copied from
*/
- public void onServerSavestate(int index, File target, File current);
+ public void onServerSavestate(MinecraftServer server, int index, Path target, Path current);
}
/**
@@ -35,7 +38,7 @@ interface EventServerLoadstate extends EventBase {
* @param target Target folder, where the savestate is copied to
* @param current The current folder that will be copied from
*/
- public void onServerLoadstate(int index, File target, File current);
+ public void onServerLoadstate(MinecraftServer server, int index, Path target, Path current);
}
/**
@@ -49,10 +52,46 @@ interface EventServerCompleteLoadstate extends EventBase {
*/
public void onServerLoadstateComplete();
}
-
+
+ /**
+ * Fired when saving a savestate
+ */
@FunctionalInterface
interface EventClientSavestate extends EventBase {
-
+
public void onClientSavestate();
}
+
+ /**
+ * Fired when loading a savestate
+ */
+ @FunctionalInterface
+ interface EventClientLoadstate extends EventBase {
+
+ public void onClientLoadstate();
+ }
+
+ /**
+ * Fired one tick after a loadstate was carried out
+ */
+ @FunctionalInterface
+ interface EventClientCompleteLoadstate extends EventBase {
+
+ /**
+ * Fired one tick after a loadstate was carried out
+ */
+ public void onClientLoadstateComplete();
+ }
+
+ /**
+ * Fired during loadstating, after the player is loaded on the client
+ */
+ @FunctionalInterface
+ interface EventClientLoadPlayer extends EventBase {
+
+ /**
+ * Fired during loadstating, after the player is loaded on the client
+ */
+ public void onClientLoadPlayer(EntityPlayerSP player);
+ }
}
diff --git a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java
index 20cb8f5c..e3a4f780 100644
--- a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java
+++ b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java
@@ -11,6 +11,7 @@
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.input.Keyboard;
+import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import com.minecrafttas.mctcommon.events.EventClient.EventClientTick;
@@ -30,8 +31,8 @@
* any everything can be customized
* @author Pancake
*/
-public class InfoHud extends GuiScreen implements EventClientTick, EventDrawHotbar{
-
+public class InfoHud extends GuiScreen implements EventClientTick, EventDrawHotbar {
+
public static class InfoLabel {
public String displayName;
public int x;
@@ -40,8 +41,7 @@ public static class InfoLabel {
public boolean renderRect;
public String renderText;
private Callable text;
-
-
+
public InfoLabel(String displayName, int x, int y, boolean visible, boolean renderRect, Callable text) {
this.displayName = displayName;
this.visible = visible;
@@ -50,7 +50,7 @@ public InfoLabel(String displayName, int x, int y, boolean visible, boolean rend
this.renderRect = renderRect;
this.text = text;
}
-
+
public void tick() {
try {
renderText = text.call();
@@ -60,45 +60,45 @@ public void tick() {
}
}
}
-
+
/** -1, or the current index in {@link InfoHud#lists} that is being dragged by the mouse */
private int currentlyDraggedIndex = -1;
private int xOffset; // drag offsets
private int yOffset;
-
- private int gridSizeX=14;
- private int gridSizeY=14;
-
+
+ private int gridSizeX = 14;
+ private int gridSizeY = 14;
+
public Properties configuration;
private boolean resetLayout;
public static List lists = new ArrayList<>();
-
+
private void setDefaults(String string, int y) {
setDefaults(string, y, false);
}
-
+
private void setDefaults(String string, int y, boolean enabled) {
configuration.setProperty(string + "_x", "0");
configuration.setProperty(string + "_y", y + "");
- configuration.setProperty(string + "_visible", enabled?"true":"false");
+ configuration.setProperty(string + "_visible", enabled ? "true" : "false");
configuration.setProperty(string + "_rect", "false");
saveConfig();
}
-
+
/**
* Returns the object below the mouse
*/
public void identify(int mouseX, int mouseY) {
int index = 0;
for (InfoLabel label : lists) {
- int x=0;
- int y=0;
+ int x = 0;
+ int y = 0;
try {
x = Integer.parseInt(configuration.getProperty(label.displayName + "_x"));
y = Integer.parseInt(configuration.getProperty(label.displayName + "_y"));
-
+
Pair newPos = getScreenOffset(x, y, label);
-
+
x = newPos.getLeft();
y = newPos.getRight();
} catch (NumberFormatException e) {
@@ -108,7 +108,7 @@ public void identify(int mouseX, int mouseY) {
}
int w = x + Minecraft.getMinecraft().fontRenderer.getStringWidth(label.renderText);
int h = y + 15;
-
+
if (mouseX >= x && mouseX <= w && mouseY >= y && mouseY <= h) {
currentlyDraggedIndex = index;
xOffset = mouseX - x;
@@ -121,8 +121,9 @@ public void identify(int mouseX, int mouseY) {
xOffset = -1;
yOffset = -1;
}
-
- @Override protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
+
+ @Override
+ protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
if (mouseButton == 2) {
identify(mouseX, mouseY);
if (currentlyDraggedIndex != -1) {
@@ -147,74 +148,77 @@ public void identify(int mouseX, int mouseY) {
identify(mouseX, mouseY);
super.mouseClicked(mouseX, mouseY, mouseButton);
}
-
+
@Override
protected void mouseReleased(int p_mouseReleased_1_, int p_mouseReleased_2_, int p_mouseReleased_3_) {
currentlyDraggedIndex = -1;
saveConfig();
super.mouseReleased(p_mouseReleased_1_, p_mouseReleased_2_, p_mouseReleased_3_);
}
-
+
@Override
protected void mouseClickMove(int mouseX, int mouseY, int k, long millis) {
if (currentlyDraggedIndex != -1) {
String dragging = lists.get(currentlyDraggedIndex).displayName;
-
- int mousePosX=mouseX - xOffset;
- int mousePosY=mouseY - yOffset;
-
- if(TASmodClient.virtual.isKeyDown(42)) {
- mousePosX=snapToGridX(mousePosX);
- mousePosY=snapToGridY(mousePosY);
+
+ int mousePosX = mouseX - xOffset;
+ int mousePosY = mouseY - yOffset;
+
+ if (TASmodClient.virtual.isKeyDown(42)) {
+ mousePosX = snapToGridX(mousePosX);
+ mousePosY = snapToGridY(mousePosY);
}
-
+
lists.get(currentlyDraggedIndex).x = mousePosX;
lists.get(currentlyDraggedIndex).y = mousePosY;
-
+
configuration.setProperty(dragging + "_x", lists.get(currentlyDraggedIndex).x + "");
configuration.setProperty(dragging + "_y", lists.get(currentlyDraggedIndex).y + "");
}
super.mouseClickMove(mouseX, mouseY, k, millis);
}
-
+
private int snapToGridX(int x) {
return Math.round(x / gridSizeX) * gridSizeX;
}
-
+
private int snapToGridY(int y) {
return Math.round(y / gridSizeY) * gridSizeY;
}
-
+
/**
* Saves the Configuration
*/
private void saveConfig() {
- if(!(Minecraft.getMinecraft().currentScreen instanceof InfoHud) || configuration == null) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof InfoHud) || configuration == null) {
return;
}
try {
File tasmodDir = new File(Minecraft.getMinecraft().mcDataDir, "tasmod");
tasmodDir.mkdir();
File configFile = new File(tasmodDir, "infogui2.cfg");
- if (!configFile.exists()) configFile.createNewFile();
+ if (!configFile.exists())
+ configFile.createNewFile();
configuration.store(new FileOutputStream(configFile, false), "DO NOT EDIT MANUALLY");
} catch (IOException e) {
e.printStackTrace();
}
}
-
+
/**
* Updates every tick
*/
@Override
public void onClientTick(Minecraft mc) {
- if(mc.player!=null) {
- if (checkInit()) return;
+ if (mc.player != null) {
+ if (checkInit())
+ return;
}
}
-
+
public boolean checkInit() {
- if (configuration != null) return false;
+ if (configuration != null)
+ return false;
/* Check whether already rendered before */
try {
configuration = new Properties();
@@ -222,200 +226,253 @@ public boolean checkInit() {
File tasmodDir = new File(Minecraft.getMinecraft().mcDataDir, "tasmod");
tasmodDir.mkdir();
File configFile = new File(tasmodDir, "infogui2.cfg");
- if (!configFile.exists()) configFile.createNewFile();
+ if (!configFile.exists())
+ configFile.createNewFile();
configuration.load(new FileReader(configFile));
- }else {
+ } else {
resetLayout = false;
}
lists = new ArrayList();
/* ====================== */
String title = "tickrate";
int y = 0;
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "Tickrate";
- return String.format("Tickrate: %s", TASmodClient.tickratechanger.ticksPerSecond);
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "Tickrate";
+ return String.format("Tickrate: %s", TASmodClient.tickratechanger.ticksPerSecond);
+ }));
+
title = "position";
y += 14;
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "XYZ";
- return String.format("%.2f %.2f %.2f", Minecraft.getMinecraft().player.posX, Minecraft.getMinecraft().player.posY, Minecraft.getMinecraft().player.posZ);
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "XYZ";
+ return String.format("%.2f %.2f %.2f", Minecraft.getMinecraft().player.posX, Minecraft.getMinecraft().player.posY, Minecraft.getMinecraft().player.posZ);
+ }));
+
title = "position2";
y += 14;
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "Precise XYZ";
- return String.format("%f %f %f", Minecraft.getMinecraft().player.posX, Minecraft.getMinecraft().player.posY, Minecraft.getMinecraft().player.posZ);
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "Precise XYZ";
+ return String.format("%s %s %s", Minecraft.getMinecraft().player.posX, Minecraft.getMinecraft().player.posY, Minecraft.getMinecraft().player.posZ);
+ }));
+
title = "chunkpos";
y += 14;
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "Chunk Position";
- return String.format("%d %d", Minecraft.getMinecraft().player.chunkCoordX, Minecraft.getMinecraft().player.chunkCoordZ);
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "Chunk Position";
+ return String.format("%d %d", Minecraft.getMinecraft().player.chunkCoordX, Minecraft.getMinecraft().player.chunkCoordZ);
+ }));
+
title = "worldseed";
y += 14;
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "Worldseed";
- return "World Seed: " + Minecraft.getMinecraft().world.getWorldInfo().getSeed();
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "Worldseed";
+ return "World Seed: " + Minecraft.getMinecraft().world.getWorldInfo().getSeed();
+ }));
+
y += 14;
-
- if(TASmod.ktrngHandler.isLoaded()) {
- title = "ktrng_randomseed";
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "KTRNG";
- return "RandomSeed: " + TASmod.ktrngHandler.getGlobalSeedClient();
- }));
- }
-
+
+// if (TASmod.ktrngHandler.isLoaded()) {
+// title = "ktrng_randomseed";
+// if (configuration.getProperty(title + "_x", "err").equals("err"))
+// setDefaults(title, y);
+// lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+// + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+// if (Minecraft.getMinecraft().currentScreen == this)
+// return "KTRNG";
+// return "RandomSeed: " + TASmod.ktrngHandler.getGlobalSeedClient();
+// }));
+// }
+
title = "facing";
y += 14;
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "Facing";
- return String.format("%.2f %.2f", Minecraft.getMinecraft().player.rotationPitch, Minecraft.getMinecraft().player.rotationYaw);
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "Facing";
+ return String.format("%.2f %.2f", Minecraft.getMinecraft().player.rotationYaw, Minecraft.getMinecraft().player.rotationPitch);
+ }));
+
+ title = "camera";
+ y += 14;
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "Camera";
+ return String.format("%.2f %.2f", TASmodClient.virtual.CAMERA_ANGLE.getCurrentYaw(), TASmodClient.virtual.CAMERA_ANGLE.getCurrentPitch());
+ }));
+
title = "cticks";
y += 14;
-// if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
-// lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
-// if (Minecraft.getMinecraft().currentScreen == this) return "Client Ticks";
-// return "Client Ticks: " + ClientProxy.ticksyncClient.getClienttickcounter();
-// }));
-
+ // if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
+ // lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ // if (Minecraft.getMinecraft().currentScreen == this) return "Client Ticks";
+ // return "Client Ticks: " + ClientProxy.ticksyncClient.getClienttickcounter();
+ // }));
+
title = "sticks";
y += 14;
-// if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
-// lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
-// if (Minecraft.getMinecraft().currentScreen == this) return "Server Ticks";
-// return "Server Ticks: " + ClientProxy.ticksyncClient.getServertickcounter();
-// }));
-
+ // if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
+ // lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ // if (Minecraft.getMinecraft().currentScreen == this) return "Server Ticks";
+ // return "Server Ticks: " + ClientProxy.ticksyncClient.getServertickcounter();
+ // }));
+
title = "nextxyz";
y += 14;
-// if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
-// lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
-// if (Minecraft.getMinecraft().currentScreen == this) return "Predicted Position";
-// return String.format("%f %f %f", PlayerPositionCalculator.xNew, PlayerPositionCalculator.yNew, PlayerPositionCalculator.zNew);
-// }));
-
+ // if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
+ // lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ // if (Minecraft.getMinecraft().currentScreen == this) return "Predicted Position";
+ // return String.format("%f %f %f", PlayerPositionCalculator.xNew, PlayerPositionCalculator.yNew, PlayerPositionCalculator.zNew);
+ // }));
+
title = "state";
y += 14;
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) {
- return "State";
- } else {
- TASstate state = TASmodClient.controller.getState();
- ChatFormatting format = ChatFormatting.WHITE;
- String out = "";
- if (state == TASstate.PLAYBACK) {
- out = "Playback";
- format = ChatFormatting.GREEN;
- } else if (state == TASstate.RECORDING) {
- out = "Recording";
- format = ChatFormatting.RED;
- } else if (state == TASstate.PAUSED) {
- out = "Paused";
- format = ChatFormatting.YELLOW;
- } else if (state == TASstate.NONE) {
- out = "";
- }
- return String.format("%s%s", format, out);
- }
- }));
-
-// title = "cursor";
-// y += 14;
-// if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
-// lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
-// if (Minecraft.getMinecraft().currentScreen == this) return "Mouse Position";
-// return String.format("Mouse Cursor: " + TASmodClient.virtual.getNextMouse().getPath().get(0).cursorX + " " + TASmodClient.virtual.getNextMouse().getPath().get(0).cursorY);
-// })); TODO Remove?
-
-// title = "trajectories";
-// y += 14;
-// if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
-// lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
-// if (Minecraft.getMinecraft().currentScreen == this) return "Trajectories";
-// String message = "Invalid Item";
-// Vec3d vec = TrajectoriesCalculator.calculate();
-// if (vec != null) {
-// message = String.format("%.3f %.3f %.3f", vec.x, vec.y, vec.z);
-// }
-// return String.format("Trajectories: " + message);
-// }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this) {
+ return "State";
+ } else {
+ TASstate state = TASmodClient.controller.getState();
+ ChatFormatting format = ChatFormatting.WHITE;
+ String out = "";
+ if (state == TASstate.PLAYBACK) {
+ out = "Playback";
+ format = ChatFormatting.GREEN;
+ } else if (state == TASstate.RECORDING) {
+ out = "Recording";
+ format = ChatFormatting.RED;
+ } else if (state == TASstate.PAUSED) {
+ out = "Paused";
+ format = ChatFormatting.YELLOW;
+ } else if (state == TASstate.NONE) {
+ out = "";
+ }
+ return String.format("%s%s", format, out);
+ }
+ }));
+
+ // title = "cursor";
+ // y += 14;
+ // if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
+ // lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ // if (Minecraft.getMinecraft().currentScreen == this) return "Mouse Position";
+ // return String.format("Mouse Cursor: " + TASmodClient.virtual.getNextMouse().getPath().get(0).cursorX + " " + TASmodClient.virtual.getNextMouse().getPath().get(0).cursorY);
+ // })); TODO Remove?
+
+ // title = "trajectories";
+ // y += 14;
+ // if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
+ // lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ // if (Minecraft.getMinecraft().currentScreen == this) return "Trajectories";
+ // String message = "Invalid Item";
+ // Vec3d vec = TrajectoriesCalculator.calculate();
+ // if (vec != null) {
+ // message = String.format("%.3f %.3f %.3f", vec.x, vec.y, vec.z);
+ // }
+ // return String.format("Trajectories: " + message);
+ // }));
+
title = "velocity";
y += 14;
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "Velocity";
- return "Velocity: " + Minecraft.getMinecraft().player.motionX + " " + Minecraft.getMinecraft().player.motionY + " " + Minecraft.getMinecraft().player.motionZ;
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "Velocity";
+ return Minecraft.getMinecraft().player.motionX + " " + Minecraft.getMinecraft().player.motionY + " " + Minecraft.getMinecraft().player.motionZ;
+ }));
+
title = "desyncstatus";
y += 14;
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "Desync";
- DesyncMonitorFileCommandExtension dMonitor=TASmodClient.desyncMonitorFileCommandExtension;
- return dMonitor.getStatus(Minecraft.getMinecraft().player);
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "Desync";
+ DesyncMonitorFileCommandExtension dMonitor = TASmodClient.desyncMonitorFileCommandExtension;
+ return dMonitor.getStatus(Minecraft.getMinecraft().player);
+ }));
+
title = "desyncstatusMotion";
y += 14;
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "Desync Motion";
- DesyncMonitorFileCommandExtension dMonitor=TASmodClient.desyncMonitorFileCommandExtension;
- return dMonitor.getMotion();
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "Desync Motion";
+ DesyncMonitorFileCommandExtension dMonitor = TASmodClient.desyncMonitorFileCommandExtension;
+ return dMonitor.getMotion();
+ }));
+
title = "desyncstatusPos";
y += 14;
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "Desync Position";
- DesyncMonitorFileCommandExtension dMonitor=TASmodClient.desyncMonitorFileCommandExtension;
- return dMonitor.getPos();
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "Desync Position";
+ DesyncMonitorFileCommandExtension dMonitor = TASmodClient.desyncMonitorFileCommandExtension;
+ return dMonitor.getPos();
+ }));
+
y = height - 28;
title = "playback_index";
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y, true);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "PlaybackIndex";
- return Long.toString(TASmodClient.controller.index());
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y, true);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "PlaybackIndex";
+ return Long.toString(TASmodClient.controller.index());
+ }));
+
y = height - 14;
title = "keystrokes";
- if (configuration.getProperty(title + "_x", "err").equals("err")) setDefaults(title, y, true);
- lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
- if (Minecraft.getMinecraft().currentScreen == this) return "Keystrokes";
- return keystrokes();
- }));
-
+ if (configuration.getProperty(title + "_x", "err").equals("err"))
+ setDefaults(title, y, true);
+ lists.add(new InfoLabel(title, Integer.parseInt(configuration.getProperty(title + "_x")), Integer.parseInt(configuration.getProperty(title + "_y")), Boolean.parseBoolean(configuration.getProperty(title
+ + "_visible")), Boolean.parseBoolean(configuration.getProperty(title + "_rect")), () -> {
+ if (Minecraft.getMinecraft().currentScreen == this)
+ return "Keystrokes";
+ return keystrokes();
+ }));
+
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
-
+
/**
* Render the Info Hud only
*/
@@ -428,33 +485,33 @@ public void onDrawHotbar() {
// skip rendering of control byte is set
if (!TASmodClient.optionsFileCommandExtension.shouldRenderHud() && TASmodClient.controller.isPlayingback())
return;
- int xpos=40;
- int ypos=190;
+ int xpos = 40;
+ int ypos = 190;
for (InfoLabel label : lists) {
label.tick();
-
+
int lx = label.x;
int ly = label.y;
Pair newPos = getScreenOffset(lx, ly, label);
-
+
lx = newPos.getLeft();
ly = newPos.getRight();
-
+
if (label.visible) {
drawRectWithText(label.renderText, lx, ly, label.renderRect);
} else if (Minecraft.getMinecraft().currentScreen != null) {
if (Minecraft.getMinecraft().currentScreen.getClass().getSimpleName().contains("InfoHud")) {
- Minecraft.getMinecraft().fontRenderer.drawStringWithShadow(label.renderText, label.x + 2, label.y + 3, 0x60FFFFFF);
+ Minecraft.getMinecraft().fontRenderer.drawStringWithShadow(label.renderText, label.x + 2, label.y + 3, 0x60FFFFFF);
}
}
- if(Minecraft.getMinecraft().currentScreen instanceof InfoHud) {
- Minecraft.getMinecraft().fontRenderer.drawStringWithShadow("Leftclick to move", width-ypos, xpos- 30, 0x60FF00);
- Minecraft.getMinecraft().fontRenderer.drawStringWithShadow("Rightclick to enable", width-ypos, xpos-20, 0x60FF00);
- Minecraft.getMinecraft().fontRenderer.drawStringWithShadow("Middleclick to add black background", width-ypos, xpos-10, 0x60FF00);
- Minecraft.getMinecraft().fontRenderer.drawStringWithShadow("Hold Shift to snap to grid", width-ypos, xpos, 0x60FF00);
+ if (Minecraft.getMinecraft().currentScreen instanceof InfoHud) {
+ Minecraft.getMinecraft().fontRenderer.drawStringWithShadow("Leftclick to move", width - ypos, xpos - 30, 0x60FF00);
+ Minecraft.getMinecraft().fontRenderer.drawStringWithShadow("Rightclick to enable", width - ypos, xpos - 20, 0x60FF00);
+ Minecraft.getMinecraft().fontRenderer.drawStringWithShadow("Middleclick to add black background", width - ypos, xpos - 10, 0x60FF00);
+ Minecraft.getMinecraft().fontRenderer.drawStringWithShadow("Hold Shift to snap to grid", width - ypos, xpos, 0x60FF00);
Minecraft.getMinecraft().fontRenderer.drawStringWithShadow("CTRL+Shift+R to reset the layout", width - ypos, xpos + 10, 0xEE8100);
-
+
if (isCtrlKeyDown() && isShiftKeyDown() && TASmodClient.virtual.isKeyDown(Keyboard.KEY_R)) {
resetLayout = true;
configuration = null;
@@ -462,49 +519,53 @@ public void onDrawHotbar() {
}
}
ScaledResolution scaled = new ScaledResolution(Minecraft.getMinecraft());
- drawCenteredString(Minecraft.getMinecraft().fontRenderer, "TASmod is still in development! Major issues may arise!", scaled.getScaledWidth() / 2, scaled.getScaledHeight() - 50, 0xFF8400);
-// drawCenteredString(Minecraft.getMinecraft().fontRenderer, Float.toString(TASmod.tickratechanger.ticksPerSecond), scaled.getScaledWidth() / 2, scaled.getScaledHeight() - 36, 0xFFFFFF);
+ // drawCenteredString(Minecraft.getMinecraft().fontRenderer, "TASmod is still in development! Major issues may arise!", scaled.getScaledWidth() / 2, scaled.getScaledHeight() - 50, 0xFF8400);
+ drawString(Minecraft.getMinecraft().fontRenderer, TASmod.version, scaled.getScaledWidth() - Minecraft.getMinecraft().fontRenderer.getStringWidth(TASmod.version) - 2, scaled.getScaledHeight() - 10, 0xFFFFFF);
+ // drawCenteredString(Minecraft.getMinecraft().fontRenderer, Float.toString(TASmod.tickratechanger.ticksPerSecond), scaled.getScaledWidth() / 2, scaled.getScaledHeight() - 36, 0xFFFFFF);
}
-
+
/**
* Renders a Box with Text in it
*/
private void drawRectWithText(String text, int x, int y, boolean rect) {
- if (rect) drawRect(x, y, x + Minecraft.getMinecraft().fontRenderer.getStringWidth(text) + 4, y + 14, 0x60000000);
+ if (rect)
+ drawRect(x, y, x + Minecraft.getMinecraft().fontRenderer.getStringWidth(text) + 4, y + 14, 0x60000000);
Minecraft.getMinecraft().fontRenderer.drawStringWithShadow(text, x + 2, y + 3, 0xFFFFFF);
GL11.glEnable(3042 /*GL_BLEND*/);
}
-
+
private String keystrokes() {
-// if (Display.isActive()) { //TODO Update
-// String out1 = ""+ChatFormatting.WHITE;
-// for (String mouse : TASmodClient.virtual.getCurrentMousePresses()) {
-// out1 = out1.concat(mouse + " ");
-// }
-// out1=out1.concat(""+ChatFormatting.GREEN);
-// for (String mouse : TASmodClient.virtual.getNextMousePresses()) {
-// out1 = out1.concat(mouse + " ");
-// }
-//
-// String out2 = ""+ChatFormatting.WHITE;
-// for (String key : TASmodClient.virtual.getCurrentKeyboardPresses()) {
-// out2 = out2.concat(key + " ");
-// }
-// out2=out2.concat(""+ChatFormatting.GREEN);
-// for (String key : TASmodClient.virtual.getNextKeyboardPresses()) {
-// out2 = out2.concat(key + " ");
-// }
-// return out1+out2;
-// }
- return "";
+
+ String out1 = "" + ChatFormatting.WHITE;
+ for (String mouse : TASmodClient.virtual.getCurrentMousePresses()) {
+ out1 = out1.concat(mouse + " ");
+ }
+ if (Display.isActive() || TASmodClient.controller.isPlayingback()) {
+ out1 = out1.concat("" + ChatFormatting.GREEN);
+ for (String mouse : TASmodClient.virtual.getNextMousePresses()) {
+ out1 = out1.concat(mouse + " ");
+ }
+ }
+
+ String out2 = "" + ChatFormatting.WHITE;
+ for (String key : TASmodClient.virtual.getCurrentKeyboardPresses()) {
+ out2 = out2.concat(key + " ");
+ }
+ if (Display.isActive() || TASmodClient.controller.isPlayingback()) {
+ out2 = out2.concat("" + ChatFormatting.GREEN);
+ for (String key : TASmodClient.virtual.getNextKeyboardPresses()) {
+ out2 = out2.concat(key + " ");
+ }
+ }
+ return out1 + out2;
}
-
- private Pair getScreenOffset(int x, int y, InfoLabel label){
+
+ private Pair getScreenOffset(int x, int y, InfoLabel label) {
ScaledResolution scaled = new ScaledResolution(Minecraft.getMinecraft());
-
+
int marginX = 5;
int marginY = 5;
-
+
if (getBBRight(x, label.renderText) > scaled.getScaledWidth()) {
int offset = getBBRight(x, label.renderText);
x = x - (offset - scaled.getScaledWidth()) - marginX;
@@ -514,7 +575,7 @@ private Pair getScreenOffset(int x, int y, InfoLabel label){
int offset = getBBDown(y);
y = y - (offset - scaled.getScaledHeight()) - marginY;
}
-
+
return Pair.of(x, y);
}
@@ -525,5 +586,5 @@ private int getBBRight(int x, String text) {
private int getBBDown(int y) {
return y + 14;
}
-
+
}
\ No newline at end of file
diff --git a/src/main/java/com/minecrafttas/tasmod/ktrng/KillTheRNGHandler.java b/src/main/java/com/minecrafttas/tasmod/ktrng/KillTheRNGHandler.java
index b2669838..8b4c53b7 100644
--- a/src/main/java/com/minecrafttas/tasmod/ktrng/KillTheRNGHandler.java
+++ b/src/main/java/com/minecrafttas/tasmod/ktrng/KillTheRNGHandler.java
@@ -163,7 +163,7 @@ public void setInitialSeed(long initialSeed) {
e.printStackTrace();
}
} else {
- TASmod.ktrngHandler.setGlobalSeedClient(initialSeed);
+ // TASmod.ktrngHandler.setGlobalSeedClient(initialSeed);
}
}
@@ -190,7 +190,7 @@ public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws
case KILLTHERNG_STARTSEED:
TASmod.tickSchedulerServer.add(() -> {
- TASmod.ktrngHandler.setGlobalSeedServer(seed);
+ // TASmod.ktrngHandler.setGlobalSeedServer(seed);
});
break;
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/MixinInGameHud.java b/src/main/java/com/minecrafttas/tasmod/mixin/MixinInGameHud.java
deleted file mode 100644
index 50acb8f2..00000000
--- a/src/main/java/com/minecrafttas/tasmod/mixin/MixinInGameHud.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.minecrafttas.tasmod.mixin;
-
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.Gui;
-import net.minecraft.client.gui.GuiIngame;
-import net.minecraft.client.gui.ScaledResolution;
-import net.minecraft.client.renderer.GlStateManager;
-import net.minecraft.util.ResourceLocation;
-
-@Mixin(GuiIngame.class)
-public abstract class MixinInGameHud {
-
- ResourceLocation potion = new ResourceLocation("tasmod:textures/potion.png");
-
- /**
- * Renders the potion into the gui
- * @param ci
- */
- @Inject(method="renderExpBar", at=@At(value="HEAD"), remap = false)
- public void mixinRenderExperienceBar(CallbackInfo ci) {
- ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft());
- Minecraft.getMinecraft().getTextureManager().bindTexture(potion);
- int m = (scaledresolution.getScaledWidth() / 2)-6;
- int n = scaledresolution.getScaledHeight() - 31 - 19;
- int skale=20;
- GlStateManager.enableBlend();
- GlStateManager.enableAlpha();
- GlStateManager.color(1, 1, 1, 0.3F);
- Gui.drawModalRectWithCustomSizedTexture(m-3, n, 0F, 0F, skale, skale, skale, skale);
- GlStateManager.disableBlend();
- GlStateManager.disableAlpha();
- }
-}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/MixinMinecraft.java b/src/main/java/com/minecrafttas/tasmod/mixin/MixinMinecraft.java
index a4e77c57..450efdc7 100644
--- a/src/main/java/com/minecrafttas/tasmod/mixin/MixinMinecraft.java
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/MixinMinecraft.java
@@ -1,8 +1,5 @@
package com.minecrafttas.tasmod.mixin;
-import java.io.IOException;
-
-import com.minecrafttas.mctcommon.events.EventListenerRegistry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -12,9 +9,9 @@
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import com.minecrafttas.mctcommon.events.EventListenerRegistry;
import com.minecrafttas.tasmod.TASmodClient;
import com.minecrafttas.tasmod.events.EventClient.EventClientTickPost;
-import com.minecrafttas.tasmod.savestates.SavestateHandlerServer;
import com.minecrafttas.tasmod.util.Ducks.SubtickDuck;
import net.minecraft.client.Minecraft;
@@ -25,12 +22,11 @@
@Mixin(Minecraft.class)
public abstract class MixinMinecraft {
-
// =====================================================================================================================================
@Shadow
private GuiScreen currentScreen;
-
+
@Inject(method = "runGameLoop", at = @At(value = "HEAD"))
public void injectRunGameLoop(CallbackInfo ci) {
TASmodClient.gameLoopSchedulerClient.runAllTasks();
@@ -58,7 +54,7 @@ public void redirectRunTick(Minecraft mc) {
TASmodClient.tickratechanger.advanceTick = false;
TASmodClient.tickratechanger.changeClientTickrate(0F);
}
- EventListenerRegistry.fireEvent(EventClientTickPost.class, (Minecraft)(Object)this);
+ EventListenerRegistry.fireEvent(EventClientTickPost.class, (Minecraft) (Object) this);
}
@Shadow
@@ -75,17 +71,6 @@ public void inject_shutdownMinecraftApplet(CallbackInfo ci) {
e.printStackTrace();
}
}
-
- @Inject(method = "runTick", at = @At(value = "HEAD"))
- public void injectRunTick(CallbackInfo ci) throws IOException {
- if (SavestateHandlerServer.wasLoading) {
- SavestateHandlerServer.wasLoading = false;
-
- if(Minecraft.getMinecraft().player!=null) { //The player can be null when loading a savestate and quitting to the main menu
- SavestateHandlerServer.playerLoadSavestateEventClient(); // TODO Replace with event
- }
- }
- }
@ModifyConstant(method = "runTickMouse", constant = @Constant(longValue = 200L))
public long fixMouseWheel(long twohundredLong) {
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/MixinMinecraftServer.java b/src/main/java/com/minecrafttas/tasmod/mixin/MixinMinecraftServer.java
index 7146a961..3ff76f6e 100644
--- a/src/main/java/com/minecrafttas/tasmod/mixin/MixinMinecraftServer.java
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/MixinMinecraftServer.java
@@ -3,7 +3,6 @@
import java.util.Queue;
import java.util.concurrent.FutureTask;
-import com.minecrafttas.mctcommon.events.EventListenerRegistry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -11,8 +10,10 @@
import org.spongepowered.asm.mixin.injection.ModifyConstant;
import org.spongepowered.asm.mixin.injection.Redirect;
+import com.minecrafttas.mctcommon.events.EventListenerRegistry;
import com.minecrafttas.tasmod.TASmod;
import com.minecrafttas.tasmod.events.EventServer.EventServerTickPost;
+import com.minecrafttas.tasmod.savestates.SavestateHandlerServer.SavestateState;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@@ -33,7 +34,7 @@ public long modifyMSPT(long fiftyLong) {
@Redirect(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;tick()V"))
public void redirectTick(MinecraftServer server) {
-
+
}
@Shadow
@@ -61,35 +62,35 @@ public long redirectMathMax(long oneLong, long i) {
@Shadow
private boolean serverIsRunning;
-
+
@Redirect(method = "run", at = @At(value = "INVOKE", target = "Ljava/lang/Thread;sleep(J)V"))
public void redirectThreadSleep(long msToTick) {
-
+
/* The server should tick if:
* (shouldTick in ticksync is true OR there are no players connected to the custom server) AND the tickrate is not zero. That or advance tick is true*/
- if( (TASmod.ticksyncServer.shouldTick() && TASmod.tickratechanger.ticksPerSecond != 0) || TASmod.tickratechanger.advanceTick) {
+ if ((TASmod.ticksyncServer.shouldTick() && TASmod.tickratechanger.ticksPerSecond != 0) || TASmod.tickratechanger.advanceTick) {
long timeBeforeTick = System.currentTimeMillis();
-
+
this.tick();
TASmod.tickSchedulerServer.runAllTasks();
-
+
if (TASmod.tickratechanger.advanceTick) {
TASmod.tickratechanger.changeServerTickrate(0F);
TASmod.tickratechanger.advanceTick = false;
}
- EventListenerRegistry.fireEvent(EventServerTickPost.class, (MinecraftServer)(Object)this);
-
+ EventListenerRegistry.fireEvent(EventServerTickPost.class, (MinecraftServer) (Object) this);
+
long tickDuration = System.currentTimeMillis() - timeBeforeTick;
-
+
// ==================================================
-
+
try {
Thread.sleep(Math.max(1L, TASmod.tickratechanger.millisecondsPerTick - tickDuration));
} catch (InterruptedException e) {
e.printStackTrace();
}
} else { // This is when the server should not tick... This is to ensure network tick stuff is working
- if(TASmod.tickratechanger.ticksPerSecond == 0) {
+ if (TASmod.tickratechanger.ticksPerSecond == 0) {
faketick++;
if (faketick >= 50) {
faketick = 0;
@@ -99,20 +100,25 @@ public void redirectThreadSleep(long msToTick) {
}
}
}
-
+
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
-
- synchronized (this.futureTaskQueue) {
- while (!this.futureTaskQueue.isEmpty()) {
- try {
- ((FutureTask>) this.futureTaskQueue.poll()).run();
- } catch (Throwable var9) {
- var9.printStackTrace();
+
+ TASmod.gameLoopSchedulerServer.runAllTasks();
+
+ boolean stopTaskQueue = TASmod.savestateHandlerServer != null && TASmod.savestateHandlerServer.state == SavestateState.LOADING;
+ if (!stopTaskQueue) {
+ synchronized (this.futureTaskQueue) {
+ while (!this.futureTaskQueue.isEmpty()) {
+ try {
+ ((FutureTask>) this.futureTaskQueue.poll()).run();
+ } catch (Throwable var9) {
+ var9.printStackTrace();
+ }
}
}
}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinEntityPlayerMP.java b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinEntityPlayerMP.java
new file mode 100644
index 00000000..ee6bd9af
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinEntityPlayerMP.java
@@ -0,0 +1,33 @@
+package com.minecrafttas.tasmod.mixin.events;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import com.minecrafttas.mctcommon.events.EventListenerRegistry;
+import com.minecrafttas.tasmod.events.EventNBT;
+import com.minecrafttas.tasmod.events.EventNBT.EventPlayerRead;
+import com.minecrafttas.tasmod.events.EventNBT.EventPlayerWrite;
+
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.nbt.NBTTagCompound;
+
+/**
+ * Implements {@link EventPlayerRead} and {@link EventPlayerWrite} events
+ *
+ * @author Scribble
+ */
+@Mixin(EntityPlayerMP.class)
+public class MixinEntityPlayerMP {
+
+ @Inject(method = "readEntityFromNBT", at = @At(value = "RETURN"))
+ public void readClientMotion(NBTTagCompound compound, CallbackInfo ci) {
+ EventListenerRegistry.fireEvent(EventNBT.EventPlayerRead.class, compound, (EntityPlayerMP) (Object) this);
+ }
+
+ @Inject(method = "writeEntityToNBT", at = @At(value = "RETURN"))
+ public void writeClientMotion(NBTTagCompound compound, CallbackInfo ci) {
+ EventListenerRegistry.fireEvent(EventNBT.EventPlayerWrite.class, compound, (EntityPlayerMP) (Object) this);
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinEntityRenderer.java b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinEntityRenderer.java
new file mode 100644
index 00000000..f61e3de6
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinEntityRenderer.java
@@ -0,0 +1,35 @@
+package com.minecrafttas.tasmod.mixin.events;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import com.minecrafttas.mctcommon.events.EventListenerRegistry;
+import com.minecrafttas.tasmod.events.EventClient.EventDrawHotbarAlways;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.EntityRenderer;
+import net.minecraft.client.renderer.GlStateManager;
+
+@Mixin(EntityRenderer.class)
+public class MixinEntityRenderer {
+
+ @Shadow
+ private Minecraft mc;
+
+ @Inject(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V"))
+ public void inject_onRenderGameOverlay(CallbackInfo ci) {
+ ScaledResolution scaledResolution = new ScaledResolution(this.mc);
+ GlStateManager.clear(256);
+ GlStateManager.matrixMode(5889);
+ GlStateManager.loadIdentity();
+ GlStateManager.ortho(0.0, scaledResolution.getScaledWidth_double(), scaledResolution.getScaledHeight_double(), 0.0, 1000.0, 3000.0);
+ GlStateManager.matrixMode(5888);
+ GlStateManager.loadIdentity();
+ GlStateManager.translate(0.0F, 0.0F, -2000.0F);
+ EventListenerRegistry.fireEvent(EventDrawHotbarAlways.class);
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinGuiIngame.java b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinGuiIngame.java
index ebeeb56f..dfea37f3 100644
--- a/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinGuiIngame.java
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinGuiIngame.java
@@ -1,18 +1,18 @@
package com.minecrafttas.tasmod.mixin.events;
-import com.minecrafttas.mctcommon.events.EventListenerRegistry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import com.minecrafttas.mctcommon.events.EventListenerRegistry;
import com.minecrafttas.tasmod.events.EventClient.EventDrawHotbar;
import net.minecraft.client.gui.GuiIngame;
@Mixin(GuiIngame.class)
public class MixinGuiIngame {
-
+
@Inject(method = "renderHotbar", at = @At("HEAD"))
public void inject_renderHotbar(CallbackInfo ci) {
EventListenerRegistry.fireEvent(EventDrawHotbar.class);
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinGuiMainMenu.java b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinGuiMainMenu.java
index ef5ea361..6a3e847b 100644
--- a/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinGuiMainMenu.java
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinGuiMainMenu.java
@@ -14,7 +14,7 @@
public class MixinGuiMainMenu extends GuiScreen {
@Redirect(method = "actionPerformed", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;displayGuiScreen(Lnet/minecraft/client/gui/GuiScreen;)V", ordinal = 3))
- public void redirectOpenGuiMultiplayer(Minecraft mc, GuiScreen screen) {
+ public void redirect_openGuiMultiplayer(Minecraft mc, GuiScreen screen) {
mc.displayGuiScreen(new GuiMultiplayerWarn((GuiMainMenu)(Object)this));
}
}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinSaveFormatOld.java b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinSaveFormatOld.java
new file mode 100644
index 00000000..f1ab8f2b
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinSaveFormatOld.java
@@ -0,0 +1,21 @@
+package com.minecrafttas.tasmod.mixin.events;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.ModifyArgs;
+
+import com.minecrafttas.mctcommon.events.EventListenerRegistry;
+import com.minecrafttas.tasmod.events.EventNBT;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.storage.SaveFormatOld;
+
+@Mixin(SaveFormatOld.class)
+public class MixinSaveFormatOld {
+
+ @ModifyArgs(method = "getWorldData", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/datafix/DataFixer;process(Lnet/minecraft/util/datafix/FixTypes;Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/nbt/NBTTagCompound;"))
+ public NBTTagCompound modifyargs_getWorldData(NBTTagCompound compound) {
+ EventListenerRegistry.fireEvent(EventNBT.EventWorldRead.class, compound);
+ return compound;
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinSaveHandler.java b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinSaveHandler.java
new file mode 100644
index 00000000..acd856db
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinSaveHandler.java
@@ -0,0 +1,30 @@
+package com.minecrafttas.tasmod.mixin.events;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.ModifyArg;
+
+import com.llamalad7.mixinextras.sugar.Share;
+import com.llamalad7.mixinextras.sugar.ref.LocalRef;
+import com.minecrafttas.mctcommon.events.EventListenerRegistry;
+import com.minecrafttas.tasmod.events.EventNBT;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.storage.SaveHandler;
+import net.minecraft.world.storage.WorldInfo;
+
+@Mixin(SaveHandler.class)
+public class MixinSaveHandler {
+
+ @Inject(method = "saveWorldInfoWithPlayer", at = @At(value = "HEAD"))
+ public void inject_onSaveWorldInfo(WorldInfo worldInfo, NBTTagCompound singlePlayerData, @Share(value = "worldInfo") LocalRef sharedWorldInfo) {
+ sharedWorldInfo.set(worldInfo);
+ }
+
+ @ModifyArg(method = "saveWorldInfoWithPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/NBTTagCompound;setTag(Ljava/lang/String;Lnet/minecraft/nbt/NBTTagCompound;)V"), index = 1)
+ public NBTTagCompound modifyarg_onSaveWorldInfo(NBTTagCompound singlePlayerCompound, @Share("worldInfo") LocalRef sharedWorldInfo) {
+ WorldInfo worldInfo = sharedWorldInfo.get();
+ return (NBTTagCompound) EventListenerRegistry.fireEvent(EventNBT.EventWorldWrite.class, singlePlayerCompound, worldInfo);
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java b/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java
index 761dbff6..4ad6feb8 100644
--- a/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java
@@ -81,13 +81,13 @@ public void playback_injectAtStartSection(float partialTicks, long nanoTime, Cal
}
mc.getTutorial().handleMouse(mc.mouseHelper);
- TASmodClient.virtual.CAMERA_ANGLE.updateNextCameraAngle((float) -((double)deltaPitch * 0.15D * invertMouse), (float) ((double)deltaYaw * 0.15D), TASmodClient.tickratechanger.ticksPerSecond != 0);
+ TASmodClient.virtual.CAMERA_ANGLE.updateNextCameraAngle((float) -((double) deltaPitch * 0.15D * invertMouse), (float) ((double) deltaYaw * 0.15D), TASmodClient.tickratechanger.ticksPerSecond != 0);
}
}
@Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/entity/EntityPlayerSP;turn(FF)V"))
- public void playback_stopVanilla(EntityPlayerSP player, float deltaYaw, float deltaPitch){
- if(TASmodClient.tickratechanger.ticksPerSecond == 0){
+ public void playback_turnPlayer(EntityPlayerSP player, float deltaYaw, float deltaPitch) {
+ if (TASmodClient.tickratechanger.ticksPerSecond == 0 && !TASmodClient.controller.isPlayingback()) {
player.turn(deltaYaw, deltaPitch);
}
}
@@ -100,35 +100,35 @@ public void playback_stopVanilla(EntityPlayerSP player, float deltaYaw, float de
*/
@Override
public void runUpdate(float partialTicks) {
- if(mc.player == null){
- return;
- }
- // Update the currentCameraAngle
- TASmodClient.virtual.CAMERA_ANGLE.nextCameraTick();
-
- // Store current rotation to be used as prevRotationPitch/Yaw
- float prevPitch = mc.player.rotationPitch;
- float prevYaw = mc.player.rotationYaw;
-
- // Get the new pitch from the virtual input
- Float newPitch = TASmodClient.virtual.CAMERA_ANGLE.getCurrentPitch();
- Float newYaw = TASmodClient.virtual.CAMERA_ANGLE.getCurrentYaw();
-
- // If the pitch or yaw is null (usually on initialize or when the player joins the world),
- // set nextCameraAngle to the current absolute camera coordinates.
- // This ensures that the camera position is loaded correctly
- if(newPitch == null || newYaw == null) {
- TASmodClient.virtual.CAMERA_ANGLE.setCamera(prevPitch, prevYaw);
- return;
- }
+ if (mc.player == null) {
+ return;
+ }
+ // Update the currentCameraAngle
+ TASmodClient.virtual.CAMERA_ANGLE.nextCameraTick();
+
+ // Store current rotation to be used as prevRotationPitch/Yaw
+ float prevPitch = mc.player.rotationPitch;
+ float prevYaw = mc.player.rotationYaw;
+
+ // Get the new pitch from the virtual input
+ Float newPitch = TASmodClient.virtual.CAMERA_ANGLE.getCurrentPitch();
+ Float newYaw = TASmodClient.virtual.CAMERA_ANGLE.getCurrentYaw();
+
+ // If the pitch or yaw is null (usually on initialize or when the player joins the world),
+ // set nextCameraAngle to the current absolute camera coordinates.
+ // This ensures that the camera position is loaded correctly
+ if (newPitch == null || newYaw == null) {
+ TASmodClient.virtual.CAMERA_ANGLE.setCamera(prevPitch, prevYaw);
+ return;
+ }
- // Update the rotation of the player
- mc.player.rotationPitch = newPitch;
- mc.player.rotationYaw = newYaw;
+ // Update the rotation of the player
+ mc.player.rotationPitch = newPitch;
+ mc.player.rotationYaw = newYaw;
- // Update the previous rotation of the player
- mc.player.prevRotationPitch = prevPitch;
- mc.player.prevRotationYaw = prevYaw;
+ // Update the previous rotation of the player
+ mc.player.prevRotationPitch = prevPitch;
+ mc.player.prevRotationYaw = prevYaw;
}
/**
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/AccessorEntityLivingBase.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/AccessorEntityLivingBase.java
new file mode 100644
index 00000000..271cf872
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/AccessorEntityLivingBase.java
@@ -0,0 +1,22 @@
+package com.minecrafttas.tasmod.mixin.savestates;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+import com.minecrafttas.tasmod.savestates.SavestateHandlerClient;
+
+import net.minecraft.entity.EntityLivingBase;
+
+@Mixin(EntityLivingBase.class)
+public interface AccessorEntityLivingBase {
+
+ /**
+ * Clears potion particles.
+ *
Used to clear potion particles on the client still persisting
+ * after loading a savestate across dimensions
+ *
+ * @see SavestateHandlerClient#loadPlayer(net.minecraft.nbt.NBTTagCompound)
+ */
+ @Invoker("resetPotionEffectMetadata")
+ public void clearPotionEffects();
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/AccessorPlayerChunkMap.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/AccessorPlayerChunkMap.java
new file mode 100644
index 00000000..bd85e03c
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/AccessorPlayerChunkMap.java
@@ -0,0 +1,22 @@
+package com.minecrafttas.tasmod.mixin.savestates;
+
+import java.util.List;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import com.minecrafttas.tasmod.savestates.handlers.SavestateWorldHandler;
+
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.server.management.PlayerChunkMap;
+
+@Mixin(PlayerChunkMap.class)
+public interface AccessorPlayerChunkMap {
+
+ /**
+ * @return The players from the specified chunk map
+ * @see SavestateWorldHandler#addPlayerToChunkMap()
+ */
+ @Accessor
+ public List getPlayers();
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinChunkProviderClient.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinChunkProviderClient.java
index d3ab135b..7859b968 100644
--- a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinChunkProviderClient.java
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinChunkProviderClient.java
@@ -11,21 +11,30 @@
import net.minecraft.client.multiplayer.ChunkProviderClient;
import net.minecraft.world.chunk.Chunk;
+/**
+ * Adds {@link #unloadAllChunks()} to the {@link ChunkProviderClient}
+ *
+ * @author Scribble
+ */
@Mixin(ChunkProviderClient.class)
-public class MixinChunkProviderClient implements ChunkProviderDuck{
- @Shadow @Final
+public class MixinChunkProviderClient implements ChunkProviderDuck {
+ @Shadow
+ @Final
private Long2ObjectMap chunkMapping;
+ /**
+ * Unloads chunk data on the client.
+ *
This step is necessary as not doing this, will create phantom blocks on the client, with strange behaviour.
+ */
@Override
public void unloadAllChunks() {
- ObjectIterator> objectiterator = this.chunkMapping.values().iterator();
+ ObjectIterator> objectiterator = this.chunkMapping.values().iterator();
- while (objectiterator.hasNext())
- {
- Chunk chunk = (Chunk)objectiterator.next();
- chunk.onUnload();
- }
- chunkMapping.clear();
- }
+ while (objectiterator.hasNext()) {
+ Chunk chunk = (Chunk) objectiterator.next();
+ chunk.onUnload();
+ }
+ chunkMapping.clear();
+ }
}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinChunkProviderServer.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinChunkProviderServer.java
index e686c472..b0e829dc 100644
--- a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinChunkProviderServer.java
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinChunkProviderServer.java
@@ -11,27 +11,43 @@
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.gen.ChunkProviderServer;
+/**
+ * Adds {@link #unloadAllChunks()} to the {@link ChunkProviderServer}
+ *
+ * @author Scribble
+ */
@Mixin(ChunkProviderServer.class)
-public abstract class MixinChunkProviderServer implements ChunkProviderDuck{
-
- @Shadow @Final
+public abstract class MixinChunkProviderServer implements ChunkProviderDuck {
+
+ /**
+ * The very inadequately named loadedChunkList
+ */
+ @Shadow
+ @Final
private Long2ObjectMap id2ChunkMap;
+ /**
+ * Saves and unloads chunk data.
+ *
Oddly, there is no definitive "unload" method in the ChunkProviderServer,
+ * you can only queue the chunks to be unloaded later ({@link ChunkProviderServer#queueUnload(Chunk)})
+ *
This method adds that functionality, so savestates can be loaded even in tickrate 0.
+ */
@Override
public void unloadAllChunks() {
- ObjectIterator> objectiterator = this.id2ChunkMap.values().iterator();
-
- while (objectiterator.hasNext())
- {
- Chunk chunk = (Chunk)objectiterator.next();
- this.saveChunkData(chunk);
- this.saveChunkExtraData(chunk);
- chunk.onUnload();
- }
- id2ChunkMap.clear();
- }
+ ObjectIterator> objectiterator = this.id2ChunkMap.values().iterator();
+
+ while (objectiterator.hasNext()) {
+ Chunk chunk = (Chunk) objectiterator.next();
+ this.saveChunkData(chunk);
+ this.saveChunkExtraData(chunk);
+ chunk.onUnload();
+ }
+ id2ChunkMap.clear();
+ }
+
@Shadow
abstract void saveChunkExtraData(Chunk chunk);
+
@Shadow
abstract void saveChunkData(Chunk chunk);
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinEntityPlayerMP.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinEntityPlayerMP.java
deleted file mode 100644
index 1de0ce97..00000000
--- a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinEntityPlayerMP.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.minecrafttas.tasmod.mixin.savestates;
-
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-import com.minecrafttas.tasmod.savestates.SavestateHandlerServer.PlayerHandler;
-
-import net.minecraft.entity.player.EntityPlayerMP;
-import net.minecraft.nbt.NBTTagCompound;
-
-@Mixin(EntityPlayerMP.class)
-public class MixinEntityPlayerMP {
-
- @Inject(method = "writeEntityToNBT", at = @At(value = "RETURN"))
- public void writeClientMotion(NBTTagCompound compound, CallbackInfo ci) {
- NBTTagCompound nbttagcompound = new NBTTagCompound();
- PlayerHandler.MotionData saver = PlayerHandler.getMotion().get((EntityPlayerMP) (Object) this);
- if (saver != null) {
- nbttagcompound.setDouble("x", saver.getClientX());
- nbttagcompound.setDouble("y", saver.getClientY());
- nbttagcompound.setDouble("z", saver.getClientZ());
- nbttagcompound.setFloat("RelativeX", saver.getClientrX());
- nbttagcompound.setFloat("RelativeY", saver.getClientrY());
- nbttagcompound.setFloat("RelativeZ", saver.getClientrZ());
- nbttagcompound.setBoolean("Sprinting", saver.isSprinting());
- nbttagcompound.setFloat("JumpFactor", saver.getJumpMovementVector());
- compound.setTag("clientMotion", nbttagcompound);
- } else {
- nbttagcompound.setDouble("x", 0D);
- nbttagcompound.setDouble("y", 0D);
- nbttagcompound.setDouble("z", 0D);
- nbttagcompound.setFloat("RelativeX", 0F);
- nbttagcompound.setFloat("RelativeY", 0F);
- nbttagcompound.setFloat("RelativeZ", 0F);
- compound.setTag("clientMotion", nbttagcompound);
- }
- }
-
- @Inject(method = "readEntityFromNBT", at = @At(value = "RETURN"))
- public void readClientMotion(NBTTagCompound compound, CallbackInfo ci) {
- NBTTagCompound nbttagcompound = compound.getCompoundTag("clientMotion");
-
- double clientmotionX = nbttagcompound.getDouble("x");
- double clientmotionY = nbttagcompound.getDouble("y");
- double clientmotionZ = nbttagcompound.getDouble("z");
- float clientmotionrX = nbttagcompound.getFloat("RelativeX");
- float clientmotionrY = nbttagcompound.getFloat("RelativeY");
- float clientmotionrZ = nbttagcompound.getFloat("RelativeZ");
- boolean sprinting = nbttagcompound.getBoolean("Sprinting");
- float jumpVector = nbttagcompound.getFloat("JumpFactor");
-
- PlayerHandler.MotionData saver = new PlayerHandler.MotionData(clientmotionX, clientmotionY, clientmotionZ, clientmotionrX, clientmotionrY, clientmotionrZ, sprinting, jumpVector);
- PlayerHandler.getMotion().put((EntityPlayerMP) (Object) this, saver);
-
- }
-}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinNetHandlerPlayServer.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinNetHandlerPlayServer.java
index 40d61059..d6a4a802 100644
--- a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinNetHandlerPlayServer.java
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinNetHandlerPlayServer.java
@@ -13,8 +13,11 @@
@Mixin(NetHandlerPlayServer.class)
public class MixinNetHandlerPlayServer {
+ /**
+ * Disables the "Player moved wrongly!" message during a savestate
+ */
@Redirect(method = "processPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/EntityPlayerMP;isInvulnerableDimensionChange()Z"))
public boolean redirect_processPlayer(EntityPlayerMP parentIn) {
- return !parentIn.isInvulnerableDimensionChange() && TASmod.savestateHandlerServer.state!=SavestateState.LOADING;
+ return !parentIn.isInvulnerableDimensionChange() && TASmod.savestateHandlerServer.state != SavestateState.LOADING;
}
}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinScoreboard.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinScoreboard.java
new file mode 100644
index 00000000..dc19b8b9
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinScoreboard.java
@@ -0,0 +1,50 @@
+package com.minecrafttas.tasmod.mixin.savestates;
+
+import java.util.List;
+import java.util.Map;
+
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+import com.minecrafttas.tasmod.util.Ducks.ScoreboardDuck;
+
+import net.minecraft.scoreboard.IScoreCriteria;
+import net.minecraft.scoreboard.Score;
+import net.minecraft.scoreboard.ScoreObjective;
+import net.minecraft.scoreboard.ScorePlayerTeam;
+import net.minecraft.scoreboard.Scoreboard;
+
+@Mixin(Scoreboard.class)
+public class MixinScoreboard implements ScoreboardDuck {
+ @Shadow
+ @Final
+ private Map scoreObjectives;
+ @Shadow
+ @Final
+ private Map> scoreObjectiveCriterias;
+ @Shadow
+ @Final
+ private Map> entitiesScoreObjectives;
+ @Shadow
+ @Final
+ private ScoreObjective[] objectiveDisplaySlots;
+ @Shadow
+ @Final
+ private Map teams;
+ @Shadow
+ @Final
+ private Map teamMemberships;
+
+ @Override
+ public void clearScoreboard() {
+ scoreObjectives.clear();
+ scoreObjectiveCriterias.clear();
+ entitiesScoreObjectives.clear();
+ for (int i = 0; i < objectiveDisplaySlots.length; i++) {
+ objectiveDisplaySlots[i] = null;
+ }
+ teams.clear();
+ teamMemberships.clear();
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinWorldClient.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinWorldClient.java
new file mode 100644
index 00000000..7027c68a
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinWorldClient.java
@@ -0,0 +1,26 @@
+package com.minecrafttas.tasmod.mixin.savestates;
+
+import java.util.Set;
+
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+import com.minecrafttas.tasmod.util.Ducks.WorldClientDuck;
+
+import net.minecraft.client.multiplayer.WorldClient;
+import net.minecraft.entity.Entity;
+
+@Mixin(WorldClient.class)
+public class MixinWorldClient implements WorldClientDuck {
+
+ @Shadow
+ @Final
+ private Set entityList;
+
+ @Override
+ public void clearEntityList() {
+ entityList.clear();
+ }
+
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinWorldServer.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinWorldServer.java
new file mode 100644
index 00000000..5572281b
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinWorldServer.java
@@ -0,0 +1,44 @@
+package com.minecrafttas.tasmod.mixin.savestates;
+
+import java.util.Iterator;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+import com.minecrafttas.tasmod.util.Ducks.WorldServerDuck;
+
+import net.minecraft.server.management.PlayerChunkMap;
+import net.minecraft.world.WorldServer;
+import net.minecraft.world.chunk.Chunk;
+
+/**
+ * Adds the {@link #sendChunksToClient()} method to to the WorldServer
+ *
+ * @author Scribble
+ */
+@Mixin(WorldServer.class)
+public abstract class MixinWorldServer implements WorldServerDuck {
+
+ @Shadow
+ private PlayerChunkMap playerChunkMap;
+
+ /**
+ * Tricks the {@link #playerChunkMap} into sending the loaded chunks to the client.
+ * In theory, the playerChunkMap just needs to be ticked once,
+ * in order for the {@link PlayerChunkMap#pendingSendToPlayers} chunks to be sent to the client.
+ *
This fails however because the {@link net.minecraft.server.management.PlayerChunkMapEntry#sendToPlayers() PlayerChunkMapEntry#sendToPlayers()} method, responsible for sending, has a {@link net.minecraft.world.chunk.Chunk#isPopulated() Chunk.isPopulated()} check.
+ *
To make this check return true, the chunk needs to be ticked once (as seen in {@link net.minecraft.world.chunk.Chunk#onTick(boolean) Chunk.onTick()}).
+ * In vanilla, this usually happens in the {@link WorldServer#updateBlocks()} method,
+ * but calling this method here updates a lot of other things as well, which we do not want.
+ *
That's why we iterate through the chunks to tick each once, then send them off via the playerChunkMap.
+ */
+ @Override
+ public void sendChunksToClient() {
+ for (Iterator iterator2 = this.playerChunkMap.getChunkIterator(); iterator2.hasNext();) {
+ Chunk chunk = (Chunk) iterator2.next();
+ chunk.enqueueRelightChecks();
+ chunk.onTick(false);
+ }
+ this.playerChunkMap.tick();
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/networking/TASmodBufferBuilder.java b/src/main/java/com/minecrafttas/tasmod/networking/TASmodBufferBuilder.java
index 053fd8ff..82e2b540 100644
--- a/src/main/java/com/minecrafttas/tasmod/networking/TASmodBufferBuilder.java
+++ b/src/main/java/com/minecrafttas/tasmod/networking/TASmodBufferBuilder.java
@@ -10,61 +10,61 @@
import com.minecrafttas.mctcommon.networking.ByteBufferBuilder;
import com.minecrafttas.mctcommon.networking.interfaces.PacketID;
import com.minecrafttas.tasmod.playback.PlaybackControllerClient.TASstate;
-import com.minecrafttas.tasmod.savestates.SavestateHandlerServer.PlayerHandler.MotionData;
+import com.minecrafttas.tasmod.savestates.storage.SavestateMotionStorage.MotionData;
import com.minecrafttas.tasmod.tickratechanger.TickrateChangerServer.TickratePauseState;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTSizeTracker;
import net.minecraft.nbt.NBTTagCompound;
-public class TASmodBufferBuilder extends ByteBufferBuilder{
+public class TASmodBufferBuilder extends ByteBufferBuilder {
public TASmodBufferBuilder(int id) {
super(id);
}
-
+
public TASmodBufferBuilder(PacketID packet) {
super(packet);
}
-
+
public TASmodBufferBuilder(ByteBuffer buf) {
super(buf);
}
-
+
public TASmodBufferBuilder writeTASState(TASstate state) {
- this.writeShort((short)state.ordinal());
+ this.writeShort((short) state.ordinal());
return this;
}
-
+
public TASmodBufferBuilder writeNBTTagCompound(NBTTagCompound compound) {
-
+
ByteArrayOutputStream out = new ByteArrayOutputStream();
-
+
DataOutputStream dataout = new DataOutputStream(out);
-
+
try {
CompressedStreamTools.write(compound, dataout);
} catch (IOException e) {
e.printStackTrace();
}
-
+
this.writeByteArray(out.toByteArray());
-
+
try {
out.close();
dataout.close();
} catch (IOException e) {
e.printStackTrace();
}
-
+
return this;
}
-
+
public TASmodBufferBuilder writeTickratePauseState(TickratePauseState state) {
writeShort((short) state.ordinal());
return this;
}
-
+
public TASmodBufferBuilder writeMotionData(MotionData data) {
writeDouble(data.getClientX());
writeDouble(data.getClientY());
@@ -76,28 +76,28 @@ public TASmodBufferBuilder writeMotionData(MotionData data) {
writeBoolean(data.isSprinting());
return this;
}
-
+
public static TASstate readTASState(ByteBuffer buf) {
return TASstate.values()[buf.getShort()];
}
-
+
public static NBTTagCompound readNBTTagCompound(ByteBuffer buf) throws IOException {
ByteArrayInputStream input = new ByteArrayInputStream(readByteArray(buf));
-
+
DataInputStream datain = new DataInputStream(input);
-
+
NBTTagCompound compound = CompressedStreamTools.read(datain, NBTSizeTracker.INFINITE);
-
+
input.close();
datain.close();
-
+
return compound;
}
-
+
public static TickratePauseState readTickratePauseState(ByteBuffer buf) {
return TickratePauseState.values()[buf.getShort()];
}
-
+
public static MotionData readMotionData(ByteBuffer buf) {
double x = TASmodBufferBuilder.readDouble(buf);
double y = TASmodBufferBuilder.readDouble(buf);
@@ -107,8 +107,8 @@ public static MotionData readMotionData(ByteBuffer buf) {
float rz = TASmodBufferBuilder.readFloat(buf);
float jumpMovementVector = TASmodBufferBuilder.readFloat(buf);
boolean sprinting = TASmodBufferBuilder.readBoolean(buf);
-
+
return new MotionData(x, y, z, rx, ry, rz, sprinting, jumpMovementVector);
}
-
+
}
diff --git a/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommandsRegistry.java b/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommandsRegistry.java
index d70e4f5e..f5fd3c3f 100644
--- a/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommandsRegistry.java
+++ b/src/main/java/com/minecrafttas/tasmod/playback/filecommands/PlaybackFileCommandsRegistry.java
@@ -174,6 +174,6 @@ private void saveConfig() {
nameList.add(element.getExtensionName());
});
config.set(TASmodConfig.EnabledFileCommands, String.join(", ", nameList));
- config.save();
+ config.saveToXML();
}
}
diff --git a/src/main/java/com/minecrafttas/tasmod/playback/filecommands/integrated/DesyncMonitorFileCommandExtension.java b/src/main/java/com/minecrafttas/tasmod/playback/filecommands/integrated/DesyncMonitorFileCommandExtension.java
index a89fef45..7c3fed4d 100644
--- a/src/main/java/com/minecrafttas/tasmod/playback/filecommands/integrated/DesyncMonitorFileCommandExtension.java
+++ b/src/main/java/com/minecrafttas/tasmod/playback/filecommands/integrated/DesyncMonitorFileCommandExtension.java
@@ -52,7 +52,7 @@ public String[] getFileCommandNames() {
@Override
public void onControllerStateChange(TASstate newstate, TASstate oldstate) {
- if(newstate==TASstate.RECORDING && monitorContainer.isEmpty()) {
+ if (newstate == TASstate.RECORDING && monitorContainer.isEmpty()) {
recordNull(0);
}
}
@@ -179,13 +179,7 @@ public String getPos() {
values[1] = getFormattedString(player.posY - currentValues.values[1]);
values[2] = getFormattedString(player.posZ - currentValues.values[2]);
- String out = "";
- for (String val : values) {
- if (val != null) {
- out += val + " ";
- }
- }
- lastPos = out;
+ lastPos = String.join(" ", values);
}
return lastPos;
}
@@ -200,13 +194,7 @@ public String getMotion() {
values[1] = getFormattedString(player.motionY - currentValues.values[4]);
values[2] = getFormattedString(player.motionZ - currentValues.values[5]);
- String out = "";
- for (String val : values) {
- if (val != null) {
- out += val + " ";
- }
- }
- lastMotion = out;
+ lastMotion = String.join(" ", values);
}
return lastMotion;
}
@@ -247,14 +235,14 @@ public MonitorContainer(long index) {
public String[] toStringArray() {
String[] out = new String[values.length];
for (int i = 0; i < values.length; i++) {
- out[i] = String.format(Locale.ENGLISH, "%.5f", values[i]);
+ out[i] = String.format(Locale.ENGLISH, "%s", values[i]);
}
return out;
}
@Override
public String toString() {
- return String.format(Locale.US, "%d, %d, %d, %d, %d, %d", values[0], values[1], values[2], values[3], values[4], values[5]);
+ return String.format(Locale.ENGLISH, "%d, %d, %d, %d, %d, %d", values[0], values[1], values[2], values[3], values[4], values[5]);
}
public DesyncStatus getSeverity(long index, double[] playerValues) {
diff --git a/src/main/java/com/minecrafttas/tasmod/playback/metadata/PlaybackMetadata.java b/src/main/java/com/minecrafttas/tasmod/playback/metadata/PlaybackMetadata.java
index 3ad74cd8..fe4da30c 100644
--- a/src/main/java/com/minecrafttas/tasmod/playback/metadata/PlaybackMetadata.java
+++ b/src/main/java/com/minecrafttas/tasmod/playback/metadata/PlaybackMetadata.java
@@ -16,7 +16,7 @@ public class PlaybackMetadata {
private String extensionName;
private LinkedHashMap data;
-
+
private static String SEPERATOR = ":";
public PlaybackMetadata(PlaybackMetadataExtension extension) {
@@ -81,7 +81,7 @@ public boolean equals(Object obj) {
public static PlaybackMetadata fromStringList(String extensionName, List list) {
PlaybackMetadata out = new PlaybackMetadata(extensionName);
- final Pattern pattern = Pattern.compile("(\\w+)\\"+SEPERATOR+"(.+)");
+ final Pattern pattern = Pattern.compile("(\\w+)\\" + SEPERATOR + "(.+)");
for (String data : list) {
Matcher matcher = pattern.matcher(data);
@@ -94,19 +94,20 @@ public static PlaybackMetadata fromStringList(String extensionName, List
return out;
}
-
+
public static PlaybackMetadata fromHashMap(String extensionName, LinkedHashMap data) {
return new PlaybackMetadata(extensionName, new LinkedHashMap<>(data));
}
-
+
public static abstract class PlaybackMetadataExtension implements Registerable {
-
+
/**
* Currently unused.
* Maybe in the future, TASes have to be created with /create, then you can interactively set the values...
*/
- public void onCreate() {};
-
+ public void onCreate() {
+ };
+
/**
* Runs, when the TASfile is being stored to a file.
* Create a new {@link PlaybackMetadata} with PlaybackMetadata metadata = new PlaybackMetadata(this);.
@@ -115,14 +116,14 @@ public static abstract class PlaybackMetadataExtension implements Registerable {
* @return The {@link PlaybackMetadata} to be saved in the TASfile
*/
public abstract PlaybackMetadata onStore();
-
+
/**
* Runs when the TASfile is being loaded from a file
*
* @param metadata The metadata for this extension to read from
*/
public abstract void onLoad(PlaybackMetadata metadata);
-
+
/**
* Runs when the PlaybackController is cleared
*/
diff --git a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java
index e8945a7f..d2a61054 100644
--- a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java
+++ b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiser.java
@@ -87,8 +87,6 @@ public static void saveToFile(File file, BigArrayList container,
if (defaultFlavor == null || defaultFlavor.isEmpty())
throw new PlaybackSaveException("No default flavor specified... Please specify a flavor name first");
flavorName = defaultFlavor;
- } else {
- defaultFlavor = flavorName;
}
FileThread writerThread;
@@ -101,6 +99,12 @@ public static void saveToFile(File file, BigArrayList container,
SerialiserFlavorBase flavor = TASmodAPIRegistry.SERIALISER_FLAVOR.getFlavor(flavorName);
+ if (flavor == null) {
+ throw new PlaybackSaveException("Flavor %s doesn't exist", flavorName);
+ }
+
+ defaultFlavor = flavorName;
+
List header = flavor.serialiseHeader();
for (String line : header) {
writerThread.addLine(line);
@@ -124,6 +128,10 @@ public static void saveToFile(File file, BigArrayList container,
* @throws IOException If the file could not be read
*/
public static BigArrayList loadFromFile(File file) throws PlaybackLoadException, IOException {
+ return loadFromFile(file, true);
+ }
+
+ public static BigArrayList loadFromFile(File file, boolean processExtensions) throws PlaybackLoadException, IOException {
if (file == null) {
throw new PlaybackLoadException("Load from file failed. No file specified");
}
@@ -133,6 +141,8 @@ public static BigArrayList loadFromFile(File file) throws Playbac
SerialiserFlavorBase flavor = readFlavor(file);
+ flavor.setProcessExtensions(processExtensions);
+
return loadFromFile(file, flavor);
}
@@ -146,7 +156,11 @@ public static BigArrayList loadFromFile(File file) throws Playbac
* @throws IOException If the file could not be read
*/
public static BigArrayList loadFromFile(File file, String flavorName) throws PlaybackLoadException, IOException {
-
+ return loadFromFile(file, flavorName, true);
+ }
+
+ public static BigArrayList loadFromFile(File file, String flavorName, boolean processExtensions) throws PlaybackLoadException, IOException {
+
// If the flavor is null or empty, try to determine the flavor by reading the header
if (flavorName == null || flavorName.isEmpty()) {
return loadFromFile(file);
@@ -165,6 +179,8 @@ public static BigArrayList loadFromFile(File file, String flavorN
throw new PlaybackLoadException("Detected flavor %s in the TASfile, which does not match the specified flavor: %s");
}
+ flavor.setProcessExtensions(processExtensions);
+
return loadFromFile(file, flavor);
}
diff --git a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiserOld.java b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiserOld.java
index 9a36dcf2..589f3afd 100644
--- a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiserOld.java
+++ b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/PlaybackSerialiserOld.java
@@ -12,7 +12,6 @@
import org.apache.commons.io.FileUtils;
import com.dselent.bigarraylist.BigArrayList;
-import com.minecrafttas.tasmod.TASmod;
import com.minecrafttas.tasmod.playback.PlaybackControllerClient;
import com.minecrafttas.tasmod.playback.PlaybackControllerClient.TickContainer;
import com.minecrafttas.tasmod.playback.filecommands.integrated.DesyncMonitorFileCommandExtension;
@@ -209,7 +208,7 @@ public PlaybackControllerClient fromEntireFileV1(File file) throws IOException {
String startLocation="";
// Default the start seed to the current global ktrng seed. If KTRNG is not loaded, defaults to 0
- long startSeed=TASmod.ktrngHandler.getGlobalSeedClient();
+ long startSeed/*=TASmod.ktrngHandler.getGlobalSeedClient()*/;
// Clear the current container before reading new data
controller.clear();
diff --git a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java
index f671068a..592bcf69 100644
--- a/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java
+++ b/src/main/java/com/minecrafttas/tasmod/playback/tasfile/flavor/SerialiserFlavorBase.java
@@ -43,6 +43,11 @@ public abstract class SerialiserFlavorBase implements Registerable {
protected TickContainer previousTickContainer = null;
+ /**
+ * If true, process extension data like {@link PlaybackMetadata PlaybackMetadata} and {@link PlaybackFileCommand PlaybackFileCommands}
+ */
+ protected boolean processExtensions = true;
+
protected String headerStart() {
return createCenteredHeading("TASfile", '#', 50);
}
@@ -89,12 +94,17 @@ protected void serialiseFlavorName(List out) {
protected void serialiseFileCommandNames(List out) {
List stringlist = new ArrayList<>();
List extensionList = TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.getEnabled();
- extensionList.forEach(extension -> stringlist.add(extension.getExtensionName()));
+ if (processExtensions) {
+ extensionList.forEach(extension -> stringlist.add(extension.getExtensionName()));
+ }
out.add("FileCommand-Extensions: " + String.join(", ", stringlist));
out.add("");
}
protected void serialiseMetadata(List out) {
+ if (!processExtensions)
+ return;
+
List metadataList = TASmodAPIRegistry.PLAYBACK_METADATA.handleOnStore();
for (PlaybackMetadata metadata : metadataList) {
@@ -122,7 +132,7 @@ public BigArrayList serialise(BigArrayList inputs, long t
break;
}
currentTick = i;
- TickContainer container = inputs.get(i);
+ TickContainer container = inputs.get(i).clone();
serialiseContainer(out, container);
previousTickContainer = container;
}
@@ -152,6 +162,8 @@ protected void serialiseContainer(BigArrayList out, TickContainer contai
}
protected String serialiseFileCommand(PlaybackFileCommand fileCommand) {
+ if (!processExtensions)
+ return "";
return String.format("$%s(%s);", fileCommand.getName(), String.join(", ", fileCommand.getArgs()));
}
@@ -193,15 +205,12 @@ protected List serialiseMouse(VirtualMouse mouse) {
protected List serialiseCameraAngle(VirtualCameraAngle cameraAngle) {
VirtualCameraAngle previousCamera = null;
- if (previousTickContainer != null) {
- previousCamera = previousTickContainer.getCameraAngle();
- }
List out = new ArrayList<>();
for (VirtualCameraAngle subtick : cameraAngle.getAll()) {
if (!subtick.equals(previousCamera))
- out.add(subtick.toString2());
+ out.add(String.format("%s;%s", subtick.getYaw(), subtick.getPitch()));
previousCamera = subtick;
}
@@ -299,7 +308,7 @@ protected String getOrEmpty(String string) {
* Joins strings together but ignores empty strings
*
* @param delimiter The delimiter of the joined string
- * @param args The strings to join
+ * @param args The strings to join
* @return Joined string
*/
protected String joinNotEmpty(String delimiter, Iterable args) {
@@ -368,10 +377,17 @@ public List extractHeader(BigArrayList lines) {
}
protected void deserialiseFileCommandNames(List headerLines) {
+ if (!processExtensions) // Stops FileCommandProcessing
+ return;
+
for (String line : headerLines) {
Matcher matcher = extract("FileCommand-Extensions: ?(.*)", line);
if (matcher.find()) {
+
+ if (!processExtensions)
+ return;
+
String extensionStrings = matcher.group(1);
String[] extensionNames = extensionStrings.split(", ?");
@@ -383,6 +399,9 @@ protected void deserialiseFileCommandNames(List headerLines) {
}
protected void deserialiseMetadata(List headerLines) {
+ if (!processExtensions)
+ return;
+
List out = new ArrayList<>();
String metadataName = null;
@@ -429,9 +448,9 @@ public BigArrayList deserialise(BigArrayList lines, long
// Extract the tick and set the index
i = extractContainer(container, lines, i);
currentLine = i;
- currentTick++;
// Extract container
deserialiseContainer(out, container);
+ currentTick++;
}
previousTickContainer = null;
return out;
@@ -619,8 +638,10 @@ protected void deserialiseContainer(BigArrayList out, List deserialisedFileCommands) {
+
Matcher matcher = extract("\\$(.+?)\\((.*?)\\);", comment);
while (matcher.find()) {
String name = matcher.group(1);
String[] args = matcher.group(2).split(", ?");
- deserialisedFileCommands.add(new PlaybackFileCommand(name, args));
+
+ if (processExtensions)
+ deserialisedFileCommands.add(new PlaybackFileCommand(name, args));
+
comment = matcher.replaceFirst("");
matcher.reset(comment);
}
@@ -686,8 +711,10 @@ protected VirtualKeyboard deserialiseKeyboard(List keyboardStrings) {
String[] keys = matcher.group(1).split(",");
char[] chars = matcher.group(2).toCharArray();
- int[] keycodes = deserialiseVirtualKey(keys, VirtualKey.ZERO);
+ int[] keycodes = deserialiseVirtualKeyboardKey(keys);
out.updateFromState(keycodes, chars);
+ } else {
+ throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, "Keyboard could not be read. Probably a missing semicolon: %s", line);
}
currentSubtick++;
}
@@ -707,7 +734,7 @@ protected VirtualMouse deserialiseMouse(List mouseStrings) {
String[] buttons = matcher.group(1).split(",");
String[] functions = matcher.group(2).split(",");
- int[] keycodes = deserialiseVirtualKey(buttons, VirtualKey.MOUSEMOVED);
+ int[] keycodes = deserialiseVirtualMouseKey(buttons);
int scrollwheel;
Integer cursorX;
Integer cursorY;
@@ -717,13 +744,15 @@ protected VirtualMouse deserialiseMouse(List mouseStrings) {
cursorX = deserialiseRelativeInt("cursorX", functions[1], previousCursorX);
cursorY = deserialiseRelativeInt("cursorY", functions[2], previousCursorY);
} else {
- throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, "Mouse functions do not have the correct length");
+ throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, "Mouse can't be read. Probably a missing comma: %s", line);
}
out.updateFromState(keycodes, scrollwheel, cursorX, cursorY);
previousCursorX = cursorX;
previousCursorY = cursorY;
+ } else {
+ throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, "Mouse is missing a semicolon");
}
currentSubtick++;
}
@@ -741,57 +770,92 @@ protected VirtualCameraAngle deserialiseCameraAngle(List cameraAngleStri
Matcher matcher = extract("(.+?);(.+)", line);
if (matcher.find()) {
- String cameraPitchString = matcher.group(1);
- String cameraYawString = matcher.group(2);
+ String cameraYawString = matcher.group(1);
+ String cameraPitchString = matcher.group(2);
- Float cameraPitch = null;
Float cameraYaw = null;
-
- if (!"null".equals(cameraPitchString))
- cameraPitch = deserialiseRelativeFloat("camera pitch", cameraPitchString, previousPitch);
+ Float cameraPitch = null;
if (!"null".equals(cameraYawString))
cameraYaw = deserialiseRelativeFloat("camera yaw", cameraYawString, previousYaw);
+ if (!"null".equals(cameraPitchString))
+ cameraPitch = deserialiseRelativeFloat("camera pitch", cameraPitchString, previousPitch);
+
out.updateFromState(cameraPitch, cameraYaw);
+ } else {
+ throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, "Camera is missing a semicolon");
}
currentSubtick++;
}
return out;
}
- protected int[] deserialiseVirtualKey(String[] keyString, VirtualKey defaultKey) {
+ protected int[] deserialiseVirtualKeyboardKey(String[] keyString) {
int[] out = new int[keyString.length];
for (int i = 0; i < keyString.length; i++) {
String key = keyString[i];
+ out[i] = deserialiseVirtualKey(key, VirtualKey.ZERO, (vkey) -> {
+ if (vkey < 0) {
+ throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, "Keyboard section contains a mouse key: %s", VirtualKey.get(vkey));
+ }
+ });
+ }
+ return out;
+ }
- /* If no key is pressed, then a zero key will be used for the state.
- * This zero key is either VirtualKey.ZERO on a keyboard or VirtualKey.MOUSEMOVED on a mouse,
- * hence the parameter */
- if (key.isEmpty()) {
- out[i] = defaultKey.getKeycode();
- continue;
- }
-
- /* Instead of keynames such as W, A, S, KEY_1, NUMPAD3 you can also write the numerical keycodes
- * into the tasfile, e.g. 17, 30, 31, 2, 81. This enables TASmod to support every current and future
- * keycodes, even if no name was given to the key in VirtualKey.*/
- if (isNumeric(key)) {
- out[i] = Integer.parseInt(key);
- continue;
- }
+ protected int[] deserialiseVirtualMouseKey(String[] keyString) {
+ int[] out = new int[keyString.length];
- out[i] = VirtualKey.getKeycode(key);
+ for (int i = 0; i < keyString.length; i++) {
+ String key = keyString[i];
+ out[i] = deserialiseVirtualKey(key, VirtualKey.MOUSEMOVED, (vkey) -> {
+ if (vkey >= 0) {
+ throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, "Mouse section contains a keyboard key: %s", VirtualKey.get(vkey));
+ }
+ });
}
return out;
}
+ protected int deserialiseVirtualKey(String key, VirtualKey defaultKey, WrongKeyCheck keyValidator) {
+
+ Integer vkey = null;
+ /* If no key is pressed, then a zero key will be used for the state.
+ * This zero key is either VirtualKey.ZERO on a keyboard or VirtualKey.MOUSEMOVED on a mouse,
+ * hence the parameter */
+ if (key.isEmpty()) {
+ vkey = defaultKey.getKeycode();
+ }
+ /* Instead of keynames such as W, A, S, KEY_1, NUMPAD3 you can also write the numerical keycodes
+ * into the tasfile, e.g. 17, 30, 31, 2, 81. This enables TASmod to support every current and future
+ * keycodes, even if no name was given to the key in VirtualKey.*/
+ else if (isNumeric(key)) {
+ vkey = Integer.parseInt(key);
+ } else {
+ vkey = VirtualKey.getKeycode(key);
+ }
+
+ if (vkey == null) {
+ throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, "The keycode %s does not exist", key);
+ }
+
+ keyValidator.checkKey(vkey);
+
+ return vkey;
+ }
+
+ @FunctionalInterface
+ protected interface WrongKeyCheck {
+ public void checkKey(int key) throws PlaybackLoadException;
+ }
+
protected int parseInt(String name, String intstring) {
try {
return Integer.parseInt(intstring);
} catch (NumberFormatException e) {
- throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, e, "Can't parse integer in %s", name);
+ throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, e, "The %s could not be processed. This should be a number: %s", name, intstring);
}
}
@@ -815,7 +879,7 @@ protected float parseFloat(String name, String floatstring) {
try {
return Float.parseFloat(floatstring);
} catch (NumberFormatException e) {
- throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, e, "Can't parse float in %s", name);
+ throw new PlaybackLoadException(currentLine, currentTick, currentSubtick, e, "The %s could not be processed. This should be a decimal number: %s", name, floatstring);
}
}
@@ -843,7 +907,8 @@ protected void splitInputs(List lines, List serialisedKeyboard,
String previousCamera = null;
if (previousTickContainer != null) {
- previousCamera = previousTickContainer.getCameraAngle().toString2();
+ VirtualCameraAngle camera = previousTickContainer.getCameraAngle();
+ previousCamera = String.format("%s;%s", camera.getYaw(), camera.getPitch());
}
for (String line : lines) {
@@ -1016,4 +1081,8 @@ public boolean equals(Object obj) {
}
return super.equals(obj);
}
+
+ public void setProcessExtensions(boolean processExtensions) {
+ this.processExtensions = processExtensions;
+ }
}
diff --git a/src/main/java/com/minecrafttas/tasmod/registries/TASmodAPIRegistry.java b/src/main/java/com/minecrafttas/tasmod/registries/TASmodAPIRegistry.java
index 86e68530..62804042 100644
--- a/src/main/java/com/minecrafttas/tasmod/registries/TASmodAPIRegistry.java
+++ b/src/main/java/com/minecrafttas/tasmod/registries/TASmodAPIRegistry.java
@@ -25,7 +25,7 @@ public class TASmodAPIRegistry {
*
*/
public static final PlaybackFileCommandsRegistry PLAYBACK_FILE_COMMAND = new PlaybackFileCommandsRegistry();
-
+
/**
* Registry for registering custom serialiser flavors that dictate the syntax of the inputs stored in the TASfile.
*
@@ -35,5 +35,4 @@ public class TASmodAPIRegistry {
* The resulting flavor can be registered here and can be found as a saving option with /saveTAS
*/
public static final SerialiserFlavorRegistry SERIALISER_FLAVOR = new SerialiserFlavorRegistry();
-
}
diff --git a/src/main/java/com/minecrafttas/tasmod/registries/TASmodConfig.java b/src/main/java/com/minecrafttas/tasmod/registries/TASmodConfig.java
index 166582c3..645c518c 100644
--- a/src/main/java/com/minecrafttas/tasmod/registries/TASmodConfig.java
+++ b/src/main/java/com/minecrafttas/tasmod/registries/TASmodConfig.java
@@ -1,7 +1,12 @@
package com.minecrafttas.tasmod.registries;
-import com.minecrafttas.mctcommon.Configuration.ConfigOptions;
+import com.minecrafttas.mctcommon.ConfigurationRegistry.ConfigOptions;
+/**
+ * The config options that will be stored in .minecraft/config/tasmod.cfg
+ *
+ * @author Scribble
+ */
public enum TASmodConfig implements ConfigOptions {
FileToOpen("fileToOpen", ""),
ServerConnection("serverConnection", ""),
@@ -9,12 +14,12 @@ public enum TASmodConfig implements ConfigOptions {
private String configKey;
private String defaultValue;
-
+
private TASmodConfig(String configKey, String defaultValue) {
this.configKey = configKey;
this.defaultValue = defaultValue;
}
-
+
@Override
public String getDefaultValue() {
return defaultValue;
@@ -29,5 +34,4 @@ public String getConfigKey() {
public String getExtensionName() {
return "TASmodConfig";
}
-
}
diff --git a/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java b/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java
index 5abafea7..6743870c 100644
--- a/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java
+++ b/src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java
@@ -11,16 +11,12 @@
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.KeyBinding;
-import net.minecraft.util.text.ChatType;
-import net.minecraft.util.text.TextComponentString;
-import net.minecraft.util.text.TextFormatting;
public enum TASmodKeybinds {
TICKRATE_0("Tickrate 0 Key", "TASmod", Keyboard.KEY_F8, () -> TASmodClient.tickratechanger.togglePause(), VirtualKeybindings::isKeyDown),
ADVANCE("Advance Tick", "TASmod", Keyboard.KEY_F9, () -> TASmodClient.tickratechanger.advanceTick(), VirtualKeybindings::isKeyDown),
STOP("Recording/Playback Stop", "TASmod", Keyboard.KEY_F10, () -> TASmodClient.controller.setTASState(TASstate.NONE), VirtualKeybindings::isKeyDown),
SAVESTATE("Create Savestate", "TASmod", Keyboard.KEY_J, () -> {
- Minecraft.getMinecraft().ingameGUI.addChatMessage(ChatType.CHAT, new TextComponentString("Savestates might not work correctly at the moment... rewriting a lot of core features, which might break this..."));
try {
TASmodClient.client.send(new TASmodBufferBuilder(TASmodPackets.SAVESTATE_SAVE).writeInt(-1));
} catch (Exception e) {
@@ -28,7 +24,6 @@ public enum TASmodKeybinds {
}
}),
LOADSTATE("Load Latest Savestate", "TASmod", Keyboard.KEY_K, () -> {
- Minecraft.getMinecraft().ingameGUI.addChatMessage(ChatType.CHAT, new TextComponentString(TextFormatting.RED + "Savestates might not work correctly at the moment... rewriting a lot of core features, which might break this..."));
try {
TASmodClient.client.send(new TASmodBufferBuilder(TASmodPackets.SAVESTATE_LOAD).writeInt(-1));
} catch (Exception e) {
@@ -37,7 +32,6 @@ public enum TASmodKeybinds {
}),
INFO_GUI("Open InfoGui Editor", "TASmod", Keyboard.KEY_F6, () -> Minecraft.getMinecraft().displayGuiScreen(TASmodClient.hud)),
TEST1("Various Testing", "TASmod", Keyboard.KEY_F12, () -> {
- TASmodClient.controller.setTASState(TASstate.RECORDING);
}, VirtualKeybindings::isKeyDown),
TEST2("Various Testing2", "TASmod", Keyboard.KEY_F7, () -> {
// try {
diff --git a/src/main/java/com/minecrafttas/tasmod/registries/TASmodPackets.java b/src/main/java/com/minecrafttas/tasmod/registries/TASmodPackets.java
index 31c4cbd1..cc2fdb26 100644
--- a/src/main/java/com/minecrafttas/tasmod/registries/TASmodPackets.java
+++ b/src/main/java/com/minecrafttas/tasmod/registries/TASmodPackets.java
@@ -8,9 +8,11 @@
import com.minecrafttas.tasmod.playback.PlaybackControllerClient.TASstate;
import com.minecrafttas.tasmod.playback.filecommands.PlaybackFileCommand.PlaybackFileCommandExtension;
import com.minecrafttas.tasmod.playback.tasfile.flavor.SerialiserFlavorBase;
-import com.minecrafttas.tasmod.savestates.SavestateHandlerServer.PlayerHandler.MotionData;
+import com.minecrafttas.tasmod.savestates.storage.SavestateMotionStorage.MotionData;
import com.minecrafttas.tasmod.tickratechanger.TickrateChangerServer.TickratePauseState;
+import com.minecrafttas.tasmod.util.Ducks.ScoreboardDuck;
+import net.minecraft.client.Minecraft;
import net.minecraft.nbt.NBTTagCompound;
/**
@@ -81,12 +83,28 @@ public enum TASmodPackets implements PacketID {
* Client->Server {@link MotionData} motionData An Object containing all necessary motion data
*/
SAVESTATE_REQUEST_MOTION,
+ /**
+ * Used for setting the client motion data after it was loaded from a savestate
+ *
Side: Client
+ * ARGS:
+ * Server->Client {@link MotionData} motionData An Object containing all necessary motion data
+ */
+ SAVESTATE_SET_MOTION,
/**
*
Unloads the chunks on the client side
*
SIDE: Client
* ARGS: none
*/
SAVESTATE_UNLOAD_CHUNKS,
+ /**
+ *
Clears the scoreboard on the client side
+ *
SIDE: Client
+ * ARGS: none
+ */
+ SAVESTATE_CLEAR_SCOREBOARD(Side.CLIENT, (buf, clientID) -> {
+ Minecraft mc = Minecraft.getMinecraft();
+ ((ScoreboardDuck) mc.world.getScoreboard()).clearScoreboard();
+ }),
/**
*
Notifies the client to clear all inputs from the input buffer in {@link PlaybackControllerClient}
*
SIDE: Both
@@ -189,6 +207,16 @@ public enum TASmodPackets implements PacketID {
break;
}
}),
+ /**
+ *
Clears the current gui screen on the client
+ *
+ *
Side: CLIENT
+ * ARGS: none
+ */
+ CLEAR_SCREEN(Side.CLIENT, (buf, clientID) -> {
+ Minecraft mc = Minecraft.getMinecraft();
+ mc.displayGuiScreen(null);
+ }),
/**
*
Requests the list of TASfiles in the folder from the client for use in tab completions
*
SIDE: Both
@@ -207,7 +235,7 @@ public enum TASmodPackets implements PacketID {
COMMAND_FLAVORLIST,
/**
*
Requests the list of {@link PlaybackFileCommandExtension PlaybackFileCommandExtensions} from the client for use in tab completions
- *
SIDE: Bith
+ *
SIDE: Both
* ARGS:
* Server->Client None
* Client->Server String The string of file command names, seperated with |
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java
index 1b7b9ac5..159a5259 100644
--- a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java
@@ -7,23 +7,28 @@
import java.nio.ByteBuffer;
import com.dselent.bigarraylist.BigArrayList;
+import com.minecrafttas.mctcommon.events.EventListenerRegistry;
import com.minecrafttas.mctcommon.networking.Client.Side;
import com.minecrafttas.mctcommon.networking.exception.PacketNotImplementedException;
import com.minecrafttas.mctcommon.networking.exception.WrongSideException;
import com.minecrafttas.mctcommon.networking.interfaces.ClientPacketHandler;
import com.minecrafttas.mctcommon.networking.interfaces.PacketID;
import com.minecrafttas.tasmod.TASmodClient;
+import com.minecrafttas.tasmod.events.EventSavestate;
+import com.minecrafttas.tasmod.mixin.savestates.AccessorEntityLivingBase;
import com.minecrafttas.tasmod.mixin.savestates.MixinChunkProviderClient;
import com.minecrafttas.tasmod.networking.TASmodBufferBuilder;
import com.minecrafttas.tasmod.playback.PlaybackControllerClient;
import com.minecrafttas.tasmod.playback.PlaybackControllerClient.TASstate;
import com.minecrafttas.tasmod.playback.PlaybackControllerClient.TickContainer;
import com.minecrafttas.tasmod.playback.tasfile.PlaybackSerialiser;
+import com.minecrafttas.tasmod.registries.TASmodAPIRegistry;
import com.minecrafttas.tasmod.registries.TASmodPackets;
-import com.minecrafttas.tasmod.savestates.SavestateHandlerServer.PlayerHandler.MotionData;
import com.minecrafttas.tasmod.savestates.exceptions.SavestateException;
import com.minecrafttas.tasmod.savestates.gui.GuiSavestateSavingScreen;
import com.minecrafttas.tasmod.util.Ducks.ChunkProviderDuck;
+import com.minecrafttas.tasmod.util.Ducks.SubtickDuck;
+import com.minecrafttas.tasmod.util.Ducks.WorldClientDuck;
import com.minecrafttas.tasmod.util.LoggerMarkers;
import com.mojang.realmsclient.gui.ChatFormatting;
@@ -32,7 +37,6 @@
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.multiplayer.ChunkProviderClient;
-import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.TextComponentString;
@@ -44,7 +48,7 @@
*
* @author Scribble
*/
-public class SavestateHandlerClient implements ClientPacketHandler {
+public class SavestateHandlerClient implements ClientPacketHandler, EventSavestate.EventClientCompleteLoadstate, EventSavestate.EventClientLoadPlayer {
public final static File savestateDirectory = new File(TASmodClient.tasdirectory + File.separator + "savestates");
@@ -65,8 +69,8 @@ public class SavestateHandlerClient implements ClientPacketHandler {
*
* Side: Client
*/
- @Environment(EnvType.CLIENT)
- public static void keepPlayerInLoadedEntityList(net.minecraft.entity.player.EntityPlayer player) {
+ @Override
+ public void onClientLoadPlayer(EntityPlayerSP player) {
LOGGER.trace(LoggerMarkers.Savestate, "Keep player {} in loaded entity list", player.getName());
Minecraft.getMinecraft().world.unloadedEntityList.remove(player);
}
@@ -87,8 +91,9 @@ public static void keepPlayerInLoadedEntityList(net.minecraft.entity.player.Enti
*
* Side: Client
*/
- @Environment(EnvType.CLIENT)
- public static void addPlayerToClientChunk(EntityPlayer player) {
+ @Override
+ public void onClientLoadstateComplete() {
+ EntityPlayerSP player = Minecraft.getMinecraft().player;
LOGGER.trace(LoggerMarkers.Savestate, "Add player {} to loaded entity list", player.getName());
int i = MathHelper.floor(player.posX / 16.0D);
int j = MathHelper.floor(player.posZ / 16.0D);
@@ -164,7 +169,7 @@ public static void loadstate(String nameOfSavestate) throws Exception {
BigArrayList savestateContainerList;
if (targetfile.exists()) {
- savestateContainerList = PlaybackSerialiser.loadFromFile(targetfile);
+ savestateContainerList = PlaybackSerialiser.loadFromFile(targetfile, state != TASstate.PLAYBACK);
} else {
controller.setTASStateClient(TASstate.NONE, false);
Minecraft.getMinecraft().player.sendMessage(new TextComponentString(ChatFormatting.YELLOW + "Inputs could not be loaded for this savestate,"));
@@ -175,7 +180,7 @@ public static void loadstate(String nameOfSavestate) throws Exception {
/*
* Imagine a recording that is 20 tick long with VV showing the current index of the controller:
- * VV
+ * VV
* 0 20
* <====================>
*
@@ -186,7 +191,7 @@ public static void loadstate(String nameOfSavestate) throws Exception {
*
* We expect to resume the recording at the 10th tick.
* Therefore when loading a client savestate during a recording we set the index to size-1 and preload the inputs at the same index.
- * VV
+ * VV
* 0 10
* <==========>
*
@@ -194,7 +199,6 @@ public static void loadstate(String nameOfSavestate) throws Exception {
if (state == TASstate.RECORDING) {
long index = savestateContainerList.size() - 1;
- preload(savestateContainerList, index);
controller.setInputs(savestateContainerList, index);
/*
@@ -207,7 +211,7 @@ public static void loadstate(String nameOfSavestate) throws Exception {
* The loadstated file is SMALLER than the total inputs in the controller:
*
* The recording is 20 ticks long, with VV being the index where the playback is currently at.
- * VV
+ * VV
* 0 13 20
* <====================>
*
@@ -220,7 +224,7 @@ public static void loadstate(String nameOfSavestate) throws Exception {
* If we were to replace the controller, everything above tick 10 would be lost.
* So we only set the index to 10, preload and preload the inputs.
*
- * VV
+ * VV
* 0 10 20
* <====================>
* */
@@ -244,11 +248,17 @@ public static void loadstate(String nameOfSavestate) throws Exception {
controller.setInputs(savestateContainerList, index);
}
}
+
+ TASmodClient.tickSchedulerClient.add(() -> {
+ EventListenerRegistry.fireEvent(EventSavestate.EventClientCompleteLoadstate.class);
+ });
}
private static void preload(BigArrayList containerList, long index) {
TickContainer containerToPreload = containerList.get(index);
TASmodClient.virtual.preloadInput(containerToPreload.getKeyboard(), containerToPreload.getMouse(), containerToPreload.getCameraAngle());
+
+ TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.onPlaybackTick(index, containerToPreload);
}
public static void loadPlayer(NBTTagCompound compound) {
@@ -256,32 +266,47 @@ public static void loadPlayer(NBTTagCompound compound) {
Minecraft mc = Minecraft.getMinecraft();
EntityPlayerSP player = mc.player;
+ // Clear any accidental applied potion particles on the client
+ ((AccessorEntityLivingBase) player).clearPotionEffects();
+
+ /*
+ * TODO
+ * The following 20 lines are all one
+ * gross workaround for correctly applying the player motion
+ * to the client...
+ *
+ * The motion is applied
+ * to the player in a previous step and unfortunately
+ * player.readFromNBT(compound) overwrites the
+ * previously applied motion...
+ *
+ * So this workaround makes sure that the motion is not overwritten
+ * Fixing this, requires restructuring the steps for loadstating
+ * and since I plan to do this anyway at some point, I will
+ * leave this here and be done for today*/
+ double x = player.motionX;
+ double y = player.motionY;
+ double z = player.motionZ;
+
+ float rx = player.moveForward;
+ float ry = player.moveStrafing;
+ float rz = player.moveVertical;
+
+ boolean sprinting = player.isSprinting();
+ float jumpVector = player.jumpMovementFactor;
+
player.readFromNBT(compound);
- NBTTagCompound motion = compound.getCompoundTag("clientMotion");
- if (motion.hasNoTags()) {
- LOGGER.warn(LoggerMarkers.Savestate, "Could not load the motion from the savestate. Savestate seems to be created manually or by a different mod");
- } else {
- LOGGER.trace(LoggerMarkers.Savestate, "Loading client motion from NBT");
- double x = motion.getDouble("x");
- double y = motion.getDouble("y");
- double z = motion.getDouble("z");
- player.motionX = x;
- player.motionY = y;
- player.motionZ = z;
-
- float rx = motion.getFloat("RelativeX");
- float ry = motion.getFloat("RelativeY");
- float rz = motion.getFloat("RelativeZ");
- player.moveForward = rx;
- player.moveVertical = ry;
- player.moveStrafing = rz;
-
- boolean sprinting = motion.getBoolean("Sprinting");
- float jumpVector = motion.getFloat("JumpFactor");
- player.setSprinting(sprinting);
- player.jumpMovementFactor = jumpVector;
- }
+ player.motionX = x;
+ player.motionY = y;
+ player.motionZ = z;
+
+ player.moveForward = rx;
+ player.moveVertical = ry;
+ player.moveStrafing = rz;
+
+ player.setSprinting(sprinting);
+ player.jumpMovementFactor = jumpVector;
LOGGER.trace(LoggerMarkers.Savestate, "Setting client gamemode");
// #86
@@ -289,11 +314,12 @@ public static void loadPlayer(NBTTagCompound compound) {
GameType type = GameType.getByID(gamemode);
mc.playerController.setGameType(type);
- // #?? Player rotation does not change when loading a savestate
- // CameraInterpolationEvents.rotationPitch = player.rotationPitch;
- // CameraInterpolationEvents.rotationYaw = player.rotationYaw + 180f;
+ // Set the camera rotation to the player rotation
+ TASmodClient.virtual.CAMERA_ANGLE.setCamera(player.rotationPitch, player.rotationYaw);
+ SubtickDuck entityRenderer = (SubtickDuck) Minecraft.getMinecraft().entityRenderer;
+ entityRenderer.runUpdate(0);
- SavestateHandlerClient.keepPlayerInLoadedEntityList(player);
+ EventListenerRegistry.fireEvent(EventSavestate.EventClientLoadPlayer.class, player);
}
/**
@@ -312,7 +338,8 @@ public static void unloadAllClientChunks() {
ChunkProviderClient chunkProvider = mc.world.getChunkProvider();
((ChunkProviderDuck) chunkProvider).unloadAllChunks();
- Minecraft.getMinecraft().renderGlobal.loadRenderers();
+ mc.renderGlobal.loadRenderers();
+ ((WorldClientDuck) mc.world).clearEntityList();
}
@Override
@@ -321,8 +348,6 @@ public PacketID[] getAcceptedPacketIDs() {
//@formatter:off
TASmodPackets.SAVESTATE_SAVE,
TASmodPackets.SAVESTATE_LOAD,
- TASmodPackets.SAVESTATE_PLAYER,
- TASmodPackets.SAVESTATE_REQUEST_MOTION,
TASmodPackets.SAVESTATE_SCREEN,
TASmodPackets.SAVESTATE_UNLOAD_CHUNKS };
//@formatter:on
@@ -331,66 +356,41 @@ public PacketID[] getAcceptedPacketIDs() {
@Override
public void onClientPacket(PacketID id, ByteBuffer buf, String username) throws PacketNotImplementedException, WrongSideException, Exception {
TASmodPackets packet = (TASmodPackets) id;
- String name = null;
Minecraft mc = Minecraft.getMinecraft();
switch (packet) {
case SAVESTATE_SAVE:
- // Create client savestate
- name = TASmodBufferBuilder.readString(buf);
- try {
- SavestateHandlerClient.savestate(name);
- } catch (SavestateException e) {
- LOGGER.error(e.getMessage());
- } catch (IOException e) {
- e.printStackTrace();
- }
+ String savestateName = TASmodBufferBuilder.readString(buf);
+ Minecraft.getMinecraft().addScheduledTask(() -> {
+
+ // Create client savestate
+ try {
+ SavestateHandlerClient.savestate(savestateName);
+ } catch (SavestateException e) {
+ LOGGER.error(e.getMessage());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
break;
case SAVESTATE_LOAD:
// Load client savestate
- name = TASmodBufferBuilder.readString(buf);
- try {
- SavestateHandlerClient.loadstate(name);
- } catch (IOException e) {
- e.printStackTrace();
- }
- break;
- case SAVESTATE_PLAYER:
- NBTTagCompound compound;
- try {
- compound = TASmodBufferBuilder.readNBTTagCompound(buf);
- } catch (IOException e) {
- e.printStackTrace();
- return;
- }
- /*
- * Fair warning: Do NOT read the buffer inside an addScheduledTask. Read it
- * before that. The buffer will have the wrong limit, when the task is executed.
- * This is probably due to the buffers being reused.
- */
+ String loadstateName = TASmodBufferBuilder.readString(buf);
Minecraft.getMinecraft().addScheduledTask(() -> {
- SavestateHandlerClient.loadPlayer(compound);
- });
- break;
-
- case SAVESTATE_REQUEST_MOTION:
- EntityPlayerSP player = Minecraft.getMinecraft().player;
- if (player != null) {
- if (!(Minecraft.getMinecraft().currentScreen instanceof GuiSavestateSavingScreen)) {
- Minecraft.getMinecraft().displayGuiScreen(new GuiSavestateSavingScreen());
+ try {
+ SavestateHandlerClient.loadstate(loadstateName);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
}
- MotionData motionData = new MotionData(player.motionX, player.motionY, player.motionZ, player.moveForward, player.moveVertical, player.moveStrafing, player.isSprinting(), player.jumpMovementFactor);
- TASmodClient.client.send(new TASmodBufferBuilder(TASmodPackets.SAVESTATE_REQUEST_MOTION).writeMotionData(motionData));
- }
+ });
break;
case SAVESTATE_SCREEN:
- // Open/Close Savestate screen
- boolean open = TASmodBufferBuilder.readBoolean(buf);
- if (open) {
+ // Open Savestate screen
+ Minecraft.getMinecraft().addScheduledTask(() -> {
mc.displayGuiScreen(new GuiSavestateSavingScreen());
- } else {
- mc.displayGuiScreen(null);
- }
+ });
break;
case SAVESTATE_UNLOAD_CHUNKS:
@@ -402,7 +402,5 @@ public void onClientPacket(PacketID id, ByteBuffer buf, String username) throws
default:
throw new PacketNotImplementedException(packet, this.getClass(), Side.CLIENT);
}
-
}
-
}
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java
index 3809fb8a..fdb69c59 100644
--- a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java
@@ -1,24 +1,26 @@
package com.minecrafttas.tasmod.savestates;
import static com.minecrafttas.tasmod.TASmod.LOGGER;
+import static com.minecrafttas.tasmod.registries.TASmodPackets.CLEAR_SCREEN;
import java.io.File;
-import java.io.FileFilter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Stream;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.Logger;
-import com.google.common.collect.Maps;
import com.minecrafttas.mctcommon.events.EventListenerRegistry;
import com.minecrafttas.mctcommon.networking.Client.Side;
import com.minecrafttas.mctcommon.networking.exception.PacketNotImplementedException;
@@ -29,39 +31,28 @@
import com.minecrafttas.tasmod.events.EventSavestate;
import com.minecrafttas.tasmod.mixin.savestates.AccessorAnvilChunkLoader;
import com.minecrafttas.tasmod.mixin.savestates.AccessorChunkLoader;
-import com.minecrafttas.tasmod.mixin.savestates.MixinChunkProviderServer;
import com.minecrafttas.tasmod.networking.TASmodBufferBuilder;
import com.minecrafttas.tasmod.registries.TASmodPackets;
-import com.minecrafttas.tasmod.savestates.SavestateHandlerServer.PlayerHandler.MotionData;
import com.minecrafttas.tasmod.savestates.exceptions.LoadstateException;
import com.minecrafttas.tasmod.savestates.exceptions.SavestateDeleteException;
import com.minecrafttas.tasmod.savestates.exceptions.SavestateException;
import com.minecrafttas.tasmod.savestates.files.SavestateDataFile;
import com.minecrafttas.tasmod.savestates.files.SavestateDataFile.DataValues;
import com.minecrafttas.tasmod.savestates.files.SavestateTrackerFile;
-import com.minecrafttas.tasmod.util.Ducks.ChunkProviderDuck;
+import com.minecrafttas.tasmod.savestates.handlers.SavestatePlayerHandler;
+import com.minecrafttas.tasmod.savestates.handlers.SavestateWorldHandler;
import com.minecrafttas.tasmod.util.LoggerMarkers;
+import com.minecrafttas.tasmod.util.Scheduler.Task;
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-import net.minecraft.client.Minecraft;
-import net.minecraft.entity.Entity;
-import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.PlayerList;
-import net.minecraft.util.math.MathHelper;
+import net.minecraft.util.text.Style;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextFormatting;
-import net.minecraft.world.NextTickListEntry;
-import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
-import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.AnvilChunkLoader;
-import net.minecraft.world.gen.ChunkProviderServer;
-import net.minecraft.world.storage.SaveHandler;
-import net.minecraft.world.storage.WorldInfo;
/**
* Creates and loads savestates on both client and server without closing the
@@ -76,18 +67,28 @@
*/
public class SavestateHandlerServer implements ServerPacketHandler {
- private MinecraftServer server;
- private File savestateDirectory;
+ private final MinecraftServer server;
+ private Path savestateDirectory;
public SavestateState state = SavestateState.NONE;
+ public static enum SavestateState {
+ SAVING,
+ LOADING,
+ NONE
+ }
+
private final List indexList = new ArrayList<>();
private int latestIndex = 0;
private int currentIndex;
+ private final SavestatePlayerHandler playerHandler;
+ private final SavestateWorldHandler worldHandler;
+
+ public static final Path storageDir = Paths.get("tasmod/");
+
private final Logger logger;
- public static boolean wasLoading;
/**
* Creates a savestate handler on the specified server
@@ -98,6 +99,9 @@ public class SavestateHandlerServer implements ServerPacketHandler {
public SavestateHandlerServer(MinecraftServer server, Logger logger) {
this.server = server;
this.logger = logger;
+ this.playerHandler = new SavestatePlayerHandler(server);
+ this.worldHandler = new SavestateWorldHandler(server);
+
createSavestateDirectory();
refresh();
loadCurrentIndexFromFile();
@@ -150,7 +154,7 @@ public void saveState(int savestateIndex, boolean tickrate0, boolean changeIndex
try {
// Open GuiSavestateScreen
- TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.SAVESTATE_SCREEN).writeBoolean(true));
+ TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.SAVESTATE_SCREEN));
} catch (Exception e) {
e.printStackTrace();
}
@@ -164,12 +168,6 @@ public void saveState(int savestateIndex, boolean tickrate0, boolean changeIndex
// Enable tickrate 0
TASmod.tickratechanger.pauseGame(true);
- // Update the server variable
- server = TASmod.getServerInstance();
-
- // Get the motion from the client
- PlayerHandler.requestMotionFromClient();
-
// Save the world!
server.getPlayerList().saveAllPlayerData();
server.saveAllWorlds(false);
@@ -192,14 +190,14 @@ public void saveState(int savestateIndex, boolean tickrate0, boolean changeIndex
// Get the current and target directory for copying
String worldname = server.getFolderName();
- File currentfolder = new File(savestateDirectory, ".." + File.separator + worldname);
- File targetfolder = getSavestateFile(indexToSave);
+ Path currentfolder = savestateDirectory.resolve(".." + File.separator + worldname);
+ Path targetfolder = getSavestateFile(indexToSave);
- EventListenerRegistry.fireEvent(EventSavestate.EventServerSavestate.class, indexToSave, targetfolder, currentfolder);
+ EventListenerRegistry.fireEvent(EventSavestate.EventServerSavestate.class, server, indexToSave, targetfolder, currentfolder);
- if (targetfolder.exists()) {
+ if (Files.exists(targetfolder)) {
logger.warn(LoggerMarkers.Savestate, "WARNING! Overwriting the savestate with the index {}", indexToSave);
- FileUtils.deleteDirectory(targetfolder);
+ deleteFolder(targetfolder);
}
/*
@@ -230,19 +228,18 @@ public void saveState(int savestateIndex, boolean tickrate0, boolean changeIndex
saveSavestateDataFile(false);
// Copy the directory
- FileUtils.copyDirectory(currentfolder, targetfolder);
+ copyFolder(currentfolder, targetfolder);
// Incrementing info file
- SavestateTrackerFile tracker = new SavestateTrackerFile(new File(savestateDirectory, worldname + "-info.txt"));
- tracker.increaseSavestates();
- tracker.saveFile();
+ SavestateTrackerFile tracker = new SavestateTrackerFile(savestateDirectory.resolve(worldname + "-info.txt"));
+ tracker.increaseSaveStateCount();
// Send a notification that the savestate has been loaded
server.getPlayerList().sendMessage(new TextComponentString(TextFormatting.GREEN + "Savestate " + indexToSave + " saved"));
try {
// close GuiSavestateScreen
- TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.SAVESTATE_SCREEN).writeBoolean(false));
+ TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.CLEAR_SCREEN));
} catch (Exception e) {
e.printStackTrace();
}
@@ -315,14 +312,11 @@ public void loadState(int savestateIndex, boolean tickrate0, boolean changeIndex
// Enable tickrate 0
TASmod.tickratechanger.pauseGame(true);
- // Update the server instance
- server = TASmod.getServerInstance();
-
refresh();
int indexToLoad = savestateIndex < 0 ? currentIndex : savestateIndex;
- if (getSavestateFile(indexToLoad).exists()) {
+ if (Files.exists(getSavestateFile(indexToLoad))) {
// Updating current index
if (changeIndex) {
setCurrentIndex(indexToLoad);
@@ -335,10 +329,10 @@ public void loadState(int savestateIndex, boolean tickrate0, boolean changeIndex
// Get the current and target directory for copying
String worldname = server.getFolderName();
- File currentfolder = new File(savestateDirectory, ".." + File.separator + worldname);
- File targetfolder = getSavestateFile(indexToLoad);
+ Path currentfolder = savestateDirectory.resolve(".." + File.separator + worldname);
+ Path targetfolder = getSavestateFile(indexToLoad);
- EventListenerRegistry.fireEvent(EventSavestate.EventServerLoadstate.class, indexToLoad, targetfolder, currentfolder);
+ EventListenerRegistry.fireEvent(EventSavestate.EventServerLoadstate.class, server, indexToLoad, targetfolder, currentfolder);
/*
* Prevents loading an InputSavestate when loading index 0 (Index 0 is the
@@ -356,9 +350,7 @@ public void loadState(int savestateIndex, boolean tickrate0, boolean changeIndex
// Disabeling level saving for all worlds in case the auto save kicks in during
// world unload
- for (WorldServer world : server.worlds) {
- world.disableLevelSaving = true;
- }
+ worldHandler.disableLevelSaving();
try {
// unload chunks on client
@@ -368,46 +360,50 @@ public void loadState(int savestateIndex, boolean tickrate0, boolean changeIndex
}
// Unload chunks on the server
- ChunkHandler.disconnectPlayersFromChunkMap(server);
- ChunkHandler.unloadAllServerChunks(server);
- ChunkHandler.flushSaveHandler(server);
+ worldHandler.disconnectPlayersFromChunkMap();
+ worldHandler.unloadAllServerChunks();
+ worldHandler.flushSaveHandler();
// Delete and copy directories
- FileUtils.deleteDirectory(currentfolder);
- FileUtils.copyDirectory(targetfolder, currentfolder);
+ deleteFolder(currentfolder);
+ copyFolder(targetfolder, currentfolder);
// Loads savestate data from the file like name and ktrng seed if ktrng is loaded
loadSavestateDataFile();
+ playerHandler.clearScoreboard();
+
+ // Load the world from disk
+// server.loadAllWorlds(worldname, worldname, 0, WorldType.DEFAULT, "");
+ worldHandler.loadAllWorlds(worldname, worldname);
+
// Update the player and the client
- PlayerHandler.loadAndSendMotionToPlayer(server);
- // Update the session.lock file so minecraft behaves and saves the world
- ChunkHandler.updateSessionLock(server);
+ playerHandler.loadAndSendMotionToPlayer();
+
// Load the chunks and send them to the client
- ChunkHandler.addPlayersToChunkMap(server);
+ worldHandler.addPlayersToChunkMap();
- // Enable level saving again
- for (WorldServer world : server.worlds) {
- world.disableLevelSaving = false;
- }
+ // Reenable level saving
+ worldHandler.enableLevelSaving();
// Incrementing info file
- SavestateTrackerFile tracker = new SavestateTrackerFile(new File(savestateDirectory, worldname + "-info.txt"));
- tracker.increaseRerecords();
- tracker.saveFile();
+ SavestateTrackerFile tracker = new SavestateTrackerFile(savestateDirectory.resolve(worldname + "-info.txt"));
+ tracker.increaseLoadstateCount();
// Send a notification that the savestate has been loaded
server.getPlayerList().sendMessage(new TextComponentString(TextFormatting.GREEN + "Savestate " + indexToLoad + " loaded"));
// Add players to the chunk
server.getPlayerList().getPlayers().forEach(player -> {
- ChunkHandler.addPlayerToServerChunk(player);
+ worldHandler.addPlayerToServerChunk(player);
});
- WorldServer[] worlds = server.worlds;
+ worldHandler.sendChunksToClient();
- for (WorldServer world : worlds) {
- world.tick();
+ try {
+ TASmod.server.sendToAll(new TASmodBufferBuilder(CLEAR_SCREEN));
+ } catch (Exception e) {
+ LOGGER.catching(e);
}
if (!tickrate0) {
@@ -429,13 +425,21 @@ public void loadState(int savestateIndex, boolean tickrate0, boolean changeIndex
*/
private void createSavestateDirectory() {
logger.trace(LoggerMarkers.Savestate, "Creating savestate directory");
+
+ Path dataDirectory = server.getDataDirectory().toPath();
+
if (!server.isDedicatedServer()) {
- savestateDirectory = new File(server.getDataDirectory() + File.separator + "saves" + File.separator + "savestates" + File.separator);
+ savestateDirectory = dataDirectory.resolve("saves/savestates");
} else {
- savestateDirectory = new File(server.getDataDirectory() + File.separator + "savestates" + File.separator);
+ savestateDirectory = dataDirectory.resolve("savestates");
}
- if (!savestateDirectory.exists()) {
- savestateDirectory.mkdir();
+ if (!Files.exists(savestateDirectory)) {
+ try {
+ Files.createDirectory(savestateDirectory);
+ } catch (IOException e) {
+ logger.error("Could not create savestate directory");
+ logger.catching(e);
+ }
}
}
@@ -445,31 +449,42 @@ private void createSavestateDirectory() {
private void refresh() {
logger.trace(LoggerMarkers.Savestate, "Refreshing savestate list");
indexList.clear();
- File[] files = savestateDirectory.listFiles(new FileFilter() {
+ if (!Files.isDirectory(savestateDirectory)) {
+ logger.error("Savestate directory is not a directory! {}", savestateDirectory.toAbsolutePath().toString());
+ return;
+ }
- @Override
- public boolean accept(File pathname) {
- return pathname.getName().startsWith(server.getFolderName() + "-Savestate");
- }
+ Stream files = null;
+ try {
+ files = Files.list(savestateDirectory);
+ } catch (IOException e) {
+ logger.error("Can't refresh savestatelist");
+ logger.catching(e);
+ return;
+ }
+ Stream filteredfiles = files.filter(file -> file.getFileName().toString().startsWith(server.getFolderName() + "-Savestate"));
- });
- int index = 0;
- for (File file : files) {
+ filteredfiles.forEach(file -> {
+ int index = 0;
try {
Pattern patt = Pattern.compile("\\d+$");
- Matcher matcher = patt.matcher(file.getName());
+ Matcher matcher = patt.matcher(file.getFileName().toString());
if (matcher.find()) {
index = Integer.parseInt(matcher.group(0));
} else {
- logger.warn(String.format("Could not process the savestate %s", file.getName()));
- continue;
+ logger.warn(String.format("Could not process the savestate %s", file.getFileName()));
+ return;
}
} catch (NumberFormatException e) {
logger.warn(String.format("Could not process the savestate %s", e.getMessage()));
- continue;
+ return;
}
indexList.add(index);
- }
+ });
+
+ filteredfiles.close();
+ files.close();
+
Collections.sort(indexList);
if (!indexList.isEmpty()) {
latestIndex = indexList.get(indexList.size() - 1);
@@ -482,8 +497,8 @@ public boolean accept(File pathname) {
* @param index The index of the savestate file that we want to get
* @return The file of the savestate from the specified index
*/
- private File getSavestateFile(int index) {
- return new File(savestateDirectory, getSavestateName(index));
+ private Path getSavestateFile(int index) {
+ return savestateDirectory.resolve(getSavestateName(index));
}
/**
@@ -514,17 +529,19 @@ public void deleteSavestate(int index) throws SavestateDeleteException {
if (index == 0) {
throw new SavestateDeleteException("Cannot delete protected savestate 0");
}
- File toDelete = getSavestateFile(index);
- if (toDelete.exists()) {
- try {
- FileUtils.deleteDirectory(toDelete);
- } catch (IOException e) {
- e.printStackTrace();
- throw new SavestateDeleteException("Something went wrong while trying to delete the savestate " + index);
- }
+
+ Path toDelete = getSavestateFile(index);
+ if (Files.exists(getSavestateFile(index))) {
+// try {
+ deleteFolder(toDelete);
+// } catch (IOException e) {
+// e.printStackTrace();
+// throw new SavestateDeleteException("Something went wrong while trying to delete the savestate " + index);
+// }
} else {
throw new SavestateDeleteException(TextFormatting.YELLOW + "Savestate " + index + " doesn't exist, so it can't be deleted");
}
+
refresh();
if (!indexList.contains(currentIndex)) {
setCurrentIndex(latestIndex);
@@ -582,25 +599,31 @@ public String getIndexesAsString() {
*/
private void saveSavestateDataFile(boolean legacy) {
logger.trace(LoggerMarkers.Savestate, "Saving savestate data file");
- File tasmodDir = new File(savestateDirectory, "../" + server.getFolderName() + "/tasmod/");
- if (!tasmodDir.exists()) {
- tasmodDir.mkdir();
+ Path tasmodDir = savestateDirectory.resolve("../" + server.getFolderName() + "/tasmod/");
+ if (!Files.exists(tasmodDir)) {
+ try {
+ Files.createDirectories(tasmodDir);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
- File savestateDat = new File(tasmodDir, "savestateData.txt");
- if (savestateDat.exists()) {
- savestateDat.delete();
+ Path savestateDat = tasmodDir.resolve("savestateData.txt");
+ try {
+ Files.deleteIfExists(savestateDat);
+ } catch (IOException e) {
+ e.printStackTrace();
}
- SavestateDataFile file = new SavestateDataFile();
+ SavestateDataFile file = new SavestateDataFile(savestateDat);
file.set(DataValues.INDEX, Integer.toString(currentIndex));
- if (!legacy) {
- if (TASmod.ktrngHandler.isLoaded()) {
- file.set(DataValues.SEED, Long.toString(TASmod.ktrngHandler.getGlobalSeedServer()));
- }
- }
+ // if (!legacy) {
+ // if (TASmod.ktrngHandler.isLoaded()) {
+ // file.set(DataValues.SEED, Long.toString(TASmod.ktrngHandler.getGlobalSeedServer()));
+ // }
+ // }
file.save(savestateDat);
}
@@ -612,25 +635,25 @@ private void saveSavestateDataFile(boolean legacy) {
*/
private void loadSavestateDataFile() {
logger.trace(LoggerMarkers.Savestate, "Loading savestate data file");
- File tasmodDir = new File(savestateDirectory, "../" + server.getFolderName() + "/tasmod/");
- File savestateDat = new File(tasmodDir, "savestateData.txt");
+ Path tasmodDir = savestateDirectory.resolve("../" + server.getFolderName()).resolve(storageDir);
+ Path savestateDat = tasmodDir.resolve("savestateData.txt");
- if (!savestateDat.exists()) {
+ if (!Files.exists(savestateDat)) {
return;
}
- SavestateDataFile datafile = new SavestateDataFile();
+ SavestateDataFile datafile = new SavestateDataFile(savestateDirectory);
datafile.load(savestateDat);
- if (TASmod.ktrngHandler.isLoaded()) {
- String seedString = datafile.get(DataValues.SEED);
- if (seedString != null) {
- TASmod.ktrngHandler.sendGlobalSeedToServer(Long.parseLong(seedString));
- } else {
- logger.warn("KTRNG seed not loaded because it was not found in savestateData.txt!");
- }
- }
+ // if (TASmod.ktrngHandler.isLoaded()) {
+ // String seedString = datafile.get(DataValues.SEED);
+ // if (seedString != null) {
+ // TASmod.ktrngHandler.sendGlobalSeedToServer(Long.parseLong(seedString));
+ // } else {
+ // logger.warn("KTRNG seed not loaded because it was not found in savestateData.txt!");
+ // }
+ // }
}
/**
@@ -642,23 +665,31 @@ private void loadSavestateDataFile() {
public void loadCurrentIndexFromFile() {
logger.trace(LoggerMarkers.Savestate, "Loading current index from file");
int index = -1;
- File tasmodDir = new File(savestateDirectory, "../" + server.getFolderName() + "/tasmod/");
- if (!tasmodDir.exists()) {
- tasmodDir.mkdir();
+ Path tasmodDir = savestateDirectory.resolve("../" + server.getFolderName()).resolve(storageDir);
+ if (!Files.exists(tasmodDir)) {
+ try {
+ Files.createDirectory(tasmodDir);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
- File savestateDat = new File(tasmodDir, "savestate.data");
- if (savestateDat.exists()) {
+ Path savestateDat = tasmodDir.resolve("savestate.data");
+ if (Files.exists(savestateDat)) {
index = legacyIndexFile(savestateDat);
setCurrentIndex(index);
saveSavestateDataFile(true);
- savestateDat.delete();
+ try {
+ Files.delete(savestateDat);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
return;
}
- savestateDat = new File(tasmodDir, "savestateData.txt");
- if (savestateDat.exists()) {
- SavestateDataFile file = new SavestateDataFile();
+ savestateDat = tasmodDir.resolve("savestateData.txt");
+ if (Files.exists(savestateDat)) {
+ SavestateDataFile file = new SavestateDataFile(savestateDat);
file.load(savestateDat);
index = Integer.parseInt(file.get(DataValues.INDEX));
@@ -676,31 +707,28 @@ private void setCurrentIndex(int index) {
logger.debug(LoggerMarkers.Savestate, "Setting the savestate index to {}", currentIndex);
}
+ public SavestatePlayerHandler getPlayerHandler() {
+ return playerHandler;
+ }
+
public int getCurrentIndex() {
return currentIndex;
}
public void onLoadstateComplete() {
logger.trace(LoggerMarkers.Savestate, "Running loadstate complete event");
- PlayerList playerList = TASmod.getServerInstance().getPlayerList();
+ PlayerList playerList = server.getPlayerList();
for (EntityPlayerMP player : playerList.getPlayers()) {
NBTTagCompound nbttagcompound = playerList.readPlayerDataFromFile(player);
- PlayerHandler.reattachEntityToPlayer(nbttagcompound, player.getServerWorld(), player);
+ playerHandler.reattachEntityToPlayer(nbttagcompound, player.getServerWorld(), player);
}
- // Updating redstone component timers to the new world time (#136)
- ChunkHandler.updateWorldServerTickListEntries();
- }
-
- @Environment(EnvType.CLIENT)
- public static void playerLoadSavestateEventClient() {
- SavestateHandlerClient.addPlayerToClientChunk(Minecraft.getMinecraft().player);
}
- private int legacyIndexFile(File savestateDat) {
+ private int legacyIndexFile(Path savestateDat) {
int index = -1;
List lines = new ArrayList();
try {
- lines = FileUtils.readLines(savestateDat, StandardCharsets.UTF_8);
+ lines = FileUtils.readLines(savestateDat.toFile(), StandardCharsets.UTF_8);
} catch (IOException e) {
logger.warn("No savestate.data file found in current world folder, ignoring it");
}
@@ -718,21 +746,15 @@ private int legacyIndexFile(File savestateDat) {
return index;
}
- public static enum SavestateState {
- SAVING,
- LOADING,
- NONE
- }
-
@Override
public PacketID[] getAcceptedPacketIDs() {
return new TASmodPackets[] {
- TASmodPackets.SAVESTATE_SAVE,
- TASmodPackets.SAVESTATE_LOAD,
- TASmodPackets.SAVESTATE_PLAYER,
- TASmodPackets.SAVESTATE_REQUEST_MOTION,
- TASmodPackets.SAVESTATE_SCREEN,
+ //@formatter:off
+ TASmodPackets.SAVESTATE_SAVE,
+ TASmodPackets.SAVESTATE_LOAD,
+ TASmodPackets.SAVESTATE_SCREEN,
TASmodPackets.SAVESTATE_UNLOAD_CHUNKS
+ //@formatter:on
};
}
@@ -742,31 +764,39 @@ public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws
TASmodPackets packet = (TASmodPackets) id;
EntityPlayerMP player = TASmod.getServerInstance().getPlayerList().getPlayerByUsername(username);
- Integer index = null;
switch (packet) {
case SAVESTATE_SAVE:
- index = TASmodBufferBuilder.readInt(buf);
- try {
- TASmod.savestateHandlerServer.saveState(index, true);
- } catch (SavestateException e) {
- if (player != null)
- player.sendMessage(new TextComponentString(TextFormatting.RED + "Failed to create a savestate: " + e.getMessage()));
+ Integer index = TASmodBufferBuilder.readInt(buf);
- LOGGER.error(LoggerMarkers.Savestate, "Failed to create a savestate: " + e.getMessage());
- } catch (Exception e) {
- if (player != null)
- player.sendMessage(new TextComponentString(TextFormatting.RED + "Failed to create a savestate: " + e.getCause().toString()));
+ Task savestateTask = () -> {
+ try {
+ TASmod.savestateHandlerServer.saveState(index, true);
+ } catch (SavestateException e) {
+ if (player != null)
+ player.sendMessage(new TextComponentString(TextFormatting.RED + "Failed to create a savestate: " + e.getMessage()));
- LOGGER.error(e);
- } finally {
- TASmod.savestateHandlerServer.state = SavestateState.NONE;
- }
+ LOGGER.error(LoggerMarkers.Savestate, "Failed to create a savestate");
+ LOGGER.catching(e);
+ } catch (Exception e) {
+ if (player != null)
+ player.sendMessage(new TextComponentString(TextFormatting.RED + "Failed to create a savestate: " + e.getClass().getName().toString() + ": " + e.getMessage()));
+
+ LOGGER.catching(e);
+ } finally {
+ TASmod.savestateHandlerServer.state = SavestateState.NONE;
+ }
+ };
+
+ if (TASmod.tickratechanger.ticksPerSecond == 0)
+ TASmod.gameLoopSchedulerServer.add(savestateTask);
+ else
+ TASmod.tickSchedulerServer.add(savestateTask);
break;
case SAVESTATE_LOAD:
int indexing = TASmodBufferBuilder.readInt(buf);
- player.getServerWorld().addScheduledTask(() -> {
+ Task loadstateTask = () -> {
try {
TASmod.savestateHandlerServer.loadState(indexing, true);
} catch (LoadstateException e) {
@@ -776,20 +806,21 @@ public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws
LOGGER.error(LoggerMarkers.Savestate, "Failed to create a savestate: " + e.getMessage());
TASmod.savestateHandlerServer.state = SavestateState.NONE;
} catch (Exception e) {
- if (player != null)
- player.sendMessage(new TextComponentString(TextFormatting.RED + "Failed to load a savestate: " + e.getCause().toString()));
+ if (player != null) {
+ Throwable cause = e.getCause();
+ if (cause == null) {
+ cause = e;
+ }
+ player.sendMessage(new TextComponentString(String.format("Failed to load a savestate: %s", cause.getMessage())).setStyle(new Style().setColor(TextFormatting.RED)));
+ }
- LOGGER.error(e);
+ LOGGER.throwing(e);
TASmod.savestateHandlerServer.state = SavestateState.NONE;
}
- });
+ };
+ TASmod.gameLoopSchedulerServer.add(loadstateTask);
break;
- case SAVESTATE_REQUEST_MOTION:
- MotionData data = TASmodBufferBuilder.readMotionData(buf);
- PlayerHandler.getMotion().put(player, data);
- break;
- case SAVESTATE_PLAYER:
case SAVESTATE_SCREEN:
case SAVESTATE_UNLOAD_CHUNKS:
throw new WrongSideException(id, Side.SERVER);
@@ -798,316 +829,44 @@ public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws
}
}
- /**
- * Contains player related classes
- */
- public static class PlayerHandler {
-
- public static class MotionData {
- private double clientX;
- private double clientY;
- private double clientZ;
- private float clientrX;
- private float clientrY;
- private float clientrZ;
- private boolean sprinting;
- private float jumpMovementVector;
-
- public MotionData(double x, double y, double z, float rx, float ry, float rz, boolean sprinting, float jumpMovementVector) {
- clientX = x;
- clientY = y;
- clientZ = z;
- clientrX = rx;
- clientrY = ry;
- clientrZ = rz;
- this.sprinting = sprinting;
- this.jumpMovementVector = jumpMovementVector;
- }
-
- public double getClientX() {
- return clientX;
- }
-
- public double getClientY() {
- return clientY;
- }
-
- public double getClientZ() {
- return clientZ;
- }
-
- public float getClientrX() {
- return clientrX;
- }
-
- public float getClientrY() {
- return clientrY;
- }
-
- public float getClientrZ() {
- return clientrZ;
- }
-
- public boolean isSprinting() {
- return sprinting;
- }
-
- public float getJumpMovementVector() {
- return jumpMovementVector;
- }
- }
-
- /**
- * Tries to reattach the player to an entity, if the player was riding it it while savestating.
- *
- * Side: Server
- * @param nbttagcompound where the ridden entity is saved
- * @param worldserver that needs to spawn the entity
- * @param playerIn that needs to ride the entity
- */
- public static void reattachEntityToPlayer(NBTTagCompound nbttagcompound, World worldserver, Entity playerIn) {
- if (nbttagcompound != null && nbttagcompound.hasKey("RootVehicle", 10)) {
- NBTTagCompound nbttagcompound1 = nbttagcompound.getCompoundTag("RootVehicle");
- Entity entity1 = AnvilChunkLoader.readWorldEntity(nbttagcompound1.getCompoundTag("Entity"), worldserver, true);
-
- if (entity1 == null) {
- for (Entity entity : worldserver.loadedEntityList) {
- if (entity.getUniqueID().equals(nbttagcompound1.getUniqueId("Attach")))
- entity1 = entity;
- }
- }
-
- if (entity1 != null) {
- UUID uuid = nbttagcompound1.getUniqueId("Attach");
-
- if (entity1.getUniqueID().equals(uuid)) {
- playerIn.startRiding(entity1, true);
- } else {
- for (Entity entity : entity1.getRecursivePassengers()) {
- if (entity.getUniqueID().equals(uuid)) {
- playerIn.startRiding(entity, true);
- break;
- }
- }
- }
-
- if (!playerIn.isRiding()) {
- LOGGER.warn("Couldn't reattach entity to player");
- worldserver.removeEntityDangerously(entity1);
-
- for (Entity entity2 : entity1.getRecursivePassengers()) {
- worldserver.removeEntityDangerously(entity2);
- }
- }
- }
- } else {
- if (playerIn.isRiding()) {
- playerIn.dismountRidingEntity();
- }
- }
- }
-
- /**
- * Loads all worlds and players from the disk. Also sends the playerdata to the client in {@linkplain SavestateHandlerClient#onClientPacket(PacketID, ByteBuffer, String)}
- *
- * Side: Server
- */
- public static void loadAndSendMotionToPlayer(MinecraftServer server) {
-
- List players = server.getPlayerList().getPlayers();
- PlayerList list = server.getPlayerList();
-
- WorldServer[] worlds = server.worlds;
- for (WorldServer world : worlds) {
- WorldInfo info = world.getSaveHandler().loadWorldInfo();
- world.worldInfo = info;
- }
- for (EntityPlayerMP player : players) {
-
- int dimensionPrev = player.dimension;
-
- NBTTagCompound nbttagcompound = server.getPlayerList().readPlayerDataFromFile(player);
-
- int dimensionNow = 0;
- if (nbttagcompound.hasKey("Dimension")) {
- dimensionNow = nbttagcompound.getInteger("Dimension");
- }
-
- if (dimensionNow != dimensionPrev) {
- list.changePlayerDimension(player, dimensionNow);
- } else {
- player.getServerWorld().unloadedEntityList.remove(player);
- }
-
- player.readFromNBT(nbttagcompound);
-
- LOGGER.debug(LoggerMarkers.Savestate, "Sending motion to {}", player.getName());
-
+ public static void copyFolder(Path src, Path dest) {
+ try {
+ Files.walk(src).forEach(s -> {
try {
- TASmod.server.sendTo(player, new TASmodBufferBuilder(TASmodPackets.SAVESTATE_PLAYER).writeNBTTagCompound(nbttagcompound));
+ Path d = dest.resolve(src.relativize(s));
+ if (Files.isDirectory(s)) {
+ if (!Files.exists(d))
+ Files.createDirectory(d);
+ return;
+ }
+ Files.copy(s, d, StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
e.printStackTrace();
}
- }
- }
-
- public static void requestMotionFromClient() {
- LOGGER.trace(LoggerMarkers.Savestate, "Request motion from client");
- PlayerHandler.motion.clear();
- try {
- // request client motion
- TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.SAVESTATE_REQUEST_MOTION));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public static Map getMotion() {
- return PlayerHandler.motion;
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
}
-
- public static Map motion = Maps.newHashMap();
-
}
- /**
- * Contains static chunk actions, which can be triggered indiviadually for testing
- */
- public static class ChunkHandler {
-
- /**
- * Updates ticklist entries to the current world time, allowing them to not be stuck in a pressed state #136
- */
- public static void updateWorldServerTickListEntries() {
- LOGGER.trace(LoggerMarkers.Savestate, "Update server tick list entries");
- MinecraftServer server = TASmod.getServerInstance();
- for (WorldServer world : server.worlds) {
- for (NextTickListEntry nextticklistentry : world.pendingTickListEntriesHashSet) {
- nextticklistentry.setScheduledTime(world.getTotalWorldTime());
- }
- }
- }
-
- /**
- * Just like {@link SavestateHandlerClient#addPlayerToClientChunk(EntityPlayer)}, adds the player to the chunk on the server.
- * This prevents the player from being able to place block inside of him
- *
- * Side: Server
- */
- public static void addPlayerToServerChunk(EntityPlayerMP player) {
- LOGGER.trace(LoggerMarkers.Savestate, "Add player {} to server chunk", player.getName());
- int i = MathHelper.floor(player.posX / 16.0D);
- int j = MathHelper.floor(player.posZ / 16.0D);
- WorldServer world = player.getServerWorld();
- Chunk chunk = world.getChunkFromChunkCoords(i, j);
- for (int k = 0; k < chunk.getEntityLists().length; k++) {
- if (chunk.getEntityLists()[k].contains(player)) {
+ public static void deleteFolder(Path toDelete) {
+ try {
+ Files.walk(toDelete).forEach(s -> {
+ if (toDelete.equals(s))
return;
+ if (Files.isDirectory(s)) {
+ deleteFolder(s);
+ } else {
+ try {
+ Files.delete(s);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
- }
- chunk.addEntity(player);
- }
-
- /**
- * The session lock is minecrafts failsafe system when it comes to saving. It prevents writing to the world folder from 2 different locations
- *
- * That works by storing system time to a session.lock file, when the server started. The integrated server also saves the time when it started in a variable.
- *
- * Those two times are then compared every time minecraft tries to save and fails if the times are different.
- *
- * Since we never close the integrated server, but copy an "old" session.lock file with the savestate, the session.lock will always mismatch.
- * Thus we need to update the session lock once the loadstating is completed
- *
- * TLDR:
- * Updates the session lock to allow for vanilla saving again
- *
- * Side: Server
- */
- public static void updateSessionLock(MinecraftServer server) {
- LOGGER.trace(LoggerMarkers.Savestate, "Update the session lock");
- WorldServer[] worlds = server.worlds;
- for (WorldServer world : worlds) {
- ((SaveHandler) world.getSaveHandler()).setSessionLock();
- }
- }
-
- /**
- * Tells the save handler to save all changes to disk and remove all references to the region files, making them editable on disc
- *
- * Side: Server
- */
- public static void flushSaveHandler(MinecraftServer server) {
- LOGGER.trace(LoggerMarkers.Savestate, "Flush the save handler");
- //Vanilla
- WorldServer[] worlds = server.worlds;
- for (WorldServer world : worlds) {
- world.getSaveHandler().flush();
- }
- }
-
- /**
- * The player chunk map keeps track of which chunks need to be sent to the client.
- * This adds the player to the chunk map so the server knows it can send the information to the client
- *
- * Side: Server
- * @see #disconnectPlayersFromChunkMap(MinecraftServer)
- */
- public static void addPlayersToChunkMap(MinecraftServer server) {
- List players = server.getPlayerList().getPlayers();
- WorldServer[] worlds = server.worlds;
- for (EntityPlayerMP player : players) {
- LOGGER.trace(LoggerMarkers.Savestate, "Add player {} to the chunk map", player.getName());
- switch (player.dimension) {
- case -1:
- worlds[1].getPlayerChunkMap().addPlayer(player);
- worlds[1].getChunkProvider().provideChunk((int) player.posX >> 4, (int) player.posZ >> 4);
- break;
- case 0:
- worlds[0].getPlayerChunkMap().addPlayer(player);
- worlds[0].getChunkProvider().provideChunk((int) player.posX >> 4, (int) player.posZ >> 4);
- break;
- case 1:
- worlds[2].getPlayerChunkMap().addPlayer(player);
- worlds[2].getChunkProvider().provideChunk((int) player.posX >> 4, (int) player.posZ >> 4);
- break;
- }
- }
- }
-
- /**
- * The player chunk map keeps track of which chunks need to be sent to the client.
- * Removing the player stops the server from sending chunks to the client.
- *
- * Side: Server
- * @see #addPlayersToChunkMap(MinecraftServer)
- */
- public static void disconnectPlayersFromChunkMap(MinecraftServer server) {
- List players = server.getPlayerList().getPlayers();
- WorldServer[] worlds = server.worlds;
- for (WorldServer world : worlds) {
- for (EntityPlayerMP player : players) {
- LOGGER.trace(LoggerMarkers.Savestate, "Disconnect player {} from the chunk map", player.getName());
- world.getPlayerChunkMap().removePlayer(player);
- }
- }
- }
-
- /**
- * Unloads all chunks on the server
- *
- * Side: Server
- * @see MixinChunkProviderServer#unloadAllChunks()
- */
- public static void unloadAllServerChunks(MinecraftServer server) {
- LOGGER.trace(LoggerMarkers.Savestate, "Unloading all server chunks");
- WorldServer[] worlds = server.worlds;
-
- for (WorldServer world : worlds) {
- ChunkProviderServer chunkProvider = world.getChunkProvider();
-
- ((ChunkProviderDuck) chunkProvider).unloadAllChunks();
- }
-
+ });
+ Files.delete(toDelete);
+ } catch (Exception e) {
+ e.printStackTrace();
}
}
}
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/exceptions/LoadstateException.java b/src/main/java/com/minecrafttas/tasmod/savestates/exceptions/LoadstateException.java
index aa6419f6..febeeb26 100644
--- a/src/main/java/com/minecrafttas/tasmod/savestates/exceptions/LoadstateException.java
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/exceptions/LoadstateException.java
@@ -1,6 +1,6 @@
package com.minecrafttas.tasmod.savestates.exceptions;
-public class LoadstateException extends Exception{
+public class LoadstateException extends RuntimeException {
/**
*
*/
@@ -9,4 +9,8 @@ public class LoadstateException extends Exception{
public LoadstateException(String s) {
super(s);
}
+
+ public LoadstateException(Throwable t, String msg, Object... args) {
+ super(String.format(msg, args), t);
+ }
}
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/exceptions/SavestateException.java b/src/main/java/com/minecrafttas/tasmod/savestates/exceptions/SavestateException.java
index bfe1ff33..73d17e06 100644
--- a/src/main/java/com/minecrafttas/tasmod/savestates/exceptions/SavestateException.java
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/exceptions/SavestateException.java
@@ -1,12 +1,23 @@
package com.minecrafttas.tasmod.savestates.exceptions;
-public class SavestateException extends Exception{
- /**
- *
- */
- private static final long serialVersionUID = 3011404784481488693L;
-
- public SavestateException(String s) {
- super(s);
+public class SavestateException extends RuntimeException {
+
+ public SavestateException() {
+ }
+
+ public SavestateException(String msg) {
+ super(msg);
+ }
+
+ public SavestateException(String msg, Object... args) {
+ super(String.format(msg, args));
+ }
+
+ public SavestateException(Throwable t, String msg) {
+ super(msg, t);
+ }
+
+ public SavestateException(Throwable t, String msg, Object... args) {
+ super(String.format(msg, args), t);
}
}
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/files/SavestateDataFile.java b/src/main/java/com/minecrafttas/tasmod/savestates/files/SavestateDataFile.java
index c41b4f8f..7b6d6c6a 100644
--- a/src/main/java/com/minecrafttas/tasmod/savestates/files/SavestateDataFile.java
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/files/SavestateDataFile.java
@@ -1,65 +1,36 @@
package com.minecrafttas.tasmod.savestates.files;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-import java.util.InvalidPropertiesFormatException;
-import java.util.Properties;
+import java.nio.file.Path;
+
+import com.minecrafttas.mctcommon.file.AbstractDataFile;
+
+public class SavestateDataFile extends AbstractDataFile {
+
+ public SavestateDataFile(Path file) {
+ super(file, "savestatedata", "Data for this savestate from TASmod");
+ }
-public class SavestateDataFile {
-
public enum DataValues {
INDEX("currentIndex"),
NAME("savestateName"),
SEED("ktrngSeed");
-
-
+
private String configname;
-
+
private DataValues(String configname) {
- this.configname=configname;
+ this.configname = configname;
}
-
+
public String getConfigName() {
return configname;
}
}
-
- Properties properties = new Properties();
-
+
public void set(DataValues key, String val) {
properties.setProperty(key.getConfigName(), val);
}
-
+
public String get(DataValues key) {
return properties.getProperty(key.getConfigName());
}
-
- public void save(File file) {
- try {
- Writer writer = new FileWriter(file);
- properties.store(writer, "Data for this savestate from TASmod");
- writer.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- public void load(File file) {
- try {
- Reader reader = new FileReader(file);
- properties.load(reader);
- reader.close();
- } catch (InvalidPropertiesFormatException e) {
- e.printStackTrace();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
}
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/files/SavestateTrackerFile.java b/src/main/java/com/minecrafttas/tasmod/savestates/files/SavestateTrackerFile.java
index 95a64fdd..6bec0bb3 100644
--- a/src/main/java/com/minecrafttas/tasmod/savestates/files/SavestateTrackerFile.java
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/files/SavestateTrackerFile.java
@@ -1,65 +1,74 @@
package com.minecrafttas.tasmod.savestates.files;
-import java.io.File;
import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
+import java.nio.file.Files;
+import java.nio.file.Path;
-import org.apache.commons.io.FileUtils;
+import com.minecrafttas.mctcommon.file.AbstractDataFile;
+import com.minecrafttas.tasmod.TASmod;
/**
* Used to keep track of savestates and rerecordings
* @author Scribble
*
*/
-public class SavestateTrackerFile {
+public class SavestateTrackerFile extends AbstractDataFile {
- private final File saveLocation;
-
- private final String top="# This file was generated by TASmod/LoTAS and diplays info about the usage of savestates\n\n";
// This shouldn't matter... static is fine!
- public static int savestatecount;
- public static int loadstatecount;
- public SavestateTrackerFile(File saveLocation) throws IOException {
- this.saveLocation=saveLocation;
- if(!saveLocation.exists()) {
- savestatecount=0;
- loadstatecount=0;
+ public SavestateTrackerFile(Path saveLocation) throws IOException {
+ super(saveLocation, "savestate tracker", "This file was generated by TASmod/LoTAS and diplays info about the usage of savestates");
+
+ if (!Files.exists(saveLocation)) {
+ setSavestateCount(0);
+ setLoadstateCount(0);
+ save();
} else {
- loadFile();
+ load();
}
}
-
- private void loadFile() throws IOException {
- List lines=FileUtils.readLines(saveLocation, Charset.defaultCharset());
-
- lines.forEach(line->{
- if(line.startsWith("Total Savestates")) {
- savestatecount=Integer.parseInt(line.split("=")[1]);
- }else if(line.startsWith("Total Rerecords")){
- loadstatecount=Integer.parseInt(line.split("=")[1]);
- }
- });
+
+ public int getSavestateCount() {
+ load();
+ return loadCount("Total Savestates");
}
- public void increaseSavestates() {
- savestatecount++;
+ private void setSavestateCount(int savestatecount) {
+ setCount("Total Savestates", savestatecount);
}
-
- public void increaseRerecords() {
- loadstatecount++;
+
+ public void increaseSaveStateCount() {
+ setSavestateCount(getSavestateCount() + 1);
+ save();
}
-
- public void saveFile() throws IOException {
- List lines= new ArrayList();
-
- lines.add(top);
-
- lines.add("Total Savestates="+savestatecount+"\nTotal Rerecords="+loadstatecount);
-
- FileUtils.writeLines(saveLocation, lines);
+
+ public int getLoadstateCount() {
+ load();
+ return loadCount("Total Loadstates");
+ }
+
+ public void setLoadstateCount(int loadstatecount) {
+ setCount("Total Loadstates", loadstatecount);
+ save();
+ }
+
+ public void increaseLoadstateCount() {
+ setLoadstateCount(getLoadstateCount() + 1);
+ }
+
+ private int loadCount(String key) {
+ String value = properties.getProperty(key, "0");
+ int count = 0;
+ try {
+ count = Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ TASmod.LOGGER.error("The {} could not be read in {}. The value {} is not a number", key, name, e.getMessage());
+ }
+ return count;
+ }
+
+ private void setCount(String key, int count) {
+ properties.setProperty(key, Integer.toString(count));
}
}
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandler.java b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandler.java
new file mode 100644
index 00000000..cdab03e2
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandler.java
@@ -0,0 +1,229 @@
+package com.minecrafttas.tasmod.savestates.handlers;
+
+import static com.minecrafttas.tasmod.TASmod.LOGGER;
+import static com.minecrafttas.tasmod.registries.TASmodPackets.SAVESTATE_PLAYER;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.UUID;
+
+import com.minecrafttas.mctcommon.networking.Client.Side;
+import com.minecrafttas.mctcommon.networking.exception.PacketNotImplementedException;
+import com.minecrafttas.mctcommon.networking.exception.WrongSideException;
+import com.minecrafttas.mctcommon.networking.interfaces.ClientPacketHandler;
+import com.minecrafttas.mctcommon.networking.interfaces.PacketID;
+import com.minecrafttas.mctcommon.networking.interfaces.ServerPacketHandler;
+import com.minecrafttas.tasmod.TASmod;
+import com.minecrafttas.tasmod.networking.TASmodBufferBuilder;
+import com.minecrafttas.tasmod.registries.TASmodPackets;
+import com.minecrafttas.tasmod.savestates.SavestateHandlerClient;
+import com.minecrafttas.tasmod.util.LoggerMarkers;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.Minecraft;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.network.play.server.SPacketRespawn;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.management.PlayerList;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldServer;
+import net.minecraft.world.chunk.storage.AnvilChunkLoader;
+
+/**
+ * Handles player related savestating methods
+ */
+public class SavestatePlayerHandler implements ClientPacketHandler, ServerPacketHandler {
+
+ private final MinecraftServer server;
+
+ public SavestatePlayerHandler(MinecraftServer server) {
+ this.server = server;
+ }
+
+ /**
+ * Tries to reattach the player to an entity, if the player was riding it it while savestating.
+ *
+ * Side: Server
+ * @param nbttagcompound where the ridden entity is saved
+ * @param worldserver that needs to spawn the entity
+ * @param playerIn that needs to ride the entity
+ */
+ public void reattachEntityToPlayer(NBTTagCompound nbttagcompound, World worldserver, Entity playerIn) {
+ if (nbttagcompound != null && nbttagcompound.hasKey("RootVehicle", 10)) {
+ NBTTagCompound nbttagcompound1 = nbttagcompound.getCompoundTag("RootVehicle");
+ Entity entity1 = AnvilChunkLoader.readWorldEntity(nbttagcompound1.getCompoundTag("Entity"), worldserver, true);
+
+ if (entity1 == null) {
+ for (Entity entity : worldserver.loadedEntityList) {
+ if (entity.getUniqueID().equals(nbttagcompound1.getUniqueId("Attach")))
+ entity1 = entity;
+ }
+ }
+
+ if (entity1 != null) {
+ UUID uuid = nbttagcompound1.getUniqueId("Attach");
+
+ if (entity1.getUniqueID().equals(uuid)) {
+ playerIn.startRiding(entity1, true);
+ } else {
+ for (Entity entity : entity1.getRecursivePassengers()) {
+ if (entity.getUniqueID().equals(uuid)) {
+ playerIn.startRiding(entity, true);
+ break;
+ }
+ }
+ }
+
+ if (!playerIn.isRiding()) {
+ LOGGER.warn("Couldn't reattach entity to player");
+ worldserver.removeEntityDangerously(entity1);
+
+ for (Entity entity2 : entity1.getRecursivePassengers()) {
+ worldserver.removeEntityDangerously(entity2);
+ }
+ }
+ }
+ } else {
+ if (playerIn.isRiding()) {
+ playerIn.dismountRidingEntity();
+ }
+ }
+ }
+
+ /**
+ * Loads all worlds and players from the disk. Also sends the playerdata to the client in {@linkplain SavestateHandlerClient#onClientPacket(PacketID, ByteBuffer, String)}
+ *
+ * Side: Server
+ */
+ public void loadAndSendMotionToPlayer() {
+
+ PlayerList list = server.getPlayerList();
+ List players = list.getPlayers();
+
+ for (EntityPlayerMP player : players) {
+
+ int dimensionFrom = player.dimension;
+
+ player.setWorld(server.getWorld(dimensionFrom));
+
+ NBTTagCompound nbttagcompound = server.getPlayerList().readPlayerDataFromFile(player);
+
+ int dimensionTo = 0;
+ if (nbttagcompound.hasKey("Dimension")) {
+ dimensionTo = nbttagcompound.getInteger("Dimension");
+ }
+
+ if (dimensionTo != dimensionFrom) {
+ changeDimensionDangerously(player, dimensionTo);
+ } else {
+ player.getServerWorld().unloadedEntityList.remove(player);
+ }
+
+ player.clearActivePotions();
+
+ player.readFromNBT(nbttagcompound);
+ player.setWorld(this.server.getWorld(player.dimension));
+ player.interactionManager.setWorld((WorldServer) player.world);
+
+ LOGGER.debug(LoggerMarkers.Savestate, "Sending motion to {}", player.getName());
+
+ try {
+ TASmod.server.sendTo(player, new TASmodBufferBuilder(TASmodPackets.SAVESTATE_PLAYER).writeNBTTagCompound(nbttagcompound));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Changes the dimension of the player without loading chunks.
+ *
+ * @param player The player that should change the dimension
+ * @param dimensionTo The dimension where the player should be put
+ */
+ public void changeDimensionDangerously(EntityPlayerMP player, int dimensionTo) {
+ int dimensionFrom = player.dimension;
+ WorldServer worldServerFrom = this.server.getWorld(dimensionFrom);
+// WorldServer worldServerTo = this.server.getWorld(dimensionTo);
+
+ //@formatter:off
+ player.connection
+ .sendPacket(
+ new SPacketRespawn(
+ dimensionTo,
+ player.world.getDifficulty(),
+ player.world.getWorldInfo().getTerrainType(),
+ player.interactionManager.getGameType()
+ )
+ );
+ //@formatter:on
+ worldServerFrom.removeEntityDangerously(player);
+ player.isDead = false;
+// worldServerTo.spawnEntity(player);
+// worldServerTo.updateEntityWithOptionalForce(player, false);
+// player.setWorld(worldServerTo);
+// player.interactionManager.setWorld(worldServerTo);
+ }
+
+ public void clearScoreboard() {
+ try {
+ TASmod.server.sendToAll(new TASmodBufferBuilder(TASmodPackets.SAVESTATE_CLEAR_SCOREBOARD));
+ } catch (Exception e) {
+ LOGGER.catching(e);
+ }
+ }
+
+ @Override
+ public PacketID[] getAcceptedPacketIDs() {
+ return new PacketID[] {
+ //@formatter:off
+ SAVESTATE_PLAYER
+ //@formatter:on
+ };
+ }
+
+ @Override
+ public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws PacketNotImplementedException, WrongSideException, Exception {
+ TASmodPackets packet = (TASmodPackets) id;
+
+ switch (packet) {
+ case SAVESTATE_PLAYER:
+ throw new WrongSideException(packet, Side.SERVER);
+ default:
+ break;
+ }
+ }
+
+ @Environment(EnvType.CLIENT)
+ @Override
+ public void onClientPacket(PacketID id, ByteBuffer buf, String username) throws PacketNotImplementedException, WrongSideException, Exception {
+ TASmodPackets packet = (TASmodPackets) id;
+
+ switch (packet) {
+ case SAVESTATE_PLAYER:
+ NBTTagCompound compound;
+ try {
+ compound = TASmodBufferBuilder.readNBTTagCompound(buf);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return;
+ }
+ /*
+ * Fair warning: Do NOT read the buffer inside an addScheduledTask. Read it
+ * before that. The buffer will have the wrong limit, when the task is executed.
+ * This is probably due to the buffers being reused.
+ */
+ Minecraft.getMinecraft().addScheduledTask(() -> {
+ SavestateHandlerClient.loadPlayer(compound);
+ });
+ break;
+
+ default:
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateWorldHandler.java b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateWorldHandler.java
new file mode 100644
index 00000000..c8de811a
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateWorldHandler.java
@@ -0,0 +1,249 @@
+package com.minecrafttas.tasmod.savestates.handlers;
+
+import static com.minecrafttas.tasmod.TASmod.LOGGER;
+
+import java.util.List;
+
+import com.minecrafttas.tasmod.mixin.savestates.AccessorPlayerChunkMap;
+import com.minecrafttas.tasmod.mixin.savestates.MixinChunkProviderServer;
+import com.minecrafttas.tasmod.savestates.SavestateHandlerClient;
+import com.minecrafttas.tasmod.util.Ducks.ChunkProviderDuck;
+import com.minecrafttas.tasmod.util.Ducks.WorldServerDuck;
+import com.minecrafttas.tasmod.util.LoggerMarkers;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.management.PlayerChunkMap;
+import net.minecraft.util.math.MathHelper;
+import net.minecraft.world.ServerWorldEventHandler;
+import net.minecraft.world.WorldServer;
+import net.minecraft.world.WorldServerMulti;
+import net.minecraft.world.chunk.Chunk;
+import net.minecraft.world.gen.ChunkProviderServer;
+import net.minecraft.world.storage.ISaveHandler;
+import net.minecraft.world.storage.SaveHandler;
+import net.minecraft.world.storage.WorldInfo;
+
+/**
+ * Contains static chunk actions, which can be triggered individually for testing
+ */
+public class SavestateWorldHandler {
+
+ private final MinecraftServer server;
+
+ public SavestateWorldHandler(MinecraftServer server) {
+ this.server = server;
+ }
+
+ /**
+ * Disables automatic saving across all worlds
+ */
+ public void disableLevelSaving() {
+ for (WorldServer world : server.worlds) {
+ world.disableLevelSaving = true;
+ }
+ }
+
+ /**
+ * Enables automatic saving across all worlds
+ */
+ public void enableLevelSaving() {
+ for (WorldServer world : server.worlds) {
+ world.disableLevelSaving = false;
+ }
+ }
+
+ /**
+ * Just like {@link SavestateHandlerClient#addPlayerToClientChunk(EntityPlayer)}, adds the player to the chunk on the server.
+ * This prevents the player from being able to place block inside of him
+ *
+ * Side: Server
+ */
+ public void addPlayerToServerChunk(EntityPlayerMP player) {
+ LOGGER.trace(LoggerMarkers.Savestate, "Add player {} to server chunk", player.getName());
+ int i = MathHelper.floor(player.posX / 16.0D);
+ int j = MathHelper.floor(player.posZ / 16.0D);
+ WorldServer world = player.getServerWorld();
+ Chunk chunk = world.getChunkFromChunkCoords(i, j);
+ for (int k = 0; k < chunk.getEntityLists().length; k++) {
+ if (chunk.getEntityLists()[k].contains(player)) {
+ return;
+ }
+ }
+ chunk.addEntity(player);
+ }
+
+ /**
+ *
The session lock is Minecraft's failsafe system when it comes to saving. It prevents writing to the world folder from 2 different locations
+ * This works by storing the {@link SaveHandler#initializationTime initializationTime} of the server to a session.lock file ({@link SaveHandler#setSessionLock()}), when the server started.
+ *
+ * When the server writes to the world folder, the current {@link SaveHandler#initializationTime initializationTime} and the session.lock time are compared ({@link SaveHandler#checkSessionLock()}).
+ * If the times match, the savehandler is allowed to continue writing to the world folder.,
+ *
+ * Since we never close the server during a loadstate and a different session.lock from an older initialization is being copied into the folder,
+ * the 2 values will always mismatch after a loadstate.
+ * Thus we need to update the session.lock file once the loadstating is completed.
+ *
+ * Side: Server
+ */
+ public void updateSessionLock() {
+ LOGGER.trace(LoggerMarkers.Savestate, "Update the session lock");
+ WorldServer[] worlds = server.worlds;
+ for (WorldServer world : worlds) {
+ ((SaveHandler) world.getSaveHandler()).setSessionLock();
+ }
+ }
+
+ /**
+ * Tells the save handler to save all changes to disk and remove all references to the region files, making them editable on disc
+ *
+ * Side: Server
+ */
+ public void flushSaveHandler() {
+ LOGGER.trace(LoggerMarkers.Savestate, "Flush the save handler");
+ //Vanilla
+ WorldServer[] worlds = server.worlds;
+ for (WorldServer world : worlds) {
+ world.getSaveHandler().flush();
+ }
+ }
+
+ /**
+ * The player chunk map keeps track of which chunks need to be sent to the client.
+ * This adds the player to the chunk map so the server knows it can send the information to the client
+ *
+ * Side: Server
+ * @see #disconnectPlayersFromChunkMap(MinecraftServer)
+ */
+ public void addPlayersToChunkMap() {
+ List players = server.getPlayerList().getPlayers();
+ WorldServer[] worlds = server.worlds;
+ for (EntityPlayerMP player : players) {
+ LOGGER.trace(LoggerMarkers.Savestate, "Add player {} to the chunk map", player.getName());
+ switch (player.dimension) {
+ case -1:
+ addPlayerToChunkMap(worlds[1], player);
+ break;
+ case 0:
+ addPlayerToChunkMap(worlds[0], player);
+ break;
+ case 1:
+ addPlayerToChunkMap(worlds[2], player);
+ break;
+ default:
+ if (worlds.length > player.dimension)
+ addPlayerToChunkMap(worlds[player.dimension + 1], player);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Adds a single player to a chunkMap
+ * @param world
+ * @param player
+ */
+ private void addPlayerToChunkMap(WorldServer world, EntityPlayerMP player) {
+ int playerChunkPosX = (int) player.posX >> 4;
+ int playerChunkPosY = (int) player.posZ >> 4;
+ PlayerChunkMap playerChunkMap = world.getPlayerChunkMap();
+
+ List players = ((AccessorPlayerChunkMap) playerChunkMap).getPlayers();
+
+ if (players.contains(player)) {
+ LOGGER.debug(LoggerMarkers.Savestate, "Not adding player {} to chunkmap, player already exists", player.getName());
+ } else {
+ playerChunkMap.addPlayer(player);
+ }
+ world.getChunkProvider().provideChunk(playerChunkPosX, playerChunkPosY);
+
+ world.spawnEntity(player);
+ }
+
+ /**
+ * The player chunk map keeps track of which chunks need to be sent to the client.
+ * Removing the player stops the server from sending chunks to the client.
+ *
+ * Side: Server
+ * @see #addPlayersToChunkMap(MinecraftServer)
+ */
+ public void disconnectPlayersFromChunkMap() {
+ List players = server.getPlayerList().getPlayers();
+ WorldServer[] worlds = server.worlds;
+ for (WorldServer world : worlds) {
+ for (EntityPlayerMP player : players) {
+ LOGGER.trace(LoggerMarkers.Savestate, "Disconnect player {} from the chunk map", player.getName());
+ world.getPlayerChunkMap().removePlayer(player);
+ }
+ }
+ }
+
+ /**
+ * Unloads all chunks on the server
+ *
+ * Side: Server
+ * @see MixinChunkProviderServer#unloadAllChunks()
+ */
+ public void unloadAllServerChunks() {
+ LOGGER.trace(LoggerMarkers.Savestate, "Unloading all server chunks");
+ WorldServer[] worlds = server.worlds;
+
+ for (WorldServer world : worlds) {
+ ChunkProviderServer chunkProvider = world.getChunkProvider();
+
+ ((ChunkProviderDuck) chunkProvider).unloadAllChunks();
+ }
+ }
+
+ /**
+ * Tick and send chunks to the client
+ */
+ public void sendChunksToClient() {
+ WorldServer[] worlds = server.worlds;
+
+ for (WorldServer world : worlds) {
+ WorldServerDuck worldTick = (WorldServerDuck) world;
+ worldTick.sendChunksToClient();
+ }
+ }
+
+ public void loadAllWorlds(String string, String string2) {
+ server.convertMapIfNeeded(string);
+ server.worlds = new WorldServer[3];
+ server.timeOfLastDimensionTick = new long[server.worlds.length][100];
+ ISaveHandler iSaveHandler = server.getActiveAnvilConverter().getSaveLoader(string, true);
+ server.setResourcePackFromWorld(server.getFolderName(), iSaveHandler);
+ WorldInfo worldInfo = iSaveHandler.loadWorldInfo();
+ if (worldInfo == null) {
+// worldInfo = new WorldInfo(server.worldSettings, string2);
+ } else {
+ worldInfo.setWorldName(string2);
+ }
+
+ for (int i = 0; i < server.worlds.length; i++) {
+ int j = 0;
+ if (i == 1) {
+ j = -1;
+ }
+
+ if (i == 2) {
+ j = 1;
+ }
+
+ if (i == 0) {
+ server.worlds[i] = (WorldServer) new WorldServer(server, iSaveHandler, worldInfo, j, server.profiler).init();
+ } else {
+ server.worlds[i] = (WorldServer) new WorldServerMulti(server, iSaveHandler, j, server.worlds[0], server.profiler).init();
+ }
+
+ server.worlds[i].addEventListener(new ServerWorldEventHandler(server, server.worlds[i]));
+ }
+
+ server.getPlayerList().setPlayerManager(server.worlds);
+ if (server.worlds[0].getWorldInfo().getDifficulty() == null) {
+ server.setDifficultyForAllWorlds(Minecraft.getMinecraft().gameSettings.difficulty);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/AbstractExtendStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/AbstractExtendStorage.java
new file mode 100644
index 00000000..d67ebc2b
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/AbstractExtendStorage.java
@@ -0,0 +1,11 @@
+package com.minecrafttas.tasmod.savestates.storage;
+
+import org.apache.logging.log4j.Logger;
+
+import com.minecrafttas.tasmod.TASmod;
+import com.minecrafttas.tasmod.events.EventSavestate.EventServerLoadstate;
+import com.minecrafttas.tasmod.events.EventSavestate.EventServerSavestate;
+
+public abstract class AbstractExtendStorage implements EventServerSavestate, EventServerLoadstate {
+ protected Logger logger = TASmod.LOGGER;
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateMotionStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateMotionStorage.java
new file mode 100644
index 00000000..c79ec326
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateMotionStorage.java
@@ -0,0 +1,287 @@
+package com.minecrafttas.tasmod.savestates.storage;
+
+import static com.minecrafttas.tasmod.TASmod.LOGGER;
+import static com.minecrafttas.tasmod.registries.TASmodPackets.SAVESTATE_REQUEST_MOTION;
+import static com.minecrafttas.tasmod.registries.TASmodPackets.SAVESTATE_SET_MOTION;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.minecrafttas.mctcommon.networking.Client.Side;
+import com.minecrafttas.mctcommon.networking.exception.PacketNotImplementedException;
+import com.minecrafttas.mctcommon.networking.exception.WrongSideException;
+import com.minecrafttas.mctcommon.networking.interfaces.ClientPacketHandler;
+import com.minecrafttas.mctcommon.networking.interfaces.PacketID;
+import com.minecrafttas.mctcommon.networking.interfaces.ServerPacketHandler;
+import com.minecrafttas.tasmod.TASmod;
+import com.minecrafttas.tasmod.TASmodClient;
+import com.minecrafttas.tasmod.networking.TASmodBufferBuilder;
+import com.minecrafttas.tasmod.registries.TASmodPackets;
+import com.minecrafttas.tasmod.savestates.SavestateHandlerServer;
+import com.minecrafttas.tasmod.savestates.exceptions.LoadstateException;
+import com.minecrafttas.tasmod.savestates.exceptions.SavestateException;
+import com.minecrafttas.tasmod.savestates.gui.GuiSavestateSavingScreen;
+import com.minecrafttas.tasmod.util.LoggerMarkers;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.management.PlayerList;
+
+public class SavestateMotionStorage extends AbstractExtendStorage implements ClientPacketHandler, ServerPacketHandler {
+
+ private static final Path fileName = Paths.get("clientMotion.json");
+ private final Gson json;
+
+ private final Map> futures;
+
+ public SavestateMotionStorage() {
+ json = new GsonBuilder().setPrettyPrinting().create();
+ futures = new HashMap<>();
+ }
+
+ @Override
+ public void onServerSavestate(MinecraftServer server, int index, Path target, Path current) {
+ LOGGER.trace(LoggerMarkers.Savestate, "Request motion from client");
+
+ this.futures.clear();
+
+ List playerList = server.getPlayerList().getPlayers();
+ playerList.forEach(player -> {
+ futures.put(player, new CompletableFuture<>());
+ });
+
+ try {
+ // request client motion
+ TASmod.server.sendToAll(new TASmodBufferBuilder(SAVESTATE_REQUEST_MOTION));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ JsonObject playerJsonObject = new JsonObject();
+
+ futures.forEach((player, future) -> {
+ try {
+ MotionData data = future.get(5L, TimeUnit.SECONDS);
+
+ String uuid = player.getUniqueID().toString();
+ if (player.getName().equals(server.getServerOwner())) {
+ uuid = "singleplayer";
+ }
+ playerJsonObject.add(uuid, json.toJsonTree(data));
+
+ } catch (TimeoutException e) {
+ throw new SavestateException(e, "Writing client motion for %s timed out!", player.getName());
+ } catch (ExecutionException | InterruptedException e) {
+ throw new SavestateException(e, "Writing client motion for %s", player.getName());
+ }
+ });
+
+ saveJson(current, playerJsonObject);
+ }
+
+ private void saveJson(Path current, JsonObject data) {
+ Path saveFile = current.resolve(SavestateHandlerServer.storageDir).resolve(fileName);
+
+ String out = json.toJson(data);
+
+ try {
+ Files.write(saveFile, out.getBytes());
+ } catch (IOException e) {
+ throw new SavestateException(e, "Could not write to the file system");
+ }
+ }
+
+ @Override
+ public void onServerLoadstate(MinecraftServer server, int index, Path target, Path current) {
+ JsonObject playerJsonObject = loadMotionData(target);
+ PlayerList list = server.getPlayerList();
+
+ for (Entry motionDataJsonElement : playerJsonObject.entrySet()) {
+ String playerUUID = motionDataJsonElement.getKey();
+ MotionData motionData = json.fromJson(motionDataJsonElement.getValue(), MotionData.class);
+
+ EntityPlayerMP player;
+ if (playerUUID.equals("singleplayer")) {
+ String ownerName = server.getServerOwner();
+ if (ownerName == null) {
+ continue;
+ }
+ player = list.getPlayerByUsername(ownerName);
+ } else {
+ player = list.getPlayerByUUID(UUID.fromString(playerUUID));
+ }
+
+ if (player == null) {
+ continue;
+ }
+
+ try {
+ TASmod.server.sendTo(player, new TASmodBufferBuilder(SAVESTATE_SET_MOTION).writeMotionData(motionData));
+ } catch (Exception e) {
+ logger.catching(e);
+ }
+ }
+ }
+
+ private JsonObject loadMotionData(Path target) {
+ Path saveFile = target.resolve(SavestateHandlerServer.storageDir).resolve(fileName);
+ String in;
+ try {
+ in = new String(Files.readAllBytes(saveFile));
+ } catch (IOException e) {
+ throw new LoadstateException(e, "Could not read from the file system");
+ }
+ return json.fromJson(in, JsonObject.class);
+ }
+
+ @Override
+ public PacketID[] getAcceptedPacketIDs() {
+ return new PacketID[] { SAVESTATE_REQUEST_MOTION, SAVESTATE_SET_MOTION };
+ }
+
+ @Environment(EnvType.CLIENT)
+ @Override
+ public void onClientPacket(PacketID id, ByteBuffer buf, String username) throws PacketNotImplementedException, WrongSideException, Exception {
+ TASmodPackets packet = (TASmodPackets) id;
+ Minecraft mc = Minecraft.getMinecraft();
+ EntityPlayerSP player = mc.player;
+
+ switch (packet) {
+ case SAVESTATE_REQUEST_MOTION:
+
+ if (player != null) {
+ if (!(mc.currentScreen instanceof GuiSavestateSavingScreen)) {
+ mc.displayGuiScreen(new GuiSavestateSavingScreen());
+ }
+ //@formatter:off
+ MotionData motionData = new MotionData(
+ player.motionX,
+ player.motionY,
+ player.motionZ,
+ player.moveForward,
+ player.moveVertical,
+ player.moveStrafing,
+ player.isSprinting(),
+ player.jumpMovementFactor
+ );
+ //@formatter:on
+ TASmodClient.client.send(new TASmodBufferBuilder(TASmodPackets.SAVESTATE_REQUEST_MOTION).writeMotionData(motionData));
+ }
+ break;
+ case SAVESTATE_SET_MOTION:
+ LOGGER.trace(LoggerMarkers.Savestate, "Loading client motion");
+
+ MotionData data = TASmodBufferBuilder.readMotionData(buf);
+ player.motionX = data.motionX;
+ player.motionY = data.motionY;
+ player.motionZ = data.motionZ;
+
+ player.moveForward = data.deltaX;
+ player.moveVertical = data.deltaY;
+ player.moveStrafing = data.deltaZ;
+
+ player.setSprinting(data.sprinting);
+ player.jumpMovementFactor = data.jumpMovementFactor;
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws PacketNotImplementedException, WrongSideException, Exception {
+ TASmodPackets packet = (TASmodPackets) id;
+ EntityPlayerMP player = TASmod.getServerInstance().getPlayerList().getPlayerByUsername(username);
+
+ switch (packet) {
+ case SAVESTATE_REQUEST_MOTION:
+ MotionData data = TASmodBufferBuilder.readMotionData(buf);
+ CompletableFuture future = this.futures.get(player);
+ future.complete(data);
+ break;
+ case SAVESTATE_SET_MOTION:
+ throw new WrongSideException(packet, Side.SERVER);
+ default:
+ break;
+ }
+ }
+
+ public static class MotionData {
+
+ private double motionX;
+ private double motionY;
+ private double motionZ;
+ private float deltaX;
+ private float deltaY;
+ private float deltaZ;
+ private boolean sprinting;
+ private float jumpMovementFactor;
+
+ public MotionData(double x, double y, double z, float rx, float ry, float rz, boolean sprinting, float jumpMovementVector) {
+ motionX = x;
+ motionY = y;
+ motionZ = z;
+ deltaX = rx;
+ deltaY = ry;
+ deltaZ = rz;
+ this.sprinting = sprinting;
+ this.jumpMovementFactor = jumpMovementVector;
+ }
+
+ public MotionData() {
+ this(0D, 0D, 0D, 0f, 0f, 0f, false, 0f);
+ }
+
+ public double getClientX() {
+ return motionX;
+ }
+
+ public double getClientY() {
+ return motionY;
+ }
+
+ public double getClientZ() {
+ return motionZ;
+ }
+
+ public float getClientrX() {
+ return deltaX;
+ }
+
+ public float getClientrY() {
+ return deltaY;
+ }
+
+ public float getClientrZ() {
+ return deltaZ;
+ }
+
+ public boolean isSprinting() {
+ return sprinting;
+ }
+
+ public float getJumpMovementVector() {
+ return jumpMovementFactor;
+ }
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/package-info.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/package-info.java
new file mode 100644
index 00000000..ec5baf8f
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/package-info.java
@@ -0,0 +1,8 @@
+package com.minecrafttas.tasmod.savestates.storage;
+/**
+ * Package for extending the vanilla storage.
+ *
+ * Some things do not get stored by the vanilla storage,
+ * causing discrepancies for savestates
+ *
+ */
diff --git a/src/main/java/com/minecrafttas/tasmod/util/Ducks.java b/src/main/java/com/minecrafttas/tasmod/util/Ducks.java
index 533affea..ea310379 100644
--- a/src/main/java/com/minecrafttas/tasmod/util/Ducks.java
+++ b/src/main/java/com/minecrafttas/tasmod/util/Ducks.java
@@ -19,19 +19,38 @@
* @author Pancake
*/
public class Ducks {
-
+
/**
* Quacks the chunk provider to unload all chunks
*/
public static interface ChunkProviderDuck {
+ /**
+ * Unloads chunks in the chunk providers
+ * @see com.minecrafttas.tasmod.mixin.savestates.MixinChunkProviderServer#unloadAllChunks() MixinChunkProviderServer#unloadAllChunks()
+ * @see com.minecrafttas.tasmod.mixin.savestates.MixinChunkProviderClient#unloadAllChunks() MixinChunkProviderClient#unloadAllChunks()
+ */
public void unloadAllChunks();
}
-
+
+ /**
+ * Quacks the worldserver to implement custom chunk ticking behavior
+ *
+ * @author Scribble
+ */
+ public static interface WorldServerDuck {
+
+ /**
+ * Sends the chunks to the client
+ * @see com.minecrafttas.tasmod.mixin.savestates.MixinWorldServer#sendChunksToClient() MixinWorldServer#sendChunksToClient()
+ */
+ public void sendChunksToClient();
+ }
+
/**
* Quacks the gui screen to spit out mouse positions independent of the display size
*/
public static interface GuiScreenDuck {
-
+
/**
* Calculates the true value of the pointer coordinate, by removing the scaling for custom screen sizes applied to it:
*
@@ -43,7 +62,7 @@ public static interface GuiScreenDuck {
* @see #rescaleX(int)
*/
public int unscaleX(int x);
-
+
/**
* Calculates the true value of the pointer coordinate, by removing the scaling for custom screen sizes applied to it:
*
@@ -55,7 +74,7 @@ public static interface GuiScreenDuck {
* @see #rescaleY(int)
*/
public int unscaleY(int y);
-
+
/**
* Reapplies the math for custom gui scales to the pointer coordinate:
*
@@ -65,7 +84,7 @@ public static interface GuiScreenDuck {
* @return The scaled pointer coordinate
*/
public int rescaleX(int x);
-
+
/**
* Reapplies the math for custom gui scales to the pointer coordinate:
*
@@ -81,12 +100,33 @@ public static interface GuiScreenDuck {
* Quacks the subtick
*/
public static interface SubtickDuck {
+
/**
* Custom updating method for EntityRenderer, updating the player rotation
* @param partialTicks The partial ticks from the vanilla Minecraft timer
*/
- void runUpdate(float partialTicks);
+ public void runUpdate(float partialTicks);
+ }
+
+ /**
+ * Quacks the scoreboard
+ */
+ public static interface ScoreboardDuck {
+
+ /**
+ * Clears the client scoreboard
+ */
+ public void clearScoreboard();
}
-
-}
+ /**
+ * Quacks the world client
+ */
+ public static interface WorldClientDuck {
+
+ /**
+ * Clear entitylist on the client
+ */
+ public void clearEntityList();
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/util/LoggerMarkers.java b/src/main/java/com/minecrafttas/tasmod/util/LoggerMarkers.java
index 61fcfad0..1d2951ed 100644
--- a/src/main/java/com/minecrafttas/tasmod/util/LoggerMarkers.java
+++ b/src/main/java/com/minecrafttas/tasmod/util/LoggerMarkers.java
@@ -3,6 +3,13 @@
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
+import com.minecrafttas.tasmod.events.EventClient.EventDrawHotbarAlways;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+
/**
* A list of Log4J markers which can be added to logging statements.
*
@@ -24,7 +31,7 @@
* @author Scribble
*
*/
-public class LoggerMarkers {
+public class LoggerMarkers implements EventDrawHotbarAlways {
public static final Marker Event = MarkerManager.getMarker("Event");
@@ -39,4 +46,132 @@ public class LoggerMarkers {
public static final Marker Keyboard = MarkerManager.getMarker("Keyboard");
public static final Marker Mouse = MarkerManager.getMarker("Mouse");
+
+ @Override
+ public void onDrawHotbarAlways() {
+ ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft());
+ float xpos = scaledresolution.getScaledWidth() / 2 - 2;
+ float ypos = scaledresolution.getScaledHeight() - 50f;
+
+ float scale = 1.26f;
+ int rotate = 15;
+ GlStateManager.translate(xpos, ypos, 0);
+ GlStateManager.scale(scale, scale, 1);
+ GlStateManager.rotate(rotate, 0, 0, 1);
+ int oW = 0xCCAFA5;
+ int o = 0xC24218;
+
+ int w = 0xFFFFFF;
+ int c = 0x546980;
+
+ int y = 0;
+ drawMarker(3, y, o);
+ drawMarker(4, y, o);
+ drawMarker(5, y, o);
+
+ y = 1;
+ drawMarker(2, y, w);
+ drawMarker(3, y, oW);
+ drawMarker(4, y, oW);
+ drawMarker(5, y, oW);
+ drawMarker(6, y, w);
+
+ y = 2;
+ drawMarker(2, y, w);
+ drawMarker(3, y, o);
+ drawMarker(4, y, o);
+ drawMarker(5, y, o);
+ drawMarker(6, y, w);
+
+ y = 3;
+ drawMarker(3, y, w);
+ drawMarker(5, y, w);
+
+ y = 4;
+ drawMarker(3, y, w);
+ drawMarker(5, y, w);
+
+ y = 5;
+ drawMarker(2, y, w);
+ drawMarker(6, y, w);
+
+ y = 6;
+ drawMarker(1, y, w);
+ drawMarker(2, y, c);
+ drawMarker(3, y, w);
+ drawMarker(4, y, c);
+ drawMarker(5, y, c);
+ drawMarker(6, y, c);
+ drawMarker(7, y, w);
+
+ y = 7;
+ drawMarker(0, y, w);
+ drawMarker(1, y, c);
+ drawMarker(2, y, w);
+ drawMarker(3, y, c);
+ drawMarker(4, y, c);
+ drawMarker(5, y, c);
+ drawMarker(6, y, c);
+ drawMarker(7, y, c);
+ drawMarker(8, y, w);
+
+ y = 8;
+ drawMarker(0, y, w);
+ drawMarker(1, y, c);
+ drawMarker(2, y, w);
+ drawMarker(3, y, c);
+ drawMarker(4, y, c);
+ drawMarker(5, y, c);
+ drawMarker(6, y, c);
+ drawMarker(7, y, c);
+ drawMarker(8, y, w);
+
+ y = 9;
+ drawMarker(0, y, w);
+ drawMarker(1, y, c);
+ drawMarker(2, y, c);
+ drawMarker(3, y, c);
+ drawMarker(4, y, c);
+ drawMarker(5, y, c);
+ drawMarker(6, y, w);
+ drawMarker(7, y, c);
+ drawMarker(8, y, w);
+
+ y = 10;
+ drawMarker(0, y, w);
+ drawMarker(1, y, c);
+ drawMarker(2, y, c);
+ drawMarker(3, y, c);
+ drawMarker(4, y, c);
+ drawMarker(5, y, c);
+ drawMarker(6, y, w);
+ drawMarker(7, y, c);
+ drawMarker(8, y, w);
+
+ y = 11;
+ drawMarker(0, y, w);
+ drawMarker(1, y, w);
+ drawMarker(2, y, c);
+ drawMarker(3, y, c);
+ drawMarker(4, y, c);
+ drawMarker(5, y, w);
+ drawMarker(6, y, c);
+ drawMarker(7, y, w);
+ drawMarker(8, y, w);
+
+ y = 12;
+ drawMarker(2, y, w);
+ drawMarker(3, y, w);
+ drawMarker(4, y, w);
+ drawMarker(5, y, w);
+ drawMarker(6, y, w);
+ GlStateManager.rotate(-rotate, 0, 0, 1);
+ GlStateManager.scale(1 / scale, 1 / scale, 1);
+ GlStateManager.translate(-xpos, -ypos, 0);
+ }
+
+ private void drawMarker(int posX, int posY, int textColor) {
+ int alpha = 0x80000000;
+ Gui.drawRect(posX, posY, posX + 1, posY + 1, textColor + alpha);
+ }
}
diff --git a/src/main/java/com/minecrafttas/tasmod/util/Monitor.java b/src/main/java/com/minecrafttas/tasmod/util/Monitor.java
index d53e5ac1..24f60e06 100644
--- a/src/main/java/com/minecrafttas/tasmod/util/Monitor.java
+++ b/src/main/java/com/minecrafttas/tasmod/util/Monitor.java
@@ -63,5 +63,4 @@ public static Object accessField(Object objectToAccess, String fieldname) {
}
return out;
}
-
}
diff --git a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java
index 7ff5ccad..63272b5e 100644
--- a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java
+++ b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java
@@ -16,6 +16,7 @@
import com.minecrafttas.tasmod.mixin.playbackhooks.MixinEntityRenderer;
import com.minecrafttas.tasmod.mixin.playbackhooks.MixinMinecraft;
import com.minecrafttas.tasmod.util.Ducks;
+import com.minecrafttas.tasmod.util.Ducks.SubtickDuck;
import com.minecrafttas.tasmod.util.LoggerMarkers;
import com.minecrafttas.tasmod.util.PointerNormalizer;
import com.minecrafttas.tasmod.virtual.event.VirtualKeyboardEvent;
@@ -144,8 +145,25 @@ public void preloadInput(VirtualKeyboard keyboardToPreload, VirtualMouse mouseTo
MOUSE.nextMouse.deepCopyFrom(mouseToPreload);
CAMERA_ANGLE.nextCameraAngle.deepCopyFrom(angleToPreload);
Minecraft.getMinecraft().runTickKeyboard(); // Letting mouse and keyboard tick once to load inputs into the "currentKeyboard"
- //
Minecraft.getMinecraft().runTickMouse();
+ SubtickDuck entityRenderer = (SubtickDuck) Minecraft.getMinecraft().entityRenderer;
+ entityRenderer.runUpdate(0);
+ }
+
+ public List getCurrentMousePresses() {
+ return MOUSE.currentMouse.getCurrentPresses();
+ }
+
+ public List getNextMousePresses() {
+ return MOUSE.nextMouse.getCurrentPresses();
+ }
+
+ public List getCurrentKeyboardPresses() {
+ return KEYBOARD.currentKeyboard.getCurrentPresses();
+ }
+
+ public List getNextKeyboardPresses() {
+ return KEYBOARD.nextKeyboard.getCurrentPresses();
}
/**
@@ -599,10 +617,10 @@ public void updateNextCameraAngle(float pitchDelta, float yawDelta) {
*
* Runs every frame
*
- * @see com.minecrafttas.tasmod.mixin.playbackhooks.MixinEntityRenderer#runUpdate(float);
* @param pitchDelta Relative rotationPitch delta from LWJGLs mouse delta.
* @param yawDelta Relative rotationYaw delta from LWJGLs mouse delta.
* @param updateSubtick Whether to add the previous camera angle to the {@link Subtickable#subtickList}
+ * @see MixinEntityRenderer#runUpdate(float)
*/
public void updateNextCameraAngle(float pitchDelta, float yawDelta, boolean updateSubtick) {
// LOGGER.debug("Pitch: {}, Yaw: {}", pitch, yaw);
diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json
index cf44a0fe..dec8d114 100644
--- a/src/main/resources/fabric.mod.json
+++ b/src/main/resources/fabric.mod.json
@@ -33,5 +33,11 @@
"fabricloader": ">=0.14.19",
"minecraft": "1.12.2",
"java": ">=8"
+ },
+ "custom": {
+ "mc-publish": {
+ "modrinth": "g0TxtOPk",
+ "curseforge": "434702"
+ }
}
}
\ No newline at end of file
diff --git a/src/main/resources/tasmod.accesswidener b/src/main/resources/tasmod.accesswidener
index 99c6bdf0..0029bc11 100644
--- a/src/main/resources/tasmod.accesswidener
+++ b/src/main/resources/tasmod.accesswidener
@@ -9,8 +9,6 @@ accessible field net/minecraft/util/Timer tickLength F
accessible field net/minecraft/world/World unloadedEntityList Ljava/util/List;
accessible field net/minecraft/world/World worldInfo Lnet/minecraft/world/storage/WorldInfo;
-accessible field net/minecraft/world/WorldServer pendingTickListEntriesHashSet Ljava/util/Set;
-
accessible method net/minecraft/world/storage/SaveHandler setSessionLock ()V
-accessible field net/minecraft/client/settings/KeyBinding CATEGORY_ORDER Ljava/util/Map;
+accessible field net/minecraft/client/settings/KeyBinding CATEGORY_ORDER Ljava/util/Map;
\ No newline at end of file
diff --git a/src/main/resources/tasmod.mixin.json b/src/main/resources/tasmod.mixin.json
index 04a4d468..25231ee5 100644
--- a/src/main/resources/tasmod.mixin.json
+++ b/src/main/resources/tasmod.mixin.json
@@ -1,47 +1,51 @@
{
- "required": true,
- "minVersion": "0.8.5",
- "package": "com.minecrafttas.tasmod.mixin",
- "compatibilityLevel": "JAVA_8",
- "mixins": [
-
- //General
- "MixinMinecraftServer",
- "MixinEntityPlayer",
-
- //Savestates
- "savestates.MixinChunkProviderServer",
- "savestates.MixinEntityPlayerMP",
- "savestates.MixinNetHandlerPlayServer",
- "savestates.AccessorChunkLoader",
- "savestates.AccessorAnvilChunkLoader",
-
- //Events
-
- //Fixing forge and vanilla stuff
- "fixes.MixinDragonFightManager"
-
- ],
- "client": [
- //General
- "MixinMinecraft",
- "MixinTimer",
- "MixinInGameHud",
-
- //Savestates
+ "required": true,
+ "minVersion": "0.8.5",
+ "package": "com.minecrafttas.tasmod.mixin",
+ "compatibilityLevel": "JAVA_8",
+ "mixins": [
+ // General
+ "MixinMinecraftServer",
+ "MixinEntityPlayer",
+
+ // Savestates
+ "savestates.AccessorAnvilChunkLoader",
+ "savestates.AccessorChunkLoader",
+ "savestates.AccessorEntityLivingBase",
+ "savestates.AccessorPlayerChunkMap",
+ "savestates.MixinChunkProviderServer",
+ "savestates.MixinNetHandlerPlayServer",
+ "savestates.MixinScoreboard",
+ "savestates.MixinWorldServer",
+
+ // Events
+ "events.MixinEntityPlayerMP",
+
+ // Fixing forge and vanilla stuff
+ "fixes.MixinDragonFightManager"
+
+ ],
+ "client": [
+ // General
+ "MixinMinecraft",
+ "MixinTimer",
+
+ // Savestates
"savestates.MixinChunkProviderClient",
+ "savestates.MixinWorldClient",
- //Interpolation
+ // Interpolation
"MixinFrustum",
- //Keybinding
+ // Keybinding
"MixinTextfield",
- //Join and leave game event on the client
+ // Events
"events.MixinGuiMainMenu",
"events.MixinGuiIngame",
+ "events.MixinEntityRenderer",
- //Playbackhooks
+ // Playbackhooks
"playbackhooks.MixinMinecraft",
"playbackhooks.MixinEntityRenderer",
"playbackhooks.MixinGuiScreen",
@@ -55,12 +59,12 @@
"playbackhooks.MixinGuiStats",
"playbackhooks.MixinKeyBinding",
- //Shields
+ // Shields
"shields.MixinRenderItem",
"shields.MixinTileEntityItemStackRenderer",
- //Fixes
- "fixes.MixinMinecraftFullscreen",
- "fixes.MixinNetworkManager"
+ // Fixes
+ "fixes.MixinMinecraftFullscreen",
+ "fixes.MixinNetworkManager"
]
}
\ No newline at end of file
diff --git a/src/test/java/mctcommon/TestConfiguration.java b/src/test/java/mctcommon/TestConfiguration.java
index 70177b22..1aac0e79 100644
--- a/src/test/java/mctcommon/TestConfiguration.java
+++ b/src/test/java/mctcommon/TestConfiguration.java
@@ -4,29 +4,32 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
-import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.minecrafttas.mctcommon.Configuration;
-import com.minecrafttas.mctcommon.Configuration.ConfigOptions;
+import com.minecrafttas.mctcommon.ConfigurationRegistry;
+import com.minecrafttas.mctcommon.ConfigurationRegistry.ConfigOptions;
class TestConfiguration {
-
+
enum TestConfig implements ConfigOptions {
FileToOpen("fileToOpen", ""),
ServerConnection("serverConnection", "");
private String configKey;
private String defaultValue;
-
+
private TestConfig(String configKey, String defaultValue) {
this.configKey = configKey;
this.defaultValue = defaultValue;
}
-
+
@Override
public String getDefaultValue() {
return defaultValue;
@@ -36,7 +39,7 @@ public String getDefaultValue() {
public String getConfigKey() {
return configKey;
}
-
+
@Override
public String getExtensionName() {
return "TestConfig";
@@ -44,19 +47,21 @@ public String getExtensionName() {
}
private Configuration config;
-
- private static final File configPath = new File("./config.xml");
-
+
+ ConfigurationRegistry registry = new ConfigurationRegistry();
+
+ private static final Path configPath = Paths.get("src/test/resources/config.xml");
+
@BeforeEach
void beforeEach() {
- config = new Configuration("Test config", configPath);
- config.register(TestConfig.values());
- config.load();
+ registry.register(TestConfig.values());
+ config = new Configuration("Test config", configPath, registry);
+ config.loadFromXML();
}
- @AfterAll
- static void tearDownAfterClass() throws Exception {
- configPath.delete();
+ @AfterEach
+ void tearDownAfterClass() throws Exception {
+ Files.delete(configPath);
}
/**
@@ -66,31 +71,28 @@ static void tearDownAfterClass() throws Exception {
void testIfInitialized() {
assertNotNull(config);
}
-
+
/**
* Test if the default option is correctly set
*/
@Test
- void testDefault() {
- configPath.delete();
- config = new Configuration("Test config", configPath);
- config.register(TestConfig.values());
- config.load();
+ void testDefault() throws Exception {
+ Files.delete(configPath);
+ config = new Configuration("Test config", configPath, registry);
+ config.loadFromXML();
assertEquals("", config.get(TestConfig.FileToOpen));
}
-
+
/**
* Setting a value and recreating the config should result in the value still being set
*/
@Test
void testSavingAndLoading() {
config.set(TestConfig.FileToOpen, "Test");
- config = new Configuration("Test config", configPath);
- config.register(TestConfig.values());
- config.load();
+ config.loadFromXML();
assertEquals("Test", config.get(TestConfig.FileToOpen));
}
-
+
/**
* Test if integers can be set
*/
@@ -108,7 +110,7 @@ void testBooleans() {
config.set(TestConfig.FileToOpen, true);
assertEquals(true, config.getBoolean(TestConfig.FileToOpen));
}
-
+
/**
* Test if deleting and unsetting a config value works
*/
@@ -117,7 +119,7 @@ void testDeleteAndContains() {
config.delete(TestConfig.FileToOpen);
assertFalse(config.has(TestConfig.FileToOpen));
}
-
+
/**
* Test if resetting to default works
*/
diff --git a/src/test/java/tasmod/playback/tasfile/PlaybackSerialiserTest.java b/src/test/java/tasmod/playback/tasfile/PlaybackSerialiserTest.java
index 91834091..a640e3fe 100644
--- a/src/test/java/tasmod/playback/tasfile/PlaybackSerialiserTest.java
+++ b/src/test/java/tasmod/playback/tasfile/PlaybackSerialiserTest.java
@@ -3,6 +3,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertIterableEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.File;
@@ -36,26 +37,25 @@
import com.minecrafttas.tasmod.virtual.VirtualMouse;
public class PlaybackSerialiserTest {
-
+
private static class TestFlavor extends SerialiserFlavorBase {
@Override
public String getExtensionName() {
return "Test";
}
-
-
+
@Override
public SerialiserFlavorBase clone() {
return new TestFlavor();
}
}
-
+
private static class TestMetadatada extends PlaybackMetadataExtension {
String testValue = "";
String actual = "e";
-
+
@Override
public String getExtensionName() {
return "Test";
@@ -63,12 +63,12 @@ public String getExtensionName() {
@Override
public void onCreate() {
-
+
}
@Override
public PlaybackMetadata onStore() {
- PlaybackMetadata metadata =new PlaybackMetadata(this);
+ PlaybackMetadata metadata = new PlaybackMetadata(this);
metadata.setValue("TestKey", testValue);
return metadata;
}
@@ -80,80 +80,89 @@ public void onLoad(PlaybackMetadata metadata) {
@Override
public void onClear() {
+ testValue = "";
+ actual = "e";
}
-
+
}
-
+
private static class TestFileCommand extends PlaybackFileCommandExtension {
List inline = new ArrayList<>();
List endline = new ArrayList<>();
-
+
@Override
public String getExtensionName() {
return "tasmod_testFileExtension";
}
-
+
@Override
public void onDeserialiseInlineComment(long tick, TickContainer container, PlaybackFileCommandContainer fileCommandContainer) {
inline.add(fileCommandContainer.split("testKey"));
}
-
+
@Override
public void onDeserialiseEndlineComment(long tick, TickContainer container, PlaybackFileCommandContainer fileCommandContainer) {
endline.add(fileCommandContainer.split("endlineKey"));
}
-
+
@Override
public String[] getFileCommandNames() {
- return new String[]{"testKey", "endlineKey"};
+ return new String[] { "testKey", "endlineKey" };
+ }
+
+ @Override
+ public void onClear() {
+ inline.clear();
+ endline.clear();
}
}
-
+
File file;
-
+
private static TestFlavor testFlavor = new TestFlavor();
private static TestMetadatada testMetadata = new TestMetadatada();
private static TestFileCommand testFileCommand = new TestFileCommand();
-
+
@BeforeAll
static void register() {
TASmodAPIRegistry.SERIALISER_FLAVOR.register(testFlavor);
TASmodAPIRegistry.PLAYBACK_METADATA.register(testMetadata);
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.register(testFileCommand);
}
-
+
@AfterEach
void afterEach() {
- testFileCommand.inline.clear();
- testFileCommand.endline.clear();
- if(file!=null) {
+ if (file != null) {
file.delete();
}
+
+ testMetadata.onClear();
+ testFileCommand.onClear();
}
-
+
@AfterAll
static void unregister() {
TASmodAPIRegistry.SERIALISER_FLAVOR.unregister(testFlavor);
TASmodAPIRegistry.PLAYBACK_METADATA.unregister(testMetadata);
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.unregister(testFileCommand);
}
-
+
@Test
void testSerialiser() {
BigArrayList expected = new BigArrayList<>();
-
+
file = new File("src/test/resources/serialiser/PlaybackSerialiserTest.mctas");
-
+
testMetadata.testValue = "testing";
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.setEnabled("tasmod_testFileExtension", true);
// Tick 1
-
+
// Keyboard
VirtualKeyboard keyboard1 = new VirtualKeyboard();
keyboard1.updateFromEvent(VirtualKey.W, true, 'w');
- keyboard1.updateFromEvent(VirtualKey.LCONTROL, true, (char)0);
-
+ keyboard1.updateFromEvent(VirtualKey.LCONTROL, true, (char) 0);
+
// Mouse
VirtualMouse mouse1 = new VirtualMouse();
mouse1.updateFromEvent(VirtualKey.MOUSEMOVED, false, 15, 0, 0);
@@ -163,17 +172,17 @@ void testSerialiser() {
VirtualCameraAngle angle1 = new VirtualCameraAngle();
angle1.set(0, 0);
angle1.updateFromEvent(10, 10);
-
+
expected.add(new TickContainer(keyboard1, mouse1, angle1));
-
+
// Tick 2
-
+
// Keyboard
VirtualKeyboard keyboard2 = new VirtualKeyboard();
keyboard2.copyFrom(keyboard1);
- keyboard2.updateFromEvent(VirtualKey.W, false, (char)0);
- keyboard2.updateFromEvent(VirtualKey.LCONTROL, false, (char)0);
-
+ keyboard2.updateFromEvent(VirtualKey.W, false, (char) 0);
+ keyboard2.updateFromEvent(VirtualKey.LCONTROL, false, (char) 0);
+
// Mouse
VirtualMouse mouse2 = new VirtualMouse();
mouse2.copyFrom(mouse1);
@@ -184,15 +193,15 @@ void testSerialiser() {
VirtualCameraAngle angle2 = new VirtualCameraAngle();
angle2.deepCopyFrom(angle1);
angle2.updateFromEvent(-10, -10);
-
+
expected.add(new TickContainer(keyboard2, mouse2, angle2));
-
+
try {
PlaybackSerialiser.saveToFile(file, expected, "Test");
} catch (PlaybackSaveException e) {
e.printStackTrace();
}
-
+
try {
BigArrayList actual = PlaybackSerialiser.loadFromFile(file, testFlavor);
assertBigArrayList(expected, actual);
@@ -201,7 +210,7 @@ void testSerialiser() {
fail(e);
}
}
-
+
@Test
void testDeserialiser() throws PlaybackLoadException, IOException {
List lines = new ArrayList<>();
@@ -219,112 +228,176 @@ void testDeserialiser() throws PlaybackLoadException, IOException {
lines.add("2|W;w|-101;0,1,1|1;1");
lines.add("3|;|-101;0,~1,~1|~1;~1");
lines.add("\t1|;|-101;0,~1,~1|~1;~1");
-
+
file = new File("src/test/resources/serialiser/PlaybackSerialiserTest2.mctas");
try {
FileUtils.writeLines(file, lines);
} catch (IOException e) {
e.printStackTrace();
}
-
+
BigArrayList actual = PlaybackSerialiser.loadFromFile(file);
BigArrayList expected = new BigArrayList<>();
-
+
VirtualKeyboard keyboard = new VirtualKeyboard();
keyboard.updateFromEvent(VirtualKey.W, true, 'w');
keyboard.updateFromEvent(VirtualKey.T, true, 't');
-
-
+
CommentContainer container = new CommentContainer();
container.addInlineComment("This is a regular comment");
container.addInlineComment(null);
container.addEndlineComment("test");
expected.add(new TickContainer(keyboard, new VirtualMouse(), new VirtualCameraAngle(), container));
-
VirtualKeyboard keyboard2 = new VirtualKeyboard();
keyboard2.updateFromEvent(VirtualKey.W, true, 'w');
-
+
VirtualMouse mouse2 = new VirtualMouse();
mouse2.updateFromEvent(VirtualKey.MOUSEMOVED, false, 0, 1, 1);
-
+
VirtualCameraAngle cameraAngle2 = new VirtualCameraAngle();
cameraAngle2.set(1f, 1f);
-
+
expected.add(new TickContainer(keyboard2, mouse2, cameraAngle2));
-
VirtualMouse mouse3 = new VirtualMouse();
mouse3.updateFromEvent(VirtualKey.MOUSEMOVED, false, 0, 2, 2);
mouse3.updateFromEvent(VirtualKey.MOUSEMOVED, false, 0, 3, 3);
-
+
VirtualCameraAngle cameraAngle3 = new VirtualCameraAngle();
cameraAngle3.updateFromState(2f, 2f);
expected.add(new TickContainer(new VirtualKeyboard(), mouse3, cameraAngle3));
-
+
assertBigArrayList(expected, actual);
-
+
assertEquals("Wat", testMetadata.actual);
-
+
List fclist = new ArrayList<>();
PlaybackFileCommandContainer fccontainer = new PlaybackFileCommandContainer();
fccontainer.add("testKey", new PlaybackFileCommand("testKey", "test"));
PlaybackFileCommandContainer fccontainerempty = new PlaybackFileCommandContainer();
fccontainerempty.put("testKey", null);
-
+
fclist.add(fccontainer);
fclist.add(fccontainerempty);
fclist.add(fccontainerempty);
assertIterableEquals(fclist, testFileCommand.inline);
-
+
List fclistEnd = new ArrayList<>();
PlaybackFileCommandContainer fccontainerEnd = new PlaybackFileCommandContainer();
fccontainerEnd.add("endlineKey", null);
fccontainerEnd.add("endlineKey", new PlaybackFileCommand("endlineKey"));
-
+
PlaybackFileCommandContainer fccontainerEndEmpty = new PlaybackFileCommandContainer();
fccontainerEndEmpty.put("endlineKey", null);
-
+
fclistEnd.add(fccontainerEnd);
fclistEnd.add(fccontainerEndEmpty);
fclistEnd.add(fccontainerEndEmpty);
assertIterableEquals(fclistEnd, testFileCommand.endline);
}
-
+
+ @Test
+ void testDeserialiserNoExtensions() throws PlaybackLoadException, IOException {
+ List lines = new ArrayList<>();
+ lines.add("TASfile");
+ lines.add("FileCommand-Extensions: tasmod_testFileExtension");
+ lines.add("Flavor: Test");
+ lines.add("----------- Test ----------");
+ lines.add("TestKey: Wat");
+ lines.add("##################################################");
+ lines.add("// This is a regular comment");
+ lines.add("");
+ lines.add("// $testKey(test);");
+ lines.add("1|W;w|| // test");
+ lines.add("\t1|W,T;t|| // $testKey(test);$endlineKey();");
+ lines.add("2|W;w|-101;0,1,1|1;1");
+ lines.add("3|;|-101;0,~1,~1|~1;~1");
+ lines.add("\t1|;|-101;0,~1,~1|~1;~1");
+
+ file = new File("src/test/resources/serialiser/PlaybackSerialiserTest3.mctas");
+ try {
+ FileUtils.writeLines(file, lines);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ BigArrayList actual = PlaybackSerialiser.loadFromFile(file, false);
+
+ BigArrayList expected = new BigArrayList<>();
+
+ VirtualKeyboard keyboard = new VirtualKeyboard();
+ keyboard.updateFromEvent(VirtualKey.W, true, 'w');
+ keyboard.updateFromEvent(VirtualKey.T, true, 't');
+
+ CommentContainer container = new CommentContainer();
+ container.addInlineComment("This is a regular comment");
+ container.addInlineComment(null);
+ container.addEndlineComment("test");
+ expected.add(new TickContainer(keyboard, new VirtualMouse(), new VirtualCameraAngle(), container));
+
+ VirtualKeyboard keyboard2 = new VirtualKeyboard();
+ keyboard2.updateFromEvent(VirtualKey.W, true, 'w');
+
+ VirtualMouse mouse2 = new VirtualMouse();
+ mouse2.updateFromEvent(VirtualKey.MOUSEMOVED, false, 0, 1, 1);
+
+ VirtualCameraAngle cameraAngle2 = new VirtualCameraAngle();
+ cameraAngle2.set(1f, 1f);
+
+ expected.add(new TickContainer(keyboard2, mouse2, cameraAngle2));
+
+ VirtualMouse mouse3 = new VirtualMouse();
+ mouse3.updateFromEvent(VirtualKey.MOUSEMOVED, false, 0, 2, 2);
+ mouse3.updateFromEvent(VirtualKey.MOUSEMOVED, false, 0, 3, 3);
+
+ VirtualCameraAngle cameraAngle3 = new VirtualCameraAngle();
+ cameraAngle3.updateFromState(2f, 2f);
+
+ expected.add(new TickContainer(new VirtualKeyboard(), mouse3, cameraAngle3));
+
+ assertBigArrayList(expected, actual);
+
+ assertEquals("e", testMetadata.actual);
+
+ assertTrue(testFileCommand.inline.isEmpty());
+ assertTrue(testFileCommand.endline.isEmpty());
+ }
+
@Test
void testFlavorNotFound() {
List lines = new ArrayList<>();
for (int i = 0; i < 500; i++) {
lines.add("Test");
}
-
+
file = new File("src/test/resources/serialiser/PlaybackSerialiserTest3.mctas");
try {
FileUtils.writeLines(file, lines);
} catch (IOException e) {
e.printStackTrace();
}
-
- Throwable t = assertThrows(PlaybackLoadException.class, ()->{
+
+ Throwable t = assertThrows(PlaybackLoadException.class, () -> {
PlaybackSerialiser.loadFromFile(file);
});
-
+
assertEquals("Couldn't find a flavorname in the file. TASfile is missing a flavor-extension or the file is broken", t.getMessage());
}
-
+
@Test
void testFlavorIsNull() {
- Throwable t = assertThrows(PlaybackLoadException.class, ()->{
+ Throwable t = assertThrows(PlaybackLoadException.class, () -> {
PlaybackSerialiser.loadFromFile(file, "NotAFlavor");
});
-
+
assertEquals("Flavor name NotAFlavor doesn't exist.", t.getMessage());
-
+
}
-
+
private void assertBigArrayList(BigArrayList expected, BigArrayList actual) {
assertIterableEquals(convertBigArrayListToArrayList(expected), convertBigArrayListToArrayList(actual));
}
diff --git a/src/test/java/tasmod/playback/tasfile/SerialiserFlavorBaseTest.java b/src/test/java/tasmod/playback/tasfile/SerialiserFlavorBaseTest.java
index 8864d879..c5e2c610 100644
--- a/src/test/java/tasmod/playback/tasfile/SerialiserFlavorBaseTest.java
+++ b/src/test/java/tasmod/playback/tasfile/SerialiserFlavorBaseTest.java
@@ -35,12 +35,12 @@ void afterEach() {
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.clear();
TASmodAPIRegistry.PLAYBACK_METADATA.clear();
TASmodAPIRegistry.SERIALISER_FLAVOR.clear();
-
+
this.currentTick = 0;
this.currentSubtick = 0;
this.previousTickContainer = null;
}
-
+
@Override
public String getExtensionName() {
return "Test";
@@ -67,7 +67,7 @@ void testSerialiseHeaderStart() {
*/
@Test
void testSerialiseMetadata() {
-
+
class MetadataTest extends PlaybackMetadataExtension {
public String testValue;
@@ -100,7 +100,7 @@ public void onClear() {
}
}
-
+
class MetadataTest2 extends PlaybackMetadataExtension {
public String testValue;
@@ -133,7 +133,7 @@ public void onClear() {
}
}
-
+
MetadataTest testmetadata1 = new MetadataTest();
testmetadata1.testValue = "This is a test";
@@ -156,14 +156,14 @@ public void onClear() {
assertIterableEquals(expected, actual);
assertEquals(0, currentTick);
-
+
TASmodAPIRegistry.PLAYBACK_METADATA.unregister(testmetadata1);
TASmodAPIRegistry.PLAYBACK_METADATA.unregister(testmetadata2);
}
-
+
@Test
void testSerialiseFileCommandNames() {
-
+
class TestFileCommand extends PlaybackFileCommandExtension {
@Override
@@ -176,18 +176,18 @@ public String[] getFileCommandNames() {
return null;
}
}
-
+
TestFileCommand fc = new TestFileCommand();
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.register(fc);
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.setEnabled("tasmod_testFileCommand", true);
-
+
List actual = new ArrayList<>();
serialiseFileCommandNames(actual);
-
+
List expected = new ArrayList<>();
expected.add("FileCommand-Extensions: tasmod_testFileCommand");
expected.add("");
-
+
assertIterableEquals(expected, actual);
}
@@ -380,11 +380,11 @@ void testExtractHeaderFail() {
*/
@Test
void testDeserialiseMetadata() {
-
- class GeneralMetadata extends PlaybackMetadataExtension{
+
+ class GeneralMetadata extends PlaybackMetadataExtension {
PlaybackMetadata metadata = null;
-
+
@Override
public String getExtensionName() {
return "General";
@@ -407,13 +407,13 @@ public void onLoad(PlaybackMetadata metadata) {
@Override
public void onClear() {
}
-
+
}
-
+
class StartPositionMetadata extends PlaybackMetadataExtension {
PlaybackMetadata metadata = null;
-
+
@Override
public String getExtensionName() {
return "StartPosition";
@@ -436,15 +436,15 @@ public void onLoad(PlaybackMetadata metadata) {
@Override
public void onClear() {
}
-
+
}
-
+
GeneralMetadata general = new GeneralMetadata();
StartPositionMetadata startPosition = new StartPositionMetadata();
-
+
TASmodAPIRegistry.PLAYBACK_METADATA.register(general);
TASmodAPIRegistry.PLAYBACK_METADATA.register(startPosition);
-
+
List lines = new ArrayList<>();
lines.add("--- General");
lines.add("Author: Scribble");
@@ -481,8 +481,8 @@ public void onClear() {
@Test
void testDeserialiseFileCommandNames() {
-
- class Test1 extends PlaybackFileCommandExtension{
+
+ class Test1 extends PlaybackFileCommandExtension {
@Override
public String getExtensionName() {
@@ -493,9 +493,9 @@ public String getExtensionName() {
public String[] getFileCommandNames() {
return null;
}
-
+
}
-
+
class Test2 extends PlaybackFileCommandExtension {
@Override
@@ -507,49 +507,49 @@ public String getExtensionName() {
public String[] getFileCommandNames() {
return null;
}
-
+
}
-
+
Test1 test1 = new Test1();
Test2 test2 = new Test2();
-
+
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.register(test1);
TASmodAPIRegistry.PLAYBACK_FILE_COMMAND.register(test2);
-
+
List lines = new ArrayList<>();
lines.add("FileCommand-Extensions: tasmod_test1, tasmod_test2");
-
+
deserialiseFileCommandNames(lines);
-
+
assertTrue(test1.isEnabled());
assertTrue(test2.isEnabled());
-
+
lines = new ArrayList<>();
lines.add("FileCommand-Extensions: ");
-
+
deserialiseFileCommandNames(lines);
-
+
assertFalse(test1.isEnabled());
assertFalse(test2.isEnabled());
-
+
lines = new ArrayList<>();
lines.add("FileCommand-Extensions: tasmod_test1,tasmod_test2");
-
+
deserialiseFileCommandNames(lines);
-
+
assertTrue(test1.isEnabled());
assertTrue(test2.isEnabled());
-
+
final List lines2 = new ArrayList<>();
lines2.add("FileCommand-Extensions tasmod_test1,tasmod_test2");
-
- Throwable t = assertThrows(PlaybackLoadException.class, ()->{
+
+ Throwable t = assertThrows(PlaybackLoadException.class, () -> {
deserialiseFileCommandNames(lines2);
});
assertEquals("FileCommand-Extensions value was not found in the header", t.getMessage());
}
-
+
/**
* Test extracing ticks from some lines
*/
@@ -597,7 +597,7 @@ void testExtractTick() {
tick2.add("56|W,LCONTROL;w|;0,887,626|17.85;-202.74799");
tick2.add("\t1||RC;0,1580,658|17.85;-202.74799");
tick2.add("\t2||;0,1580,658|17.85;-202.74799");
-
+
List tick3 = new ArrayList<>();
tick3.add("// This is a comment");
tick3.add("// $fileCommand();");
@@ -620,7 +620,7 @@ void testExtractTick() {
assertIterableEquals(expected, actual);
assertIterableEquals(expectedIndex, actualIndex);
}
-
+
@Test
void testExtractExceptions() {
// Create lines to be extracted from
@@ -629,14 +629,14 @@ void testExtractExceptions() {
lines.add("55|W,LCONTROL;w|;0,887,626|17.85;-202.74799");
lines.add("\t2||;0,1580,658|17.85;-202.74799");
- Throwable t = assertThrows(PlaybackLoadException.class, ()->{
+ Throwable t = assertThrows(PlaybackLoadException.class, () -> {
extractContainer(new ArrayList<>(), lines, 0);
});
// C o m p a r e
assertEquals("Line 1, Tick 0, Subtick 0: Error while trying to parse the file. This should not be a subtick at this position", t.getMessage());
}
-
+
@Test
void testExtractExceptions2() {
// Create lines to be extracted from
@@ -646,14 +646,14 @@ void testExtractExceptions2() {
lines.add("57|W,LCONTROL;w|;0,887,626|17.85;-202.74799");
lines.add("\t2||;0,1580,658|17.85;-202.74799");
- Throwable t = assertThrows(PlaybackLoadException.class, ()->{
+ Throwable t = assertThrows(PlaybackLoadException.class, () -> {
extractContainer(new ArrayList<>(), lines, 0);
});
// C o m p a r e
assertEquals("Line 2, Tick 0, Subtick 0: Error while trying to parse the file. This should not be a subtick at this position", t.getMessage());
}
-
+
@Test
void testExtractExceptions3() {
// Create lines to be extracted from
@@ -664,15 +664,15 @@ void testExtractExceptions3() {
lines.add("\t2||;0,1580,658|17.85;-202.74799");
extractContainer(new ArrayList<>(), lines, 0); // First extraction passes as it parses up to the comment.
-
- Throwable t = assertThrows(PlaybackLoadException.class, ()->{
- extractContainer(new ArrayList<>(), lines, 1); // Second extraction fails as it starts with the comment then, a subtick which is disallowed
+
+ Throwable t = assertThrows(PlaybackLoadException.class, () -> {
+ extractContainer(new ArrayList<>(), lines, 1); // Second extraction fails as it starts with the comment then, a subtick which is disallowed
});
// C o m p a r e
assertEquals("Line 3, Tick 0, Subtick 0: Error while trying to parse the file. This should not be a subtick at this position", t.getMessage());
}
-
+
/**
* Test deserialising a container a.k.a a tick
*/
@@ -697,10 +697,10 @@ void testDeserialiseContainer() {
mouse.updateFromState(new int[] { VirtualKey.MOUSEMOVED.getKeycode() }, 0, 1580, 658);
VirtualCameraAngle cameraAngle = new VirtualCameraAngle();
- cameraAngle.updateFromState(17.85F, -202.74799F);
- cameraAngle.updateFromState(11.85F, -2.74799F);
- cameraAngle.updateFromState(45F, -22.799F);
-
+ cameraAngle.updateFromState(-202.74799F, 17.85F);
+ cameraAngle.updateFromState(-2.74799F, 11.85F);
+ cameraAngle.updateFromState(-22.799F, 45F);
+
expected.add(new TickContainer(keyboard, mouse, cameraAngle));
assertBigArrayList(expected, actual);
@@ -818,7 +818,7 @@ void testDeserialiseKeyboard() {
assertEquals(expected, actual);
}
-
+
@Test
void testDeserialiseKeyboardWithKeyCodes() {
List tick = new ArrayList<>();
@@ -858,30 +858,30 @@ void testDeserialiseMouse() {
expected.updateFromEvent(VirtualKey.MC, true, 15, 25, 34);
assertEquals(expected, actual);
-
- currentTick=29;
+
+ currentTick = 29;
List tick2 = new ArrayList<>();
tick2.add(";0,0,0");
tick2.add("LC;0,12,35");
tick2.add("LC,MC;15,25");
-
- Throwable t = assertThrows(PlaybackLoadException.class, ()->{
+
+ Throwable t = assertThrows(PlaybackLoadException.class, () -> {
deserialiseMouse(tick2);
});
-
- assertEquals("Line 1, Tick 29, Subtick 2: Mouse functions do not have the correct length", t.getMessage());
-
- currentTick=30;
+
+ assertEquals("Line 1, Tick 29, Subtick 2: Mouse can't be read. Probably a missing comma: LC,MC;15,25", t.getMessage());
+
+ currentTick = 30;
List tick3 = new ArrayList<>();
tick3.add(";0,0,0");
tick3.add("LC;0,12,35,12");
tick3.add("LC,MC;15,25,15");
-
- Throwable t1 = assertThrows(PlaybackLoadException.class, ()->{
+
+ Throwable t1 = assertThrows(PlaybackLoadException.class, () -> {
deserialiseMouse(tick3);
});
-
- assertEquals("Line 1, Tick 30, Subtick 1: Mouse functions do not have the correct length", t1.getMessage());
+
+ assertEquals("Line 1, Tick 30, Subtick 1: Mouse can't be read. Probably a missing comma: LC;0,12,35,12", t1.getMessage());
}
/**
@@ -898,9 +898,9 @@ void testDeserialisingCameraAngle() {
VirtualCameraAngle expected = new VirtualCameraAngle();
expected.set(0, 0);
- expected.updateFromEvent(19F, -202.74799F);
- expected.updateFromEvent(11.1241500F - 19F, -2.799F + 202.74799F);
- expected.updateFromEvent(17.3F - 11.1241500F, -202.79F + 2.799F);
+ expected.updateFromEvent(-202.74799F, 19F);
+ expected.updateFromEvent(-2.799F + 202.74799F, 11.1241500F - 19F);
+ expected.updateFromEvent(-202.79F + 2.799F, 17.3F - 11.1241500F);
assertEquals(expected, actual);
}
@@ -926,66 +926,66 @@ void testIsFloat() {
assertTrue(isFloat("-145.23"));
assertTrue(isFloat(Long.toString(Integer.MAX_VALUE + 1L)));
}
-
+
@Test
void testParseInt() {
int actual = parseInt("testParseInt", "12");
assertEquals(12, actual);
-
+
this.currentTick = 13;
this.currentSubtick = 1;
- Throwable t = assertThrows(PlaybackLoadException.class, ()->{
+ Throwable t = assertThrows(PlaybackLoadException.class, () -> {
parseInt("testParseInt", "12.1");
});
-
- assertEquals("Line 1, Tick 13, Subtick 1: Can't parse integer in testParseInt", t.getMessage());
+
+ assertEquals("Line 1, Tick 13, Subtick 1: The testParseInt could not be processed. This should be a number: 12.1", t.getMessage());
assertEquals(NumberFormatException.class, t.getCause().getClass());
assertEquals("For input string: \"12.1\"", t.getCause().getMessage());
}
-
+
@Test
void testParseFloat() {
float actual = parseFloat("testParseFloat", "12.1");
assertEquals(12.1f, actual);
-
+
this.currentTick = 15;
this.currentSubtick = 6;
- Throwable t = assertThrows(PlaybackLoadException.class, ()->{
+ Throwable t = assertThrows(PlaybackLoadException.class, () -> {
parseFloat("testParseFloat", "12.123h");
});
-
- assertEquals("Line 1, Tick 15, Subtick 6: Can't parse float in testParseFloat", t.getMessage());
+
+ assertEquals("Line 1, Tick 15, Subtick 6: The testParseFloat could not be processed. This should be a decimal number: 12.123h", t.getMessage());
assertEquals(NumberFormatException.class, t.getCause().getClass());
assertEquals("For input string: \"12.123h\"", t.getCause().getMessage());
}
-
+
@Test
void testDeserialiseRelativeInt() {
int actual = deserialiseRelativeInt("testParseRelativeInt", "12", null);
assertEquals(12, actual);
-
+
actual = deserialiseRelativeInt("test", "~2", 14);
assertEquals(16, actual);
-
+
this.currentTick = 23;
this.currentSubtick = 11;
- Throwable t = assertThrows(PlaybackLoadException.class, ()->{
+ Throwable t = assertThrows(PlaybackLoadException.class, () -> {
deserialiseRelativeInt("testParseRelativeInt", "~12", null);
});
assertEquals("Line 1, Tick 23, Subtick 11: Can't process relative value ~12 in testParseRelativeInt. Previous value for comparing is not available", t.getMessage());
}
-
+
@Test
void testDeserialiseRelativeFloat() {
float actual = deserialiseRelativeFloat("testParseRelativeFloat", "12.2", null);
assertEquals(12.2f, actual);
-
+
actual = deserialiseRelativeFloat("test", "~2.4", 14.4f);
assertEquals(16.8f, actual);
-
+
this.currentTick = 20;
this.currentSubtick = 2;
- Throwable t = assertThrows(PlaybackLoadException.class, ()->{
+ Throwable t = assertThrows(PlaybackLoadException.class, () -> {
deserialiseRelativeFloat("testParseRelativeFloat", "~12.3", null);
});
assertEquals("Line 1, Tick 20, Subtick 2: Can't process relative value ~12.3 in testParseRelativeFloat. Previous value for comparing is not available", t.getMessage());
@@ -1068,6 +1068,5 @@ private ArrayList convertBigArrayListToArrayList(Big
public SerialiserFlavorBase clone() {
return new SerialiserFlavorBaseTest();
}
-
-
+
}