From 8001f4badd9eef515828448e127c1c7a2cd251ec Mon Sep 17 00:00:00 2001 From: Scribble Date: Fri, 13 Dec 2024 13:50:05 +0100 Subject: [PATCH] [Savestates] Finish implementing player motion --- .../mctcommon/file/AbstractDataFile.java | 3 +- .../java/com/minecrafttas/tasmod/TASmod.java | 6 +- .../com/minecrafttas/tasmod/TASmodClient.java | 2 + .../savestates/SavestateHandlerClient.java | 60 ++++---- .../savestates/SavestateHandlerServer.java | 3 - .../exceptions/LoadstateException.java | 6 +- .../handlers/SavestatePlayerHandler.java | 1 - .../storage/SavestateMotionStorage.java | 128 +++++++++++++----- 8 files changed, 140 insertions(+), 69 deletions(-) diff --git a/src/main/java/com/minecrafttas/mctcommon/file/AbstractDataFile.java b/src/main/java/com/minecrafttas/mctcommon/file/AbstractDataFile.java index b0779dc6..9929075d 100644 --- a/src/main/java/com/minecrafttas/mctcommon/file/AbstractDataFile.java +++ b/src/main/java/com/minecrafttas/mctcommon/file/AbstractDataFile.java @@ -7,7 +7,6 @@ import java.lang.reflect.Type; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardOpenOption; import java.util.InvalidPropertiesFormatException; import java.util.Map.Entry; import java.util.Properties; @@ -199,7 +198,7 @@ public void saveToJson(Path file) { //@formatter:on try { String element = json.toJson(properties); - Files.write(file, element.getBytes(), StandardOpenOption.WRITE, StandardOpenOption.CREATE); + Files.write(file, element.getBytes()); } catch (IOException e) { MCTCommon.LOGGER.catching(e); } diff --git a/src/main/java/com/minecrafttas/tasmod/TASmod.java b/src/main/java/com/minecrafttas/tasmod/TASmod.java index 0b8f354a..a495dfad 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmod.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmod.java @@ -114,6 +114,9 @@ public void onInitialize() { PacketHandlerRegistry.register(startPositionMetadataExtension); PacketHandlerRegistry.register(tabCompletionUtils); PacketHandlerRegistry.register(commandFileCommand); + SavestateMotionStorage motionStorage = new SavestateMotionStorage(); + PacketHandlerRegistry.register(motionStorage); + EventListenerRegistry.register(motionStorage); } @Override @@ -141,8 +144,6 @@ public void onServerInit(MinecraftServer server) { PacketHandlerRegistry.register(savestateHandlerServer); PacketHandlerRegistry.register(savestateHandlerServer.getPlayerHandler()); - EventListenerRegistry.register(savestateHandlerServer.getPlayerHandler()); - if (!server.isDedicatedServer()) { TASmod.tickratechanger.ticksPerSecond = 0F; TASmod.tickratechanger.tickrateSaved = 20F; @@ -174,7 +175,6 @@ public void onServerStop(MinecraftServer mcserver) { PacketHandlerRegistry.unregister(savestateHandlerServer); // Unregistering the savestatehandler, as a new instance is registered in onServerStart() PacketHandlerRegistry.unregister(savestateHandlerServer.getPlayerHandler()); - EventListenerRegistry.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 28fe558f..04382371 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmodClient.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmodClient.java @@ -36,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; @@ -150,6 +151,7 @@ private void registerNetworkPacketHandlers() { PacketHandlerRegistry.register(ticksyncClient); PacketHandlerRegistry.register(tickratechanger); PacketHandlerRegistry.register(savestateHandlerClient); + PacketHandlerRegistry.register(new SavestatePlayerHandler(null)); } private void registerEventListeners() { diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java index bbf21857..159a5259 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java @@ -269,32 +269,44 @@ public static void loadPlayer(NBTTagCompound compound) { // 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 diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java index 58ea4d4b..fdb69c59 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java @@ -168,9 +168,6 @@ public void saveState(int savestateIndex, boolean tickrate0, boolean changeIndex // Enable tickrate 0 TASmod.tickratechanger.pauseGame(true); - // Get the motion from the client - playerHandler.requestMotionFromClient(); - // Save the world! server.getPlayerList().saveAllPlayerData(); server.saveAllWorlds(false); 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/handlers/SavestatePlayerHandler.java b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandler.java index 78afaddb..cdab03e2 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandler.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestatePlayerHandler.java @@ -189,7 +189,6 @@ public PacketID[] getAcceptedPacketIDs() { @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_PLAYER: diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateMotionStorage.java b/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateMotionStorage.java index f49e670d..c79ec326 100644 --- a/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateMotionStorage.java +++ b/src/main/java/com/minecrafttas/tasmod/savestates/storage/SavestateMotionStorage.java @@ -2,16 +2,18 @@ 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.nio.file.StandardOpenOption; 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; @@ -19,7 +21,8 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; +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; @@ -31,6 +34,7 @@ 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; @@ -41,6 +45,7 @@ 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 { @@ -72,12 +77,18 @@ public void onServerSavestate(MinecraftServer server, int index, Path target, Pa e.printStackTrace(); } - JsonArray playerJsonArray = new JsonArray(); + JsonObject playerJsonObject = new JsonObject(); futures.forEach((player, future) -> { try { MotionData data = future.get(5L, TimeUnit.SECONDS); - playerJsonArray.add(json.toJsonTree(data)); + + 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) { @@ -85,15 +96,16 @@ public void onServerSavestate(MinecraftServer server, int index, Path target, Pa } }); - saveMotionData(current, playerJsonArray); + saveJson(current, playerJsonObject); } - private void saveMotionData(Path current, JsonArray playerJsonArray) { + private void saveJson(Path current, JsonObject data) { Path saveFile = current.resolve(SavestateHandlerServer.storageDir).resolve(fileName); - String out = json.toJson(playerJsonArray); + + String out = json.toJson(data); try { - Files.write(saveFile, out.getBytes(), StandardOpenOption.WRITE, StandardOpenOption.CREATE); + Files.write(saveFile, out.getBytes()); } catch (IOException e) { throw new SavestateException(e, "Could not write to the file system"); } @@ -101,27 +113,62 @@ private void saveMotionData(Path current, JsonArray playerJsonArray) { @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 MotionData loadMotionData(Path saveData) { - return null; + 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 }; + 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: - Minecraft mc = Minecraft.getMinecraft(); - EntityPlayerSP player = mc.player; + if (player != null) { if (!(mc.currentScreen instanceof GuiSavestateSavingScreen)) { mc.displayGuiScreen(new GuiSavestateSavingScreen()); @@ -142,7 +189,19 @@ public void onClientPacket(PacketID id, ByteBuffer buf, String username) throws } 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; @@ -169,24 +228,24 @@ public void onServerPacket(PacketID id, ByteBuffer buf, String username) throws public static class MotionData { - private double clientX; - private double clientY; - private double clientZ; - private float clientrX; - private float clientrY; - private float clientrZ; + private double motionX; + private double motionY; + private double motionZ; + private float deltaX; + private float deltaY; + private float deltaZ; private boolean sprinting; - private float jumpMovementVector; + private float jumpMovementFactor; 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; + motionX = x; + motionY = y; + motionZ = z; + deltaX = rx; + deltaY = ry; + deltaZ = rz; this.sprinting = sprinting; - this.jumpMovementVector = jumpMovementVector; + this.jumpMovementFactor = jumpMovementVector; } public MotionData() { @@ -194,27 +253,27 @@ public MotionData() { } public double getClientX() { - return clientX; + return motionX; } public double getClientY() { - return clientY; + return motionY; } public double getClientZ() { - return clientZ; + return motionZ; } public float getClientrX() { - return clientrX; + return deltaX; } public float getClientrY() { - return clientrY; + return deltaY; } public float getClientrZ() { - return clientrZ; + return deltaZ; } public boolean isSprinting() { @@ -222,8 +281,7 @@ public boolean isSprinting() { } public float getJumpMovementVector() { - return jumpMovementVector; + return jumpMovementFactor; } } - }