diff --git a/src/main/java/com/minecrafttas/mctcommon/events/EventClient.java b/src/main/java/com/minecrafttas/mctcommon/events/EventClient.java
index 4dee7837..dd6c9cbe 100644
--- a/src/main/java/com/minecrafttas/mctcommon/events/EventClient.java
+++ b/src/main/java/com/minecrafttas/mctcommon/events/EventClient.java
@@ -7,6 +7,7 @@
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.network.NetHandlerPlayClient;
/**
* Contains all events fired on the client side
@@ -59,6 +60,21 @@ public static interface EventDoneLoadingWorld extends EventBase {
public void onDoneLoadingWorld();
}
+ /**
+ * Fired when the player is done loading, after the position has been loaded from the server side
+ * @author Scribble
+ * @see NetHandlerPlayClient#handlePlayerPosLook(net.minecraft.network.play.server.SPacketPlayerPosLook)
+ */
+ @FunctionalInterface
+ public static interface EventDoneLoadingPlayer extends EventBase {
+
+ /**
+ * Fired when the player is done loading, after the position has been loaded from the server side
+ * @see NetHandlerPlayClient#handlePlayerPosLook(net.minecraft.network.play.server.SPacketPlayerPosLook)
+ */
+ public void onDoneLoadingPlayer();
+ }
+
/**
* Fired when the client ticks
* @author Scribble
diff --git a/src/main/java/com/minecrafttas/tasmod/handlers/LoadingScreenHandler.java b/src/main/java/com/minecrafttas/tasmod/handlers/LoadingScreenHandler.java
index 7d164842..3cc890c9 100644
--- a/src/main/java/com/minecrafttas/tasmod/handlers/LoadingScreenHandler.java
+++ b/src/main/java/com/minecrafttas/tasmod/handlers/LoadingScreenHandler.java
@@ -3,12 +3,15 @@
import static com.minecrafttas.tasmod.TASmod.LOGGER;
import com.minecrafttas.mctcommon.events.EventClient.EventClientGameLoop;
+import com.minecrafttas.mctcommon.events.EventClient.EventDoneLoadingPlayer;
import com.minecrafttas.mctcommon.events.EventClient.EventDoneLoadingWorld;
import com.minecrafttas.mctcommon.events.EventClient.EventLaunchIntegratedServer;
import com.minecrafttas.tasmod.TASmod;
import com.minecrafttas.tasmod.TASmodClient;
+import com.minecrafttas.tasmod.mixin.playbackhooks.MixinEntityRenderer;
import com.minecrafttas.tasmod.playback.PlaybackControllerClient;
import com.minecrafttas.tasmod.util.LoggerMarkers;
+import com.minecrafttas.tasmod.virtual.VirtualInput;
import net.minecraft.client.Minecraft;
@@ -17,7 +20,7 @@
*
* @author Scribble
*/
-public class LoadingScreenHandler implements EventLaunchIntegratedServer, EventClientGameLoop, EventDoneLoadingWorld {
+public class LoadingScreenHandler implements EventLaunchIntegratedServer, EventClientGameLoop, EventDoneLoadingWorld, EventDoneLoadingPlayer {
private boolean waszero;
private boolean isLoading;
@@ -62,7 +65,6 @@ public void onDoneLoadingWorld() {
LOGGER.debug(LoggerMarkers.Event, "Finished loading the world on the client");
loadingScreenDelay = 1;
- TASmodClient.virtual.clear();
}
}
@@ -70,4 +72,25 @@ public boolean isLoading() {
return isLoading;
}
+ /**
+ * {@inheritDoc}
+ *
+ *
Fixes an issue, where the look position of the player is reset to 0 -180,
+ * As well as removing any keyboard inputs present in the main menu
+ *
+ *
{@link MixinEntityRenderer#runUpdate(float)} rewrites the camera input,
+ * So that it can be used with interpolation.
+ * However, when you start the game, this camera input needs to be initialised with the current look position from the server.
+ * So a special condition is set, that if the {@link VirtualInput#CAMERA_ANGLE} is null,
+ * it intialises the {@link VirtualInput#CAMERA_ANGLE CAMERA_ANGLE} with the current player camera angle.
+ *
+ *
So {@link VirtualInput#clear()} has to be called at the right moment in the player initialisation
+ * to set the correct values. Before that, the playerRotation defaults to 0 -180
+ */
+ @Override
+ public void onDoneLoadingPlayer() {
+ LOGGER.debug(LoggerMarkers.Event, "Finished loading the player position on the client");
+ TASmodClient.virtual.clear();
+ }
+
}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinNetHandlerPlayClient.java b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinNetHandlerPlayClient.java
new file mode 100644
index 00000000..c11ed085
--- /dev/null
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/events/MixinNetHandlerPlayClient.java
@@ -0,0 +1,20 @@
+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.EventClient.EventDoneLoadingPlayer;
+import com.minecrafttas.mctcommon.events.EventListenerRegistry;
+
+import net.minecraft.client.network.NetHandlerPlayClient;
+
+@Mixin(NetHandlerPlayClient.class)
+public class MixinNetHandlerPlayClient {
+
+ @Inject(method = "handlePlayerPosLook", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;displayGuiScreen(Lnet/minecraft/client/gui/GuiScreen;)V"))
+ public void event_handlePlayerPosLook(CallbackInfo ci) {
+ EventListenerRegistry.fireEvent(EventDoneLoadingPlayer.class);
+ }
+}
diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinWorldServer.java b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinWorldServer.java
index 5572281b..c3f8b06b 100644
--- a/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinWorldServer.java
+++ b/src/main/java/com/minecrafttas/tasmod/mixin/savestates/MixinWorldServer.java
@@ -17,7 +17,7 @@
* @author Scribble
*/
@Mixin(WorldServer.class)
-public abstract class MixinWorldServer implements WorldServerDuck {
+public class MixinWorldServer implements WorldServerDuck {
@Shadow
private PlayerChunkMap playerChunkMap;
diff --git a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java
index 4d372071..90e3681d 100644
--- a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java
+++ b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java
@@ -539,12 +539,7 @@ public void setInputs(BigArrayList inputs) {
}
public void setInputs(BigArrayList inputs, long index) {
- try {
- this.inputs.clearMemory();
- } catch (IOException e) {
- e.printStackTrace();
- }
- this.inputs = new BigArrayList(tasFileDirectory + File.separator + "temp");
+ clearInputList();
SerialiserFlavorBase.addAll(this.inputs, inputs);
setIndex(index);
}
@@ -582,14 +577,19 @@ public InputContainer get() {
public void clear() {
LOGGER.info(LoggerMarkers.Playback, "Clearing playback controller");
+ clearInputList();
EventListenerRegistry.fireEvent(EventPlaybackClient.EventRecordClear.class);
+
+ index = 0;
+ }
+
+ private void clearInputList() {
try {
inputs.clearMemory();
} catch (IOException e) {
e.printStackTrace();
}
inputs = new BigArrayList(tasFileDirectory + File.separator + "temp");
- index = 0;
}
/**
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java
index 7a4764d3..63703a1a 100644
--- a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerClient.java
@@ -2,9 +2,10 @@
import static com.minecrafttas.tasmod.TASmod.LOGGER;
-import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
import com.dselent.bigarraylist.BigArrayList;
import com.minecrafttas.mctcommon.events.EventListenerRegistry;
@@ -50,7 +51,7 @@
*/
public class SavestateHandlerClient implements ClientPacketHandler, EventSavestate.EventClientCompleteLoadstate, EventSavestate.EventClientLoadPlayer {
- public final static File savestateDirectory = TASmodClient.savestatedirectory.toFile(); //TODO Change to path... don't want to deal with this rn ._.
+ public final static Path clientSavestateDirectory = TASmodClient.tasfiledirectory.resolve("savestates");
/**
* A bug occurs when unloading the client world. The client world has a
@@ -122,15 +123,15 @@ public static void savestate(String nameOfSavestate) throws SavestateException,
return;
}
- SavestateHandlerClient.savestateDirectory.mkdir();
+ createClientSavestateDirectory();
- File targetfile = new File(SavestateHandlerClient.savestateDirectory, nameOfSavestate + ".mctas");
+ Path targetfile = clientSavestateDirectory.resolve(nameOfSavestate + ".mctas");
PlaybackControllerClient container = TASmodClient.controller;
if (container.isRecording()) {
- PlaybackSerialiser.saveToFile(targetfile.toPath(), container, ""); // If the container is recording, store it entirely
+ PlaybackSerialiser.saveToFile(targetfile, container, ""); // If the container is recording, store it entirely
} else if (container.isPlayingback()) {
- PlaybackSerialiser.saveToFile(targetfile.toPath(), container, "", container.index()); // If the container is playing, store it until the current index
+ PlaybackSerialiser.saveToFile(targetfile, container, "", container.index()); // If the container is playing, store it until the current index
}
}
@@ -150,13 +151,14 @@ public static void loadstate(String nameOfSavestate) throws Exception {
return;
}
- savestateDirectory.mkdir();
-
PlaybackControllerClient controller = TASmodClient.controller;
TASstate state = controller.getState();
if (state == TASstate.NONE) {
+ TASmodClient.tickSchedulerClient.add(() -> {
+ EventListenerRegistry.fireEvent(EventSavestate.EventClientCompleteLoadstate.class);
+ });
return;
}
@@ -164,12 +166,12 @@ public static void loadstate(String nameOfSavestate) throws Exception {
state = controller.getStateAfterPause();
}
- File targetfile = new File(savestateDirectory, nameOfSavestate + ".mctas");
+ Path targetfile = clientSavestateDirectory.resolve(nameOfSavestate + ".mctas");
BigArrayList savestateContainerList;
- if (targetfile.exists()) {
- savestateContainerList = PlaybackSerialiser.loadFromFile(targetfile.toPath(), state != TASstate.PLAYBACK);
+ if (Files.exists(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,"));
@@ -199,12 +201,14 @@ public static void loadstate(String nameOfSavestate) throws Exception {
if (state == TASstate.RECORDING) {
long index = savestateContainerList.size() - 1;
+ preload(savestateContainerList, index);
controller.setInputs(savestateContainerList, index);
-
- /*
- * When loading a savestate during a playback 2 different scenarios can happen.
- * */
- } else if (state == TASstate.PLAYBACK) {
+ TASmodClient.virtual.clear();
+ }
+ /*
+ * When loading a savestate during a playback 2 different scenarios can happen.
+ */
+ else if (state == TASstate.PLAYBACK) {
/*
* Scenario 1:
@@ -233,6 +237,7 @@ public static void loadstate(String nameOfSavestate) throws Exception {
preload(controller.getInputs(), index);
controller.setIndex(index);
+ TASmodClient.virtual.clear();
}
/*
* Scenario 2:
@@ -254,7 +259,13 @@ public static void loadstate(String nameOfSavestate) throws Exception {
});
}
+ private static void createClientSavestateDirectory() throws IOException {
+ LOGGER.trace(LoggerMarkers.Savestate, "Creating savestate directory at {}", clientSavestateDirectory);
+ Files.createDirectories(clientSavestateDirectory);
+ }
+
private static void preload(BigArrayList containerList, long index) {
+ LOGGER.trace(LoggerMarkers.Savestate, "Preloading container at index {}", index);
InputContainer containerToPreload = containerList.get(index);
TASmodClient.virtual.preloadInput(containerToPreload.getKeyboard(), containerToPreload.getMouse(), containerToPreload.getCameraAngle());
@@ -289,8 +300,8 @@ public static void loadPlayer(NBTTagCompound compound) {
double z = player.motionZ;
float rx = player.moveForward;
- float ry = player.moveStrafing;
- float rz = player.moveVertical;
+ float ry = player.moveVertical;
+ float rz = player.moveStrafing;
boolean sprinting = player.isSprinting();
float jumpVector = player.jumpMovementFactor;
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java
index fdb69c59..e7d5b18b 100644
--- a/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java
@@ -410,12 +410,17 @@ public void loadState(int savestateIndex, boolean tickrate0, boolean changeIndex
TASmod.tickratechanger.pauseGame(false);
}
+ // Unlock savestating
+ state = SavestateState.NONE;
+
+ /*
+ * TODO Savestates can be reloaded without a tick passing...
+ * And since this scheduler is not cleared, it would execute the same task multiple times in the next tick
+ * Rn it's not a problem, but this should be looked at...
+ */
TASmod.tickSchedulerServer.add(() -> {
EventListenerRegistry.fireEvent(EventSavestate.EventServerCompleteLoadstate.class);
onLoadstateComplete();
-
- // Unlock savestating
- state = SavestateState.NONE;
});
}
diff --git a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateWorldHandler.java b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateWorldHandler.java
index ad117d1f..33694a9c 100644
--- a/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateWorldHandler.java
+++ b/src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateWorldHandler.java
@@ -239,6 +239,7 @@ public void loadAllWorlds(String string, String string2) {
}
server.worlds[i].addEventListener(new ServerWorldEventHandler(server, server.worlds[i]));
+ server.worlds[i].tick(); // TODO I give up...
}
server.getPlayerList().setPlayerManager(server.worlds);
diff --git a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualCameraAngle.java b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualCameraAngle.java
index 60558537..5dc7264c 100644
--- a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualCameraAngle.java
+++ b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualCameraAngle.java
@@ -133,7 +133,7 @@ public void set(float pitch, float yaw) {
public void getStates(List reference) {
if (isParent()) {
reference.addAll(subtickList);
- reference.add(this);
+ reference.add(this.shallowClone()); // Fixes a crash where "this" can become null in the reference.
}
}
diff --git a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java
index 1dbf2a04..440074af 100644
--- a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java
+++ b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java
@@ -141,11 +141,19 @@ public void clear() {
}
public void preloadInput(VirtualKeyboard keyboardToPreload, VirtualMouse mouseToPreload, VirtualCameraAngle angleToPreload) {
+ // Preload the nextKeyboard
KEYBOARD.nextKeyboard.deepCopyFrom(keyboardToPreload);
MOUSE.nextMouse.deepCopyFrom(mouseToPreload);
CAMERA_ANGLE.nextCameraAngle.deepCopyFrom(angleToPreload);
+
+ // Preload the currentKeyboard
+ KEYBOARD.nextKeyboardTick();
+ MOUSE.nextMouseTick();
+
+ // Preload vanilla inputs
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);
}
@@ -262,7 +270,7 @@ public void updateNextKeyboard(int keycode, boolean keystate, char character) {
* @param repeatEventsEnabled If repeat events are enabled
*/
public void updateNextKeyboard(int keycode, boolean keystate, char character, boolean repeatEventsEnabled) {
- LOGGER.debug(LoggerMarkers.Keyboard, "Update: {}, {}, {}, {}", keycode, keystate, character); // Activate with -Dtasmod.marker.keyboard=ACCEPT in VM arguments (and -Dtasmod.log.level=debug)
+ LOGGER.debug(LoggerMarkers.Keyboard, "Update: {}, {}, {}", keycode, keystate, character); // Activate with -Dtasmod.marker.keyboard=ACCEPT in VM arguments (and -Dtasmod.log.level=debug)
nextKeyboard.updateFromEvent(keycode, keystate, character, repeatEventsEnabled);
}
@@ -277,6 +285,7 @@ public void nextKeyboardTick() {
nextKeyboard.deepCopyFrom((VirtualKeyboard) EventListenerRegistry.fireEvent(EventVirtualInput.EventVirtualKeyboardTick.class, nextKeyboard));
currentKeyboard.getVirtualEvents(nextKeyboard, keyboardEventQueue);
currentKeyboard.moveFrom(nextKeyboard);
+ LOGGER.debug(LoggerMarkers.Keyboard, "KeyboardTick: {}", currentKeyboard); // Activate with -Dtasmod.marker.keyboard=ACCEPT in VM arguments (and -Dtasmod.log.level=debug)
}
/**
@@ -693,8 +702,10 @@ public Triple getInterpolatedState(float partialTick, float
if (enable && !cameraAngleInterpolationStates.isEmpty()) {
int index = (int) MathHelper.clampedLerp(0, cameraAngleInterpolationStates.size() - 1, partialTick); // Get interpolate index
- interpolatedPitch = cameraAngleInterpolationStates.get(index).getPitch();
- interpolatedYaw = cameraAngleInterpolationStates.get(index).getYaw() + 180;
+ VirtualCameraAngle interpolatedCamera = cameraAngleInterpolationStates.get(index);
+
+ interpolatedPitch = interpolatedCamera.getPitch();
+ interpolatedYaw = interpolatedCamera.getYaw() + 180;
}
return Triple.of(interpolatedPitch, interpolatedYaw, 0f);
diff --git a/src/main/resources/tasmod.mixin.json b/src/main/resources/tasmod.mixin.json
index ed795f87..7c67b9f2 100644
--- a/src/main/resources/tasmod.mixin.json
+++ b/src/main/resources/tasmod.mixin.json
@@ -43,6 +43,7 @@
// Events
"events.MixinGuiIngame",
"events.MixinEntityRenderer",
+ "events.MixinNetHandlerPlayClient",
"clientcommands.MixinEntityPlayerSP",
"clientcommands.MixinTabCompleter",