From 09aa71c0c500de3ed09982c4aa8e80d7af4e2bac Mon Sep 17 00:00:00 2001 From: Scribble Date: Sat, 7 Jun 2025 15:43:33 +0200 Subject: [PATCH 1/9] [InfoHud] Add current mouse pointer This implementation is technically not correct and will be fixed once a rewrite of the VirtualInput#VirtualMouseInput is done --- .../com/minecrafttas/tasmod/gui/InfoHud.java | 25 +++++++++++++------ .../tasmod/virtual/VirtualInput.java | 8 ++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java index 12e7a38e..715d6847 100644 --- a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java +++ b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java @@ -378,13 +378,24 @@ public boolean checkInit() { } })); - // 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 = "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"; + + Integer xCursor = TASmodClient.virtual.getPointerX(); + Integer yCursor = TASmodClient.virtual.getPointerY(); + + if (Minecraft.getMinecraft().currentScreen != null) + return String.format("Mouse Cursor: %s %s", xCursor == null ? "null" : xCursor, yCursor == null ? "null" : yCursor); + else + return "Mouse Cursor: 0 0"; + + })); // title = "trajectories"; // y += 14; diff --git a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java index ff615b56..4da8847e 100644 --- a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java +++ b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java @@ -172,6 +172,14 @@ public List getCurrentKeyboardPresses() { public List getNextKeyboardPresses() { return KEYBOARD.nextKeyboard.getCurrentPresses(); } + + public int getPointerX() { + return MOUSE.nextMouse.getCursorX(); + } + + public int getPointerY() { + return MOUSE.nextMouse.getCursorY(); + } /** * Subclass of {@link VirtualInput} handling keyboard logic.
From 30970a4a474738a152193c9ff65efbd7a2bdb0b1 Mon Sep 17 00:00:00 2001 From: Scribble Date: Mon, 9 Jun 2025 21:01:54 +0200 Subject: [PATCH 2/9] [VirtualInput] Add mouse pointer interpolation --- .../com/minecrafttas/tasmod/gui/InfoHud.java | 4 +- .../playbackhooks/MixinEntityRenderer.java | 12 +++ .../mixin/playbackhooks/MixinGuiScreen.java | 7 ++ .../playback/PlaybackControllerClient.java | 32 ++------ .../tasmod/virtual/VirtualInput.java | 79 ++++++++++++++++--- .../tasmod/virtual/VirtualMouse.java | 7 ++ 6 files changed, 102 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java index 715d6847..cae09289 100644 --- a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java +++ b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java @@ -387,8 +387,8 @@ public boolean checkInit() { if (Minecraft.getMinecraft().currentScreen == this) return "Mouse Position"; - Integer xCursor = TASmodClient.virtual.getPointerX(); - Integer yCursor = TASmodClient.virtual.getPointerY(); + Integer xCursor = TASmodClient.virtual.MOUSE.getInterpolatedX(0, false); + Integer yCursor = TASmodClient.virtual.MOUSE.getInterpolatedY(0, false); if (Minecraft.getMinecraft().currentScreen != null) return String.format("Mouse Cursor: %s %s", xCursor == null ? "null" : xCursor, yCursor == null ? "null" : yCursor); 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 daf1f405..7002ae46 100644 --- a/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java +++ b/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java @@ -211,4 +211,16 @@ private float redirectCam(float pitch, float yaw) { // Update yaw return yaw2; } + + @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getX()I")) + public int redirect_updateCameraAndRendererX() { + int interpolatedX = TASmodClient.virtual.MOUSE.getInterpolatedX(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback()); + return interpolatedX; + } + + @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getY()I")) + public int redirect_updateCameraAndRendererY() { + int interpolatedY = TASmodClient.virtual.MOUSE.getInterpolatedY(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback()); + return interpolatedY; + } } diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinGuiScreen.java b/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinGuiScreen.java index d4bb0893..7702333d 100644 --- a/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinGuiScreen.java +++ b/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinGuiScreen.java @@ -3,7 +3,9 @@ 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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.minecrafttas.tasmod.TASmodClient; import com.minecrafttas.tasmod.util.Ducks.GuiScreenDuck; @@ -103,6 +105,11 @@ private static boolean redirectIsAltKeyDown(int i) { // ===================================================================================================================================== + @Inject(method = "drawScreen", at = @At("HEAD")) + private void injectDrawScreen(int i, int j, float f, CallbackInfo ci) { + TASmodClient.controller.onDrawScreen((GuiScreen) (Object) this, i, j); // TODO Replace with event + } + @Shadow private int width; diff --git a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java index b275a921..27a433e9 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java @@ -55,14 +55,12 @@ import com.minecrafttas.tasmod.registries.TASmodPackets; import com.minecrafttas.tasmod.util.Ducks.GuiScreenDuck; import com.minecrafttas.tasmod.util.LoggerMarkers; -import com.minecrafttas.tasmod.util.PointerNormalizer; import com.minecrafttas.tasmod.util.Scheduler.Task; import com.minecrafttas.tasmod.virtual.VirtualCameraAngle; import com.minecrafttas.tasmod.virtual.VirtualInput; import com.minecrafttas.tasmod.virtual.VirtualInput.VirtualCameraAngleInput; import com.minecrafttas.tasmod.virtual.VirtualKeyboard; import com.minecrafttas.tasmod.virtual.VirtualMouse; -import com.minecrafttas.tasmod.virtual.event.VirtualMouseEvent; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityPlayerSP; @@ -100,9 +98,8 @@ public class PlaybackControllerClient implements EventVirtualInput.EventVirtualKeyboardTick, EventVirtualInput.EventVirtualMouseTick, - EventVirtualInput.EventVirtualCameraAngleTick, + EventVirtualInput.EventVirtualCameraAngleTick - EventVirtualInput.EventVirtualMouseSubtick //@formatter:on { private Logger logger = TASmod.LOGGER; @@ -406,35 +403,16 @@ public VirtualCameraAngle onVirtualCameraTick(VirtualCameraAngle vcamera) { /** * Updates the cursor location on screen */ - @Override - public void onVirtualMouseSubtick(VirtualMouseEvent event) { - if (!isPlayingback() || event == null) + public void onDrawScreen(GuiScreen screen, int x, int y) { + if (!isPlayingback()) return; Minecraft mc = Minecraft.getMinecraft(); if (!mc.gameSettings.pauseOnLostFocus && !Display.isActive()) // If pause on lost focus is on and the display is not active don't set the cursor position return; - GuiScreen screen = mc.currentScreen; - if (screen == null) - return; - - GuiScreenDuck duckedScreen = (GuiScreenDuck) mc.currentScreen; - //@formatter:off - Mouse.setCursorPosition( - duckedScreen.rescaleX( - PointerNormalizer.reapplyScalingX( - event.getCursorX() - ) - ), - duckedScreen.rescaleY( - PointerNormalizer.reapplyScalingY( - event.getCursorY() - ) - - ) - ); - //@formatter:on + GuiScreenDuck duckedScreen = (GuiScreenDuck) screen; + Mouse.setCursorPosition(duckedScreen.rescaleX(x), duckedScreen.rescaleY(y)); } /** diff --git a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java index 4da8847e..17b50fa5 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.GuiScreenDuck; import com.minecrafttas.tasmod.util.Ducks.SubtickDuck; import com.minecrafttas.tasmod.util.LoggerMarkers; import com.minecrafttas.tasmod.util.PointerNormalizer; @@ -172,14 +173,6 @@ public List getCurrentKeyboardPresses() { public List getNextKeyboardPresses() { return KEYBOARD.nextKeyboard.getCurrentPresses(); } - - public int getPointerX() { - return MOUSE.nextMouse.getCursorX(); - } - - public int getPointerY() { - return MOUSE.nextMouse.getCursorY(); - } /** * Subclass of {@link VirtualInput} handling keyboard logic.
@@ -303,7 +296,11 @@ public void nextKeyboardTick() { * @return If a keyboard event is in {@link #keyboardEventQueue} */ public boolean nextKeyboardSubtick() { - boolean isPolled = (currentKeyboardEvent = keyboardEventQueue.poll()) != null; + VirtualKeyboardEvent newKeyboardEvent = keyboardEventQueue.poll(); + boolean isPolled = newKeyboardEvent != null; + if (isPolled) { + currentKeyboardEvent = newKeyboardEvent; + } EventListenerRegistry.fireEvent(EventVirtualInput.EventVirtualKeyboardSubtick.class, currentKeyboardEvent); return isPolled; } @@ -428,6 +425,8 @@ public class VirtualMouseInput { */ private VirtualMouseEvent currentMouseEvent = new VirtualMouseEvent(); + private final List mousePointerInterpolationStates = new ArrayList<>(); + /** * Constructor to preload the {@link #currentMouse} with an existing mouse * @param preloadedMouse The new {@link #currentMouse} @@ -460,6 +459,8 @@ public void updateNextMouse(int keycode, boolean keystate, int scrollwheel, int */ public void nextMouseTick() { nextMouse.deepCopyFrom((VirtualMouse) EventListenerRegistry.fireEvent(EventVirtualInput.EventVirtualMouseTick.class, nextMouse)); + mousePointerInterpolationStates.clear(); + nextMouse.getStates(mousePointerInterpolationStates); currentMouse.getVirtualEvents(nextMouse, mouseEventQueue); currentMouse.moveFrom(nextMouse); } @@ -472,7 +473,11 @@ public void nextMouseTick() { * @return If a mouse event is in {@link #mouseEventQueue} */ public boolean nextMouseSubtick() { - boolean isPolled = (currentMouseEvent = mouseEventQueue.poll()) != null; + VirtualMouseEvent newMouseEvent = mouseEventQueue.poll(); + boolean isPolled = newMouseEvent != null; + if (isPolled) { + currentMouseEvent = newMouseEvent; + } EventListenerRegistry.fireEvent(EventVirtualInput.EventVirtualMouseSubtick.class, currentMouseEvent); return isPolled; } @@ -545,6 +550,60 @@ public boolean willKeyBeDown(int keycode) { return nextMouse.isKeyDown(keycode); } + /** + * Gets the absolute coordinates of the camera angle + * + * @param partialTick The partial ticks of the timer + * @param pitch The original pitch of the camera + * @param yaw The original yaw of the camera + * @param enable Whether the custom interpolation is enabled. Enabled during playback. + * @return A triple of pitch, yaw and roll, as left, middle and right respectively + */ + public int getInterpolatedX(float partialTick, boolean enable) { + + int interpolatedPointerX = nextMouse.getCursorX(); + + if (enable && !mousePointerInterpolationStates.isEmpty()) { + int index = (int) MathHelper.clampedLerp(0, mousePointerInterpolationStates.size() - 1, partialTick); // Get interpolate index + + VirtualMouse interpolatedCamera = mousePointerInterpolationStates.get(index); + + interpolatedPointerX = interpolatedCamera.getCursorX(); + + } + Minecraft mc = Minecraft.getMinecraft(); + GuiScreenDuck gui = (GuiScreenDuck) mc.currentScreen; + + if (gui != null) { + interpolatedPointerX = gui.rescaleX(PointerNormalizer.reapplyScalingX(interpolatedPointerX)); + } + + return interpolatedPointerX; + } + + public int getInterpolatedY(float partialTick, boolean enable) { + + int interpolatedPointerY = nextMouse.getCursorY(); + + if (enable && !mousePointerInterpolationStates.isEmpty()) { + int index = (int) MathHelper.clampedLerp(0, mousePointerInterpolationStates.size() - 1, partialTick); // Get interpolate index + + VirtualMouse interpolatedCamera = mousePointerInterpolationStates.get(index); + + interpolatedPointerY = interpolatedCamera.getCursorY(); + + } + + Minecraft mc = Minecraft.getMinecraft(); + GuiScreenDuck gui = (GuiScreenDuck) mc.currentScreen; + + if (gui != null) { + interpolatedPointerY = gui.rescaleY(PointerNormalizer.reapplyScalingY(interpolatedPointerY)); + } + + return interpolatedPointerY; + } + /** * Clears the {@link #nextMouse} */ diff --git a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualMouse.java b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualMouse.java index 76bfc0f0..1a475b77 100644 --- a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualMouse.java +++ b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualMouse.java @@ -358,4 +358,11 @@ public int getCursorY() { public boolean isEmpty() { return super.isEmpty() && scrollWheel == 0 && cursorX == 0 && cursorY == 0; } + + public void getStates(List reference) { + if (isParent()) { + reference.addAll(subtickList); + reference.add(this.shallowClone()); + } + } } From a4f3e6bdaeffb8a2a39e0d82c4250510d8fe5b53 Mon Sep 17 00:00:00 2001 From: Scribble Date: Thu, 19 Jun 2025 21:46:15 +0200 Subject: [PATCH 3/9] [VirtualInput] Fix build throwing an error --- .../mixin/playbackhooks/MixinEntityRenderer.java | 4 ++-- .../playback/PlaybackControllerClient.java | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) 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 7002ae46..49ab559c 100644 --- a/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java +++ b/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java @@ -212,13 +212,13 @@ private float redirectCam(float pitch, float yaw) { return yaw2; } - @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getX()I")) + @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getX()I", remap = false)) public int redirect_updateCameraAndRendererX() { int interpolatedX = TASmodClient.virtual.MOUSE.getInterpolatedX(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback()); return interpolatedX; } - @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getY()I")) + @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getY()I", remap = false)) public int redirect_updateCameraAndRendererY() { int interpolatedY = TASmodClient.virtual.MOUSE.getInterpolatedY(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback()); return interpolatedY; diff --git a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java index 27a433e9..11b2c1df 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java @@ -371,23 +371,23 @@ public TASstate getStateAfterPause() { // running @Override - public VirtualMouse onVirtualMouseTick(VirtualMouse vmouse) { + public VirtualKeyboard onVirtualKeyboardTick(VirtualKeyboard vkeyboard) { if (state == TASstate.RECORDING) { - this.mouse.deepCopyFrom(vmouse); + this.keyboard.deepCopyFrom(vkeyboard); } else if (state == TASstate.PLAYBACK) { - vmouse.deepCopyFrom(this.mouse); + vkeyboard.deepCopyFrom(this.keyboard); } - return vmouse.clone(); + return vkeyboard.clone(); } @Override - public VirtualKeyboard onVirtualKeyboardTick(VirtualKeyboard vkeyboard) { + public VirtualMouse onVirtualMouseTick(VirtualMouse vmouse) { if (state == TASstate.RECORDING) { - this.keyboard.deepCopyFrom(vkeyboard); + this.mouse.deepCopyFrom(vmouse); } else if (state == TASstate.PLAYBACK) { - vkeyboard.deepCopyFrom(this.keyboard); + vmouse.deepCopyFrom(this.mouse); } - return vkeyboard.clone(); + return vmouse.clone(); } @Override From 9456f94b24f5ecc653d9702236b4312620839084 Mon Sep 17 00:00:00 2001 From: Scribble Date: Fri, 20 Jun 2025 22:13:46 +0200 Subject: [PATCH 4/9] [InfoHud] Fix green keystrokes during playback not being correct - [PlaybackController] Add nextPresses that load the presses in the next playback tick --- .../com/minecrafttas/tasmod/gui/InfoHud.java | 39 +++--- .../playback/PlaybackControllerClient.java | 123 +++++++++++++----- .../tasmod/virtual/VirtualInput.java | 6 +- 3 files changed, 115 insertions(+), 53 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java index cae09289..ed59cc37 100644 --- a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java +++ b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java @@ -18,14 +18,17 @@ import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.TASmodClient; import com.minecrafttas.tasmod.events.EventClient.EventDrawHotbar; +import com.minecrafttas.tasmod.playback.PlaybackControllerClient; import com.minecrafttas.tasmod.playback.PlaybackControllerClient.TASstate; import com.minecrafttas.tasmod.playback.filecommands.builtin.DesyncMonitorFileCommandExtension; +import com.minecrafttas.tasmod.virtual.VirtualInput; import com.mojang.realmsclient.gui.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.text.TextFormatting; /** * The info hud is a hud that is always being rendered ontop of the screen, it can show some stuff such as coordinates, etc., @@ -548,29 +551,27 @@ private void drawRectWithText(String text, int x, int y, boolean rect) { } private String keystrokes() { + boolean isPlayingBack = TASmodClient.controller.isPlayingback(); + VirtualInput virtual = TASmodClient.virtual; + PlaybackControllerClient controller = TASmodClient.controller; - 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 currentMousePresses = String.join(" ", virtual.getCurrentMousePresses()); - String out2 = "" + ChatFormatting.WHITE; - for (String key : TASmodClient.virtual.getCurrentKeyboardPresses()) { - out2 = out2.concat(key + " "); + String nextMousePresses = ""; + if (Display.isActive() || isPlayingBack) { + List mousePresses = isPlayingBack ? controller.getNextMousePresses() : virtual.getNextMousePresses(); + nextMousePresses = String.join(" ", mousePresses); } - if (Display.isActive() || TASmodClient.controller.isPlayingback()) { - out2 = out2.concat("" + ChatFormatting.GREEN); - for (String key : TASmodClient.virtual.getNextKeyboardPresses()) { - out2 = out2.concat(key + " "); - } + + String currentKeyboardPresses = String.join(" ", TASmodClient.virtual.getCurrentKeyboardPresses()); + + String nextKeyboardPresses = ""; + if (Display.isActive() || isPlayingBack) { + List keyboardPresses = isPlayingBack ? controller.getNextKeyboardPresses() : virtual.getNextKeyboardPresses(); + nextKeyboardPresses = String.join(" ", keyboardPresses); } - return out1 + out2; + + return String.format("%s%s %s%s %s%s %s%s", TextFormatting.WHITE, currentMousePresses, TextFormatting.GREEN, nextMousePresses, TextFormatting.WHITE, currentKeyboardPresses, TextFormatting.GREEN, nextKeyboardPresses); } private Pair getScreenOffset(int x, int y, InfoLabel label) { diff --git a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java index 11b2c1df..3f06a9c5 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java @@ -119,12 +119,40 @@ public class PlaybackControllerClient implements */ private long index; - private VirtualKeyboard keyboard = new VirtualKeyboard(); - - private VirtualMouse mouse = new VirtualMouse(); - - private VirtualCameraAngle camera = new VirtualCameraAngle(); + /** + *

The current keyboard used in the {@link PlaybackControllerClient PlaybackController} + *

Used during recording to store incoming inputs from the {@link VirtualInput#KEYBOARD}
+ * or stores inputs that are sent to the {@link VirtualInput#KEYBOARD} during playback + */ + private VirtualKeyboard currentPlaybackKeyboard = new VirtualKeyboard(); + /** + *

The current mouse used in the {@link PlaybackControllerClient PlaybackController} + *

Used during recording to store incoming inputs from the {@link VirtualInput#MOUSE}
+ * or stores inputs that are sent to the {@link VirtualInput#MOUSE} during playback + */ + private VirtualMouse currentPlaybackMouse = new VirtualMouse(); + /** + *

The current camera angle used in the {@link PlaybackControllerClient PlaybackController} + *

Used during recording to store incoming inputs from the {@link VirtualInput#CAMERA_ANGLE}
+ * or stores inputs that are sent to the {@link VirtualInput#CAMERA_ANGLE} during playback + */ + private VirtualCameraAngle currentPlaybackCameraAngle = new VirtualCameraAngle(); + /** + *

The keyboard in the next playback tick + *

These inputs will be fed into {@link #currentPlaybackKeyboard} after a tick + */ + private VirtualKeyboard nextPlaybackKeyboard = new VirtualKeyboard(); + /** + *

The mouse in the next playback tick + *

These inputs will be fed into {@link #currentPlaybackMouse} after a tick + */ + private VirtualMouse nextPlaybackMouse = new VirtualMouse(); + /** + *

The camera angle in the next playback tick + *

These inputs will be fed into {@link #currentPlaybackCameraAngle} after a tick + */ + private VirtualCameraAngle nextPlaybackCameraAngle = new VirtualCameraAngle(); /** * The directory where to store the tasfiles */ @@ -280,7 +308,7 @@ private void startRecording() { VirtualCameraAngleInput CAMERA_ANGLE = TASmodClient.virtual.CAMERA_ANGLE; Float pitch = CAMERA_ANGLE.getCurrentPitch(); Float yaw = CAMERA_ANGLE.getCurrentYaw(); - this.camera.set(pitch, yaw); + this.currentPlaybackCameraAngle.set(pitch, yaw); inputs.add(new InputContainer()); } @@ -373,9 +401,9 @@ public TASstate getStateAfterPause() { @Override public VirtualKeyboard onVirtualKeyboardTick(VirtualKeyboard vkeyboard) { if (state == TASstate.RECORDING) { - this.keyboard.deepCopyFrom(vkeyboard); + this.currentPlaybackKeyboard.deepCopyFrom(vkeyboard); } else if (state == TASstate.PLAYBACK) { - vkeyboard.deepCopyFrom(this.keyboard); + vkeyboard.deepCopyFrom(this.currentPlaybackKeyboard); } return vkeyboard.clone(); } @@ -383,9 +411,9 @@ public VirtualKeyboard onVirtualKeyboardTick(VirtualKeyboard vkeyboard) { @Override public VirtualMouse onVirtualMouseTick(VirtualMouse vmouse) { if (state == TASstate.RECORDING) { - this.mouse.deepCopyFrom(vmouse); + this.currentPlaybackMouse.deepCopyFrom(vmouse); } else if (state == TASstate.PLAYBACK) { - vmouse.deepCopyFrom(this.mouse); + vmouse.deepCopyFrom(this.currentPlaybackMouse); } return vmouse.clone(); } @@ -393,9 +421,9 @@ public VirtualMouse onVirtualMouseTick(VirtualMouse vmouse) { @Override public VirtualCameraAngle onVirtualCameraTick(VirtualCameraAngle vcamera) { if (state == TASstate.RECORDING) { - this.camera.deepCopyFrom(vcamera); + this.currentPlaybackCameraAngle.deepCopyFrom(vcamera); } else if (state == TASstate.PLAYBACK) { - vcamera.deepCopyFrom(this.camera); + vcamera.deepCopyFrom(this.currentPlaybackCameraAngle); } return vcamera.clone(); } @@ -418,25 +446,24 @@ public void onDrawScreen(GuiScreen screen, int x, int y) { /** * Updates the input container.
*
- * During a recording this adds the {@linkplain #keyboard}, {@linkplain #mouse} - * and {@linkplain #camera} to {@linkplain #inputs} and increases the + * During a recording this adds the {@linkplain #currentPlaybackKeyboard}, {@linkplain #currentPlaybackMouse} + * and {@linkplain #currentPlaybackCameraAngle} to {@linkplain #inputs} and increases the * {@linkplain #index}.
*
* During playback the opposite is happening, getting the inputs from - * {@linkplain #inputs} and temporarily storing them in {@linkplain #keyboard}, - * {@linkplain #mouse} and {@linkplain #camera}.
+ * {@linkplain #inputs} and temporarily storing them in {@linkplain #currentPlaybackKeyboard}, + * {@linkplain #currentPlaybackMouse} and {@linkplain #currentPlaybackCameraAngle}.
*
- * Then in {@linkplain VirtualInput}, {@linkplain #keyboard}, - * {@linkplain #mouse} and {@linkplain #camera} are retrieved and emulated as + * Then in {@linkplain VirtualInput}, {@linkplain #currentPlaybackKeyboard}, + * {@linkplain #currentPlaybackMouse} and {@linkplain #currentPlaybackCameraAngle} are retrieved and emulated as * the next inputs */ @Override public void onClientTickPost(Minecraft mc) { /* Stop the playback while player is still loading */ EntityPlayerSP player = mc.player; - if (player != null && player.addedToChunk) { - if (isPaused() && stateAfterPause != TASstate.NONE) { + if (isPaused() && stateAfterPause != TASstate.NONE) { // TODO Find a better solution... setTASState(stateAfterPause); // The recording is paused in LoadWorldEvents#startLaunchServer pause(false); EventListenerRegistry.fireEvent(EventPlaybackJoinedWorld.class, state); @@ -457,7 +484,7 @@ public void onClientTickPost(Minecraft mc) { private void recordNextTick() { index++; - InputContainer container = new InputContainer(keyboard.clone(), mouse.clone(), camera.clone()); + InputContainer container = new InputContainer(currentPlaybackKeyboard.clone(), currentPlaybackMouse.clone(), currentPlaybackCameraAngle.clone()); if (inputs.size() <= index) { if (inputs.size() < index) { LOGGER.warn("Index is {} inputs bigger than the container!", index - inputs.size()); @@ -490,10 +517,24 @@ private void playbackNextTick() { } /* Continue condition */ else { - InputContainer container = inputs.get(index); // Loads the new inputs from the container - this.keyboard = container.getKeyboard().clone(); - this.mouse = container.getMouse().clone(); - this.camera = container.getCameraAngle().clone(); + InputContainer container = null; + if (index + 1 < inputs.size()) { + container = inputs.get(index + 1); // Loads the new inputs from the container + + this.currentPlaybackKeyboard = this.nextPlaybackKeyboard.clone(); + this.currentPlaybackMouse = this.nextPlaybackMouse.clone(); + this.currentPlaybackCameraAngle = this.nextPlaybackCameraAngle.clone(); + + this.nextPlaybackKeyboard = container.getKeyboard().clone(); + this.nextPlaybackMouse = container.getMouse().clone(); + this.nextPlaybackCameraAngle = container.getCameraAngle().clone(); + } else { + container = inputs.get(index); // Loads the new inputs from the container + this.currentPlaybackKeyboard = container.getKeyboard().clone(); + this.currentPlaybackMouse = container.getMouse().clone(); + this.currentPlaybackCameraAngle = container.getCameraAngle().clone(); + } + EventListenerRegistry.fireEvent(EventPlaybackTick.class, index, container); } } @@ -536,9 +577,9 @@ public void setIndex(long index) throws IndexOutOfBoundsException { this.index = index; if (state == TASstate.PLAYBACK) { InputContainer inputcontainer = inputs.get(index); - this.keyboard = inputcontainer.getKeyboard(); - this.mouse = inputcontainer.getMouse(); - this.camera = inputcontainer.getCameraAngle(); + this.currentPlaybackKeyboard = inputcontainer.getKeyboard(); + this.currentPlaybackMouse = inputcontainer.getMouse(); + this.currentPlaybackCameraAngle = inputcontainer.getCameraAngle(); } } else { throw new IndexOutOfBoundsException("Index is bigger than the container"); @@ -579,6 +620,26 @@ private void clearInputList() { inputs = new BigArrayList(tasFileDirectory + File.separator + "temp"); } + public VirtualKeyboard getNextPlaybackKeyboard() { + return nextPlaybackKeyboard; + } + + public VirtualMouse getNextPlaybackMouse() { + return nextPlaybackMouse; + } + + public VirtualCameraAngle getNextPlaybackCameraAngle() { + return nextPlaybackCameraAngle; + } + + public List getNextKeyboardPresses() { + return nextPlaybackKeyboard.getCurrentPresses(); + } + + public List getNextMousePresses() { + return nextPlaybackMouse.getCurrentPresses(); + } + /** * Used for displaying the rought contents of the input container */ @@ -598,12 +659,12 @@ public String toString() { // ============================================================== /** - * Clears {@link #keyboard} and {@link #mouse} + * Clears {@link #currentPlaybackKeyboard} and {@link #currentPlaybackMouse} */ public void unpressContainer() { LOGGER.trace(LoggerMarkers.Playback, "Unpressing container"); - keyboard.clear(); - mouse.clear(); + currentPlaybackKeyboard.clear(); + currentPlaybackMouse.clear(); } // ============================================================== diff --git a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java index 17b50fa5..89bcd94b 100644 --- a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java +++ b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java @@ -557,7 +557,7 @@ public boolean willKeyBeDown(int keycode) { * @param pitch The original pitch of the camera * @param yaw The original yaw of the camera * @param enable Whether the custom interpolation is enabled. Enabled during playback. - * @return A triple of pitch, yaw and roll, as left, middle and right respectively + * @return Integer coordinate of */ public int getInterpolatedX(float partialTick, boolean enable) { @@ -783,8 +783,8 @@ public Triple getInterpolatedState(float partialTick, float VirtualCameraAngle interpolatedCamera = cameraAngleInterpolationStates.get(index); - interpolatedPitch = interpolatedCamera.getPitch(); - interpolatedYaw = interpolatedCamera.getYaw() + 180; + interpolatedPitch = interpolatedCamera.getPitch() == null ? 0 : interpolatedCamera.getPitch(); + interpolatedYaw = interpolatedCamera.getYaw() == null ? 0 : interpolatedCamera.getYaw() + 180; } return Triple.of(interpolatedPitch, interpolatedYaw, 0f); From 1c4860cc8a0973ce9bb03a969f2773acc26d1df4 Mon Sep 17 00:00:00 2001 From: Scribble Date: Wed, 16 Jul 2025 22:28:04 +0200 Subject: [PATCH 5/9] [VirtualInput] Add nextPlaybackMouse to interpolation --- .../tasmod/playback/PlaybackControllerClient.java | 4 ++++ .../java/com/minecrafttas/tasmod/virtual/VirtualInput.java | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java index 3f06a9c5..6bad3ba5 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java @@ -640,6 +640,10 @@ public List getNextMousePresses() { return nextPlaybackMouse.getCurrentPresses(); } + public VirtualMouse getNextMouse() { + return nextPlaybackMouse; + } + /** * Used for displaying the rought contents of the input container */ diff --git a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java index 89bcd94b..3f658c6d 100644 --- a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java +++ b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java @@ -12,6 +12,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.minecrafttas.mctcommon.events.EventListenerRegistry; +import com.minecrafttas.tasmod.TASmodClient; import com.minecrafttas.tasmod.events.EventVirtualInput; import com.minecrafttas.tasmod.mixin.playbackhooks.MixinEntityRenderer; import com.minecrafttas.tasmod.mixin.playbackhooks.MixinMinecraft; @@ -460,7 +461,7 @@ public void updateNextMouse(int keycode, boolean keystate, int scrollwheel, int public void nextMouseTick() { nextMouse.deepCopyFrom((VirtualMouse) EventListenerRegistry.fireEvent(EventVirtualInput.EventVirtualMouseTick.class, nextMouse)); mousePointerInterpolationStates.clear(); - nextMouse.getStates(mousePointerInterpolationStates); + TASmodClient.controller.getNextMouse().getStates(mousePointerInterpolationStates); currentMouse.getVirtualEvents(nextMouse, mouseEventQueue); currentMouse.moveFrom(nextMouse); } From 01b4c5e5631b1c6c0aa06766797713cfc8fccf6d Mon Sep 17 00:00:00 2001 From: Scribble Date: Thu, 17 Jul 2025 21:44:41 +0200 Subject: [PATCH 6/9] Fix JUnit not working --- build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 53128ff5..52d14f78 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,8 @@ dependencies { minecraft "com.mojang:minecraft:${project.minecraft_version}" mappings "net.legacyfabric:yarn:${project.minecraft_version}+build.mcp" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0' + testImplementation 'org.junit.jupiter:junit-jupiter:5.13.3' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } // task for downloading KillTheRng From 729743dd1260da56684eb8d2d239a0d80ba91af8 Mon Sep 17 00:00:00 2001 From: Scribble Date: Thu, 17 Jul 2025 21:44:41 +0200 Subject: [PATCH 7/9] [VirtualInput] Move interpolation code into it's own class --- .../events/EventListenerRegistry.java | 4 +- .../com/minecrafttas/tasmod/TASmodClient.java | 2 + .../com/minecrafttas/tasmod/gui/InfoHud.java | 4 +- .../playbackhooks/MixinEntityRenderer.java | 6 +- .../tasmod/virtual/VirtualInput.java | 98 +-------------- .../virtual/VirtualInterpolationHandler.java | 114 ++++++++++++++++++ .../java/tasmod/virtual/VirtualInputTest.java | 24 ++-- 7 files changed, 141 insertions(+), 111 deletions(-) create mode 100644 src/main/java/com/minecrafttas/tasmod/virtual/VirtualInterpolationHandler.java diff --git a/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java b/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java index 0a42ea10..ca913669 100644 --- a/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java +++ b/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java @@ -252,7 +252,9 @@ public static Object fireEvent(Class toThrow = null; // Reset toThrow as the correct method was found method.setAccessible(true); try { - returnValue = method.invoke(eventListener, eventParams); // Call the method + Object newReturnValue = method.invoke(eventListener, eventParams); // Call the method + if (newReturnValue != null) + returnValue = newReturnValue; } catch (IllegalAccessException | InvocationTargetException e) { throw new EventException(eventClass, e); } catch (IllegalArgumentException e) { diff --git a/src/main/java/com/minecrafttas/tasmod/TASmodClient.java b/src/main/java/com/minecrafttas/tasmod/TASmodClient.java index 5f8aaa4f..6acd7502 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmodClient.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmodClient.java @@ -198,6 +198,8 @@ private void registerEventListeners() { EventListenerRegistry.register(TASmodAPIRegistry.PLAYBACK_FILE_COMMAND); EventListenerRegistry.register(new LoggerMarkers()); EventListenerRegistry.register(savestateHandlerClient); + + EventListenerRegistry.register(virtual.interpolationHandler); } @Override diff --git a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java index ed59cc37..a332ef6d 100644 --- a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java +++ b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java @@ -390,8 +390,8 @@ public boolean checkInit() { if (Minecraft.getMinecraft().currentScreen == this) return "Mouse Position"; - Integer xCursor = TASmodClient.virtual.MOUSE.getInterpolatedX(0, false); - Integer yCursor = TASmodClient.virtual.MOUSE.getInterpolatedY(0, false); + Integer xCursor = TASmodClient.virtual.interpolationHandler.getInterpolatedX(0, false); + Integer yCursor = TASmodClient.virtual.interpolationHandler.getInterpolatedY(0, false); if (Minecraft.getMinecraft().currentScreen != null) return String.format("Mouse Cursor: %s %s", xCursor == null ? "null" : xCursor, yCursor == null ? "null" : yCursor); 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 49ab559c..789bab42 100644 --- a/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java +++ b/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java @@ -201,7 +201,7 @@ public void playback_updateOverlay(CallbackInfo ci) { * @return The redirected yaw */ private float redirectCam(float pitch, float yaw) { - Triple interpolated = TASmodClient.virtual.CAMERA_ANGLE.getInterpolatedState(Minecraft.getMinecraft().timer.renderPartialTicks, pitch, yaw, TASmodClient.controller.isPlayingback()); + Triple interpolated = TASmodClient.virtual.interpolationHandler.getInterpolatedState(Minecraft.getMinecraft().timer.renderPartialTicks, pitch, yaw, TASmodClient.controller.isPlayingback()); float pitch2 = interpolated.getLeft(); float yaw2 = interpolated.getMiddle(); // Update pitch @@ -214,13 +214,13 @@ private float redirectCam(float pitch, float yaw) { @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getX()I", remap = false)) public int redirect_updateCameraAndRendererX() { - int interpolatedX = TASmodClient.virtual.MOUSE.getInterpolatedX(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback()); + int interpolatedX = TASmodClient.virtual.interpolationHandler.getInterpolatedX(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback()); return interpolatedX; } @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getY()I", remap = false)) public int redirect_updateCameraAndRendererY() { - int interpolatedY = TASmodClient.virtual.MOUSE.getInterpolatedY(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback()); + int interpolatedY = TASmodClient.virtual.interpolationHandler.getInterpolatedY(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback()); return interpolatedY; } } diff --git a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java index 3f658c6d..377f4c35 100644 --- a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java +++ b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java @@ -1,23 +1,19 @@ package com.minecrafttas.tasmod.virtual; -import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; -import org.apache.commons.lang3.tuple.Triple; import org.apache.logging.log4j.Logger; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.minecrafttas.mctcommon.events.EventListenerRegistry; -import com.minecrafttas.tasmod.TASmodClient; import com.minecrafttas.tasmod.events.EventVirtualInput; 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.GuiScreenDuck; import com.minecrafttas.tasmod.util.Ducks.SubtickDuck; import com.minecrafttas.tasmod.util.LoggerMarkers; import com.minecrafttas.tasmod.util.PointerNormalizer; @@ -26,7 +22,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; -import net.minecraft.util.math.MathHelper; /** * Main component for redirecting inputs.
@@ -51,6 +46,8 @@ public class VirtualInput { */ public final VirtualCameraAngleInput CAMERA_ANGLE; + public final VirtualInterpolationHandler interpolationHandler = new VirtualInterpolationHandler(); + /** * Creates a new virtual input with an empty {@link VirtualKeyboardInput}, {@link VirtualMouseInput} and {@link VirtualCameraAngleInput} * @param logger The logger instance @@ -426,8 +423,6 @@ public class VirtualMouseInput { */ private VirtualMouseEvent currentMouseEvent = new VirtualMouseEvent(); - private final List mousePointerInterpolationStates = new ArrayList<>(); - /** * Constructor to preload the {@link #currentMouse} with an existing mouse * @param preloadedMouse The new {@link #currentMouse} @@ -460,8 +455,6 @@ public void updateNextMouse(int keycode, boolean keystate, int scrollwheel, int */ public void nextMouseTick() { nextMouse.deepCopyFrom((VirtualMouse) EventListenerRegistry.fireEvent(EventVirtualInput.EventVirtualMouseTick.class, nextMouse)); - mousePointerInterpolationStates.clear(); - TASmodClient.controller.getNextMouse().getStates(mousePointerInterpolationStates); currentMouse.getVirtualEvents(nextMouse, mouseEventQueue); currentMouse.moveFrom(nextMouse); } @@ -551,60 +544,6 @@ public boolean willKeyBeDown(int keycode) { return nextMouse.isKeyDown(keycode); } - /** - * Gets the absolute coordinates of the camera angle - * - * @param partialTick The partial ticks of the timer - * @param pitch The original pitch of the camera - * @param yaw The original yaw of the camera - * @param enable Whether the custom interpolation is enabled. Enabled during playback. - * @return Integer coordinate of - */ - public int getInterpolatedX(float partialTick, boolean enable) { - - int interpolatedPointerX = nextMouse.getCursorX(); - - if (enable && !mousePointerInterpolationStates.isEmpty()) { - int index = (int) MathHelper.clampedLerp(0, mousePointerInterpolationStates.size() - 1, partialTick); // Get interpolate index - - VirtualMouse interpolatedCamera = mousePointerInterpolationStates.get(index); - - interpolatedPointerX = interpolatedCamera.getCursorX(); - - } - Minecraft mc = Minecraft.getMinecraft(); - GuiScreenDuck gui = (GuiScreenDuck) mc.currentScreen; - - if (gui != null) { - interpolatedPointerX = gui.rescaleX(PointerNormalizer.reapplyScalingX(interpolatedPointerX)); - } - - return interpolatedPointerX; - } - - public int getInterpolatedY(float partialTick, boolean enable) { - - int interpolatedPointerY = nextMouse.getCursorY(); - - if (enable && !mousePointerInterpolationStates.isEmpty()) { - int index = (int) MathHelper.clampedLerp(0, mousePointerInterpolationStates.size() - 1, partialTick); // Get interpolate index - - VirtualMouse interpolatedCamera = mousePointerInterpolationStates.get(index); - - interpolatedPointerY = interpolatedCamera.getCursorY(); - - } - - Minecraft mc = Minecraft.getMinecraft(); - GuiScreenDuck gui = (GuiScreenDuck) mc.currentScreen; - - if (gui != null) { - interpolatedPointerY = gui.rescaleY(PointerNormalizer.reapplyScalingY(interpolatedPointerY)); - } - - return interpolatedPointerY; - } - /** * Clears the {@link #nextMouse} */ @@ -676,11 +615,6 @@ public class VirtualCameraAngleInput { * and updates {@link #currentCameraAngle} in {@link #nextCameraTick()} */ private final VirtualCameraAngle nextCameraAngle = new VirtualCameraAngle(); - /** - * States of the {@link #nextCameraAngle} made during the tick.
- * Is updated in {@link #nextCameraTick()} - */ - private final List cameraAngleInterpolationStates = new ArrayList<>(); /** * Constructor to preload the {@link #currentCameraAngle} with an existing @@ -728,8 +662,6 @@ public void updateNextCameraAngle(float pitchDelta, float yawDelta, boolean upda */ public void nextCameraTick() { nextCameraAngle.deepCopyFrom((VirtualCameraAngle) EventListenerRegistry.fireEvent(EventVirtualInput.EventVirtualCameraAngleTick.class, nextCameraAngle)); - cameraAngleInterpolationStates.clear(); - nextCameraAngle.getStates(cameraAngleInterpolationStates); currentCameraAngle.moveFrom(nextCameraAngle); } @@ -765,32 +697,6 @@ public Float getCurrentYaw() { return currentCameraAngle.getYaw(); } - /** - * Gets the absolute coordinates of the camera angle - * - * @param partialTick The partial ticks of the timer - * @param pitch The original pitch of the camera - * @param yaw The original yaw of the camera - * @param enable Whether the custom interpolation is enabled. Enabled during playback. - * @return A triple of pitch, yaw and roll, as left, middle and right respectively - */ - public Triple getInterpolatedState(float partialTick, float pitch, float yaw, boolean enable) { - - float interpolatedPitch = nextCameraAngle.getPitch() == null ? pitch : nextCameraAngle.getPitch(); - float interpolatedYaw = nextCameraAngle.getYaw() == null ? yaw : nextCameraAngle.getYaw() + 180; - - if (enable && !cameraAngleInterpolationStates.isEmpty()) { - int index = (int) MathHelper.clampedLerp(0, cameraAngleInterpolationStates.size() - 1, partialTick); // Get interpolate index - - VirtualCameraAngle interpolatedCamera = cameraAngleInterpolationStates.get(index); - - interpolatedPitch = interpolatedCamera.getPitch() == null ? 0 : interpolatedCamera.getPitch(); - interpolatedYaw = interpolatedCamera.getYaw() == null ? 0 : interpolatedCamera.getYaw() + 180; - - } - return Triple.of(interpolatedPitch, interpolatedYaw, 0f); - } - /** * Clears the {@link #nextCameraAngle} */ diff --git a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInterpolationHandler.java b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInterpolationHandler.java new file mode 100644 index 00000000..9cdffa98 --- /dev/null +++ b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInterpolationHandler.java @@ -0,0 +1,114 @@ +package com.minecrafttas.tasmod.virtual; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.tuple.Triple; + +import com.minecrafttas.tasmod.TASmodClient; +import com.minecrafttas.tasmod.events.EventVirtualInput; +import com.minecrafttas.tasmod.util.Ducks.GuiScreenDuck; +import com.minecrafttas.tasmod.util.PointerNormalizer; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.math.MathHelper; + +public class VirtualInterpolationHandler implements EventVirtualInput.EventVirtualMouseTick, EventVirtualInput.EventVirtualCameraAngleTick { + + private final List mousePointerInterpolationStates = new ArrayList<>(); + /** + * States of the {@link #nextCameraAngle} made during the tick.
+ * Is updated in {@link #nextCameraTick()} + */ + private final List cameraAngleInterpolationStates = new ArrayList<>(); + + private VirtualMouse nextMouse = new VirtualMouse(); + private VirtualCameraAngle nextCameraAngle = new VirtualCameraAngle(); + + public int getInterpolatedX(float partialTick, boolean enable) { + + int interpolatedPointerX = nextMouse.getCursorX(); + + if (enable && !mousePointerInterpolationStates.isEmpty()) { + int index = (int) MathHelper.clampedLerp(0, mousePointerInterpolationStates.size() - 1, partialTick); // Get interpolate index + + VirtualMouse interpolatedCamera = mousePointerInterpolationStates.get(index); + + interpolatedPointerX = interpolatedCamera.getCursorX(); + + } + Minecraft mc = Minecraft.getMinecraft(); + GuiScreenDuck gui = (GuiScreenDuck) mc.currentScreen; + + if (gui != null) { + interpolatedPointerX = gui.rescaleX(PointerNormalizer.reapplyScalingX(interpolatedPointerX)); + } + + return interpolatedPointerX; + } + + public int getInterpolatedY(float partialTick, boolean enable) { + + int interpolatedPointerY = nextMouse.getCursorY(); + + if (enable && !mousePointerInterpolationStates.isEmpty()) { + int index = (int) MathHelper.clampedLerp(0, mousePointerInterpolationStates.size() - 1, partialTick); // Get interpolate index + + VirtualMouse interpolatedCamera = mousePointerInterpolationStates.get(index); + + interpolatedPointerY = interpolatedCamera.getCursorY(); + + } + + Minecraft mc = Minecraft.getMinecraft(); + GuiScreenDuck gui = (GuiScreenDuck) mc.currentScreen; + + if (gui != null) { + interpolatedPointerY = gui.rescaleY(PointerNormalizer.reapplyScalingY(interpolatedPointerY)); + } + + return interpolatedPointerY; + } + + /** + * Gets the absolute coordinates of the camera angle + * + * @param partialTick The partial ticks of the timer + * @param pitch The original pitch of the camera + * @param yaw The original yaw of the camera + * @param enable Whether the custom interpolation is enabled. Enabled during playback. + * @return A triple of pitch, yaw and roll, as left, middle and right respectively + */ + public Triple getInterpolatedState(float partialTick, float pitch, float yaw, boolean enable) { + + float interpolatedPitch = nextCameraAngle.getPitch() == null ? pitch : nextCameraAngle.getPitch(); + float interpolatedYaw = nextCameraAngle.getYaw() == null ? yaw : nextCameraAngle.getYaw() + 180; + + if (enable && !cameraAngleInterpolationStates.isEmpty()) { + int index = (int) MathHelper.clampedLerp(0, cameraAngleInterpolationStates.size() - 1, partialTick); // Get interpolate index + + VirtualCameraAngle interpolatedCamera = cameraAngleInterpolationStates.get(index); + + interpolatedPitch = interpolatedCamera.getPitch() == null ? 0 : interpolatedCamera.getPitch(); + interpolatedYaw = interpolatedCamera.getYaw() == null ? 0 : interpolatedCamera.getYaw() + 180; + + } + return Triple.of(interpolatedPitch, interpolatedYaw, 0f); + } + + @Override + public VirtualMouse onVirtualMouseTick(VirtualMouse vmouse) { + this.nextMouse = vmouse; + mousePointerInterpolationStates.clear(); + TASmodClient.controller.getNextMouse().getStates(mousePointerInterpolationStates); + return null; + } + + @Override + public VirtualCameraAngle onVirtualCameraTick(VirtualCameraAngle vcamera) { + this.nextCameraAngle = vcamera; + cameraAngleInterpolationStates.clear(); + nextCameraAngle.getStates(cameraAngleInterpolationStates); + return null; + } +} diff --git a/src/test/java/tasmod/virtual/VirtualInputTest.java b/src/test/java/tasmod/virtual/VirtualInputTest.java index cb2b4582..f77ab792 100644 --- a/src/test/java/tasmod/virtual/VirtualInputTest.java +++ b/src/test/java/tasmod/virtual/VirtualInputTest.java @@ -274,15 +274,18 @@ void testCurrentCameraAngles() { @Test void testInterpolationDisabled() { VirtualInput virtual = new VirtualInput(LOGGER); + EventListenerRegistry.register(virtual.interpolationHandler); virtual.CAMERA_ANGLE.setCamera(0f, 0f); virtual.CAMERA_ANGLE.updateNextCameraAngle(10f, 20f); virtual.CAMERA_ANGLE.updateNextCameraAngle(20f, 30f); + virtual.CAMERA_ANGLE.nextCameraTick(); Triple expected = Triple.of(30f, 50f + 180f, 0f); - Triple actual = virtual.CAMERA_ANGLE.getInterpolatedState(0f, 1f, 2f, false); + Triple actual = virtual.interpolationHandler.getInterpolatedState(0f, 1f, 2f, false); assertEquals(expected, actual); + EventListenerRegistry.unregister(virtual.interpolationHandler); } /** @@ -291,6 +294,7 @@ void testInterpolationDisabled() { @Test void testInterpolationEnabled() { VirtualInput virtual = new VirtualInput(LOGGER); + EventListenerRegistry.register(virtual.interpolationHandler); virtual.CAMERA_ANGLE.setCamera(0f, 0f); virtual.CAMERA_ANGLE.updateNextCameraAngle(0f, 0f); @@ -307,35 +311,37 @@ void testInterpolationEnabled() { virtual.CAMERA_ANGLE.nextCameraTick(); Triple expected = Triple.of(0f, 180f, 0f); - Triple actual = virtual.CAMERA_ANGLE.getInterpolatedState(0f, 0f, 0f, true); + Triple actual = virtual.interpolationHandler.getInterpolatedState(0f, 0f, 0f, true); assertEquals(expected, actual); expected = Triple.of(0f, 180f, 0f); - actual = virtual.CAMERA_ANGLE.getInterpolatedState(0.1f, 0f, 0f, true); + actual = virtual.interpolationHandler.getInterpolatedState(0.1f, 0f, 0f, true); assertEquals(expected, actual); expected = Triple.of(10f, 190f, 0f); - actual = virtual.CAMERA_ANGLE.getInterpolatedState(0.199f, 0f, 0f, true); + actual = virtual.interpolationHandler.getInterpolatedState(0.199f, 0f, 0f, true); assertEquals(expected, actual); expected = Triple.of(10f, 190f, 0f); - actual = virtual.CAMERA_ANGLE.getInterpolatedState(0.2f, 0f, 0f, true); + actual = virtual.interpolationHandler.getInterpolatedState(0.2f, 0f, 0f, true); assertEquals(expected, actual); expected = Triple.of(20f, 200f, 0f); - actual = virtual.CAMERA_ANGLE.getInterpolatedState(0.3f, 0f, 0f, true); + actual = virtual.interpolationHandler.getInterpolatedState(0.3f, 0f, 0f, true); assertEquals(expected, actual); expected = Triple.of(30f, 210f, 0f); - actual = virtual.CAMERA_ANGLE.getInterpolatedState(0.4f, 0f, 0f, true); + actual = virtual.interpolationHandler.getInterpolatedState(0.4f, 0f, 0f, true); assertEquals(expected, actual); expected = Triple.of(40f, 220f, 0f); - actual = virtual.CAMERA_ANGLE.getInterpolatedState(0.5f, 0f, 0f, true); + actual = virtual.interpolationHandler.getInterpolatedState(0.5f, 0f, 0f, true); assertEquals(expected, actual); expected = Triple.of(50f, 230f, 0f); - actual = virtual.CAMERA_ANGLE.getInterpolatedState(0.6f, 0f, 0f, true); + actual = virtual.interpolationHandler.getInterpolatedState(0.6f, 0f, 0f, true); assertEquals(expected, actual); + + EventListenerRegistry.unregister(virtual.interpolationHandler); } } From 7fdf34786932b4002a26ffa0733fe775be213b0f Mon Sep 17 00:00:00 2001 From: Scribble Date: Fri, 18 Jul 2025 22:36:45 +0200 Subject: [PATCH 8/9] [VirtualInput] Cleanup and documentation --- .../events/EventListenerRegistry.java | 3 +- .../com/minecrafttas/tasmod/gui/InfoHud.java | 6 +- .../playbackhooks/MixinEntityRenderer.java | 40 ++-- .../virtual/VirtualInterpolationHandler.java | 175 +++++++++++++----- .../java/tasmod/virtual/VirtualInputTest.java | 24 +-- 5 files changed, 162 insertions(+), 86 deletions(-) diff --git a/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java b/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java index ca913669..65aa9aa0 100644 --- a/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java +++ b/src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java @@ -235,8 +235,7 @@ public static Object fireEvent(Class // Iterate through all methods for (Method method : methodsInListener) { - // Check if the current method has the same name as the method we are looking - // for + // Check if the current method has the same name as the method we are looking for if (!checkName(method, methodToFind.getName())) { continue; } diff --git a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java index a332ef6d..c7b04baf 100644 --- a/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java +++ b/src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java @@ -22,6 +22,7 @@ import com.minecrafttas.tasmod.playback.PlaybackControllerClient.TASstate; import com.minecrafttas.tasmod.playback.filecommands.builtin.DesyncMonitorFileCommandExtension; import com.minecrafttas.tasmod.virtual.VirtualInput; +import com.minecrafttas.tasmod.virtual.VirtualInterpolationHandler.MouseInterpolation; import com.mojang.realmsclient.gui.ChatFormatting; import net.minecraft.client.Minecraft; @@ -390,8 +391,9 @@ public boolean checkInit() { if (Minecraft.getMinecraft().currentScreen == this) return "Mouse Position"; - Integer xCursor = TASmodClient.virtual.interpolationHandler.getInterpolatedX(0, false); - Integer yCursor = TASmodClient.virtual.interpolationHandler.getInterpolatedY(0, false); + MouseInterpolation mouseInterpolation = TASmodClient.virtual.interpolationHandler.getInterpolatedMouseCursor(0, false); + Integer xCursor = mouseInterpolation.getX(); + Integer yCursor = mouseInterpolation.getY(); if (Minecraft.getMinecraft().currentScreen != null) return String.format("Mouse Cursor: %s %s", xCursor == null ? "null" : xCursor, yCursor == null ? "null" : yCursor); 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 789bab42..5c1a36de 100644 --- a/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java +++ b/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java @@ -1,6 +1,5 @@ package com.minecrafttas.tasmod.mixin.playbackhooks; -import org.apache.commons.lang3.tuple.Triple; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -11,11 +10,14 @@ import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalFloatRef; +import com.llamalad7.mixinextras.sugar.ref.LocalIntRef; import com.minecrafttas.mctcommon.events.EventListenerRegistry; import com.minecrafttas.tasmod.TASmodClient; import com.minecrafttas.tasmod.events.EventClient.EventDrawHotbarAlways; import com.minecrafttas.tasmod.util.Ducks.SubtickDuck; import com.minecrafttas.tasmod.virtual.VirtualInput; +import com.minecrafttas.tasmod.virtual.VirtualInterpolationHandler.CameraInterpolation; +import com.minecrafttas.tasmod.virtual.VirtualInterpolationHandler.MouseInterpolation; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityPlayerSP; @@ -193,34 +195,32 @@ public void playback_updateOverlay(CallbackInfo ci) { EventListenerRegistry.fireEvent(EventDrawHotbarAlways.class); } + @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getX()I", remap = false)) + public int redirect_updateCameraAndRendererX(@Share(value = "interpolatedY") LocalIntRef shared) { + MouseInterpolation interpolated = TASmodClient.virtual.interpolationHandler.getInterpolatedMouseCursor(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback()); + shared.set(interpolated.getY()); + return interpolated.getX(); + } + + @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getY()I", remap = false)) + public int redirect_updateCameraAndRendererY(@Share(value = "interpolatedY") LocalIntRef shared) { + return shared.get(); + } + /** * Turns the camera via GLStateManager - * @param pitch The pi + * @param pitch The pitch * @param yaw The yaw - * @see com.minecrafttas.tasmod.virtual.VirtualInput.VirtualCameraAngleInput#getInterpolatedState(float, float, float, boolean) + * @see com.minecrafttas.tasmod.virtual.VirtualInterpolationHandler#getInterpolatedState(float, float, float, boolean) * @return The redirected yaw */ private float redirectCam(float pitch, float yaw) { - Triple interpolated = TASmodClient.virtual.interpolationHandler.getInterpolatedState(Minecraft.getMinecraft().timer.renderPartialTicks, pitch, yaw, TASmodClient.controller.isPlayingback()); - float pitch2 = interpolated.getLeft(); - float yaw2 = interpolated.getMiddle(); + CameraInterpolation interpolated = TASmodClient.virtual.interpolationHandler.getInterpolatedState(Minecraft.getMinecraft().timer.renderPartialTicks, pitch, yaw, TASmodClient.controller.isPlayingback()); + float pitch2 = interpolated.getPitch(); + float yaw2 = interpolated.getYaw(); // Update pitch GlStateManager.rotate(pitch2, 1.0f, 0.0f, 0.0f); - // Update roll - GlStateManager.rotate(interpolated.getRight(), 0.0f, 0.0f, 1.0f); // Update yaw return yaw2; } - - @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getX()I", remap = false)) - public int redirect_updateCameraAndRendererX() { - int interpolatedX = TASmodClient.virtual.interpolationHandler.getInterpolatedX(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback()); - return interpolatedX; - } - - @Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getY()I", remap = false)) - public int redirect_updateCameraAndRendererY() { - int interpolatedY = TASmodClient.virtual.interpolationHandler.getInterpolatedY(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback()); - return interpolatedY; - } } diff --git a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInterpolationHandler.java b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInterpolationHandler.java index 9cdffa98..9b861940 100644 --- a/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInterpolationHandler.java +++ b/src/main/java/com/minecrafttas/tasmod/virtual/VirtualInterpolationHandler.java @@ -3,10 +3,9 @@ import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.tuple.Triple; - import com.minecrafttas.tasmod.TASmodClient; import com.minecrafttas.tasmod.events.EventVirtualInput; +import com.minecrafttas.tasmod.playback.PlaybackControllerClient; import com.minecrafttas.tasmod.util.Ducks.GuiScreenDuck; import com.minecrafttas.tasmod.util.PointerNormalizer; @@ -15,63 +14,101 @@ public class VirtualInterpolationHandler implements EventVirtualInput.EventVirtualMouseTick, EventVirtualInput.EventVirtualCameraAngleTick { - private final List mousePointerInterpolationStates = new ArrayList<>(); /** - * States of the {@link #nextCameraAngle} made during the tick.
- * Is updated in {@link #nextCameraTick()} + * Copy of the {@link PlaybackControllerClient#nextPlaybackMouse} */ - private final List cameraAngleInterpolationStates = new ArrayList<>(); - private VirtualMouse nextMouse = new VirtualMouse(); + /** + * Copy of the {@link VirtualInput#CAMERA_ANGLE#nextCameraAngle} + */ private VirtualCameraAngle nextCameraAngle = new VirtualCameraAngle(); - public int getInterpolatedX(float partialTick, boolean enable) { - - int interpolatedPointerX = nextMouse.getCursorX(); - - if (enable && !mousePointerInterpolationStates.isEmpty()) { - int index = (int) MathHelper.clampedLerp(0, mousePointerInterpolationStates.size() - 1, partialTick); // Get interpolate index - - VirtualMouse interpolatedCamera = mousePointerInterpolationStates.get(index); - - interpolatedPointerX = interpolatedCamera.getCursorX(); - - } - Minecraft mc = Minecraft.getMinecraft(); - GuiScreenDuck gui = (GuiScreenDuck) mc.currentScreen; + /** + * States of the {@link #nextMouse} made during the tick.
+ * Is updated in {@link #onVirtualMouseTick()} + */ + private final List mousePointerStates = new ArrayList<>(); + /** + * States of the {@link #nextCameraAngle} made during the tick.
+ * Is updated in {@link #onVirtualCameraTick()} + */ + private final List cameraAngleStates = new ArrayList<>(); +// private int debugFinalIndex = 0; - if (gui != null) { - interpolatedPointerX = gui.rescaleX(PointerNormalizer.reapplyScalingX(interpolatedPointerX)); - } + @Override + public VirtualMouse onVirtualMouseTick(VirtualMouse vmouse) { + this.nextMouse = vmouse; +// if (TASmodClient.controller.isPlayingback()) { +// System.out.println(debugFinalIndex == mousePointerInterpolationStates.size() - 1); +// } + mousePointerStates.clear(); + TASmodClient.controller.getNextMouse().getStates(mousePointerStates); + return null; + } - return interpolatedPointerX; + @Override + public VirtualCameraAngle onVirtualCameraTick(VirtualCameraAngle vcamera) { + this.nextCameraAngle = vcamera; + cameraAngleStates.clear(); + nextCameraAngle.getStates(cameraAngleStates); + return null; } - public int getInterpolatedY(float partialTick, boolean enable) { + /** + * Interpolates the mouse cursor inbetween ticks based on the data from the next tick + * + * @param partialTick The partial ticks used for interpolating + * @param enable If the interpolation should be enabled. Basically if {@link PlaybackControllerClient#isPlayingback()} + * @return A {@link MouseInterpolation} object with x and y coordinates + */ + public MouseInterpolation getInterpolatedMouseCursor(float partialTick, boolean enable) { + int interpolatedPointerX = nextMouse.getCursorX(); int interpolatedPointerY = nextMouse.getCursorY(); - if (enable && !mousePointerInterpolationStates.isEmpty()) { - int index = (int) MathHelper.clampedLerp(0, mousePointerInterpolationStates.size() - 1, partialTick); // Get interpolate index - - VirtualMouse interpolatedCamera = mousePointerInterpolationStates.get(index); + if (enable && !mousePointerStates.isEmpty()) { + partialTick = dynamicallyRound(partialTick, TASmodClient.tickratechanger.ticksPerSecond); + int index = (int) MathHelper.clampedLerp(0, mousePointerStates.size() - 1, partialTick); // Get interpolate index +// debugFinalIndex = index; + VirtualMouse interpolatedCamera = mousePointerStates.get(index); + interpolatedPointerX = interpolatedCamera.getCursorX(); interpolatedPointerY = interpolatedCamera.getCursorY(); } - Minecraft mc = Minecraft.getMinecraft(); GuiScreenDuck gui = (GuiScreenDuck) mc.currentScreen; if (gui != null) { + interpolatedPointerX = gui.rescaleX(PointerNormalizer.reapplyScalingX(interpolatedPointerX)); interpolatedPointerY = gui.rescaleY(PointerNormalizer.reapplyScalingY(interpolatedPointerY)); } - return interpolatedPointerY; + return new MouseInterpolation(interpolatedPointerX, interpolatedPointerY); + } + + /** + * Rounds the partial tick to 1 depending on the tickrate + * + * To correctly play back the mouse cursor, the partial ticks have to reach 1 at some point. + * However this is not the case in higher tickrates. + * The solution is to round the partial ticks to 1 after a certain threshold. + * + * The higher the tps, the lower the threshold for rounding. + * + * @param partialTick The partial ticks to round + * @param tps The ticks per second used for setting the threshold + * @return The rounded partial ticks + */ + private float dynamicallyRound(float partialTick, float tps) { + float percent = tps / 100; + if (partialTick > 1 - percent) + partialTick = 1; + return partialTick; } /** - * Gets the absolute coordinates of the camera angle + * Gets the interpolated coordinates of the camera angle * * @param partialTick The partial ticks of the timer * @param pitch The original pitch of the camera @@ -79,36 +116,74 @@ public int getInterpolatedY(float partialTick, boolean enable) { * @param enable Whether the custom interpolation is enabled. Enabled during playback. * @return A triple of pitch, yaw and roll, as left, middle and right respectively */ - public Triple getInterpolatedState(float partialTick, float pitch, float yaw, boolean enable) { + public CameraInterpolation getInterpolatedState(float partialTick, float pitch, float yaw, boolean enable) { float interpolatedPitch = nextCameraAngle.getPitch() == null ? pitch : nextCameraAngle.getPitch(); float interpolatedYaw = nextCameraAngle.getYaw() == null ? yaw : nextCameraAngle.getYaw() + 180; - if (enable && !cameraAngleInterpolationStates.isEmpty()) { - int index = (int) MathHelper.clampedLerp(0, cameraAngleInterpolationStates.size() - 1, partialTick); // Get interpolate index + if (enable && !cameraAngleStates.isEmpty()) { + int index = (int) MathHelper.clampedLerp(0, cameraAngleStates.size() - 1, partialTick); // Get interpolate index - VirtualCameraAngle interpolatedCamera = cameraAngleInterpolationStates.get(index); + VirtualCameraAngle interpolatedCamera = cameraAngleStates.get(index); interpolatedPitch = interpolatedCamera.getPitch() == null ? 0 : interpolatedCamera.getPitch(); interpolatedYaw = interpolatedCamera.getYaw() == null ? 0 : interpolatedCamera.getYaw() + 180; } - return Triple.of(interpolatedPitch, interpolatedYaw, 0f); + return new CameraInterpolation(interpolatedPitch, interpolatedYaw); } - @Override - public VirtualMouse onVirtualMouseTick(VirtualMouse vmouse) { - this.nextMouse = vmouse; - mousePointerInterpolationStates.clear(); - TASmodClient.controller.getNextMouse().getStates(mousePointerInterpolationStates); - return null; + public static class MouseInterpolation { + final Integer x; + final Integer y; + + public MouseInterpolation(Integer x, Integer y) { + this.x = x; + this.y = y; + } + + public Integer getX() { + return x; + } + + public Integer getY() { + return y; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MouseInterpolation) { + MouseInterpolation other = (MouseInterpolation) obj; + return this.x.equals(other.x) && this.y.equals(other.y); + } + return super.equals(obj); + } } - @Override - public VirtualCameraAngle onVirtualCameraTick(VirtualCameraAngle vcamera) { - this.nextCameraAngle = vcamera; - cameraAngleInterpolationStates.clear(); - nextCameraAngle.getStates(cameraAngleInterpolationStates); - return null; + public static class CameraInterpolation { + final Float pitch; + final Float yaw; + + public CameraInterpolation(Float pitch, Float yaw) { + this.pitch = pitch; + this.yaw = yaw; + } + + public Float getPitch() { + return pitch; + } + + public Float getYaw() { + return yaw; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CameraInterpolation) { + CameraInterpolation other = (CameraInterpolation) obj; + return this.pitch.equals(other.pitch) && this.yaw.equals(other.yaw); + } + return super.equals(obj); + } } } diff --git a/src/test/java/tasmod/virtual/VirtualInputTest.java b/src/test/java/tasmod/virtual/VirtualInputTest.java index f77ab792..e7ca7aaf 100644 --- a/src/test/java/tasmod/virtual/VirtualInputTest.java +++ b/src/test/java/tasmod/virtual/VirtualInputTest.java @@ -5,7 +5,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import org.apache.commons.lang3.tuple.Triple; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.BeforeAll; @@ -15,6 +14,7 @@ import com.minecrafttas.tasmod.events.EventVirtualInput; import com.minecrafttas.tasmod.virtual.VirtualCameraAngle; import com.minecrafttas.tasmod.virtual.VirtualInput; +import com.minecrafttas.tasmod.virtual.VirtualInterpolationHandler.CameraInterpolation; import com.minecrafttas.tasmod.virtual.VirtualKey; import com.minecrafttas.tasmod.virtual.VirtualKeyboard; import com.minecrafttas.tasmod.virtual.VirtualMouse; @@ -281,8 +281,8 @@ void testInterpolationDisabled() { virtual.CAMERA_ANGLE.updateNextCameraAngle(20f, 30f); virtual.CAMERA_ANGLE.nextCameraTick(); - Triple expected = Triple.of(30f, 50f + 180f, 0f); - Triple actual = virtual.interpolationHandler.getInterpolatedState(0f, 1f, 2f, false); + CameraInterpolation expected = new CameraInterpolation(30f, 50f + 180f); + CameraInterpolation actual = virtual.interpolationHandler.getInterpolatedState(0f, 1f, 2f, false); assertEquals(expected, actual); EventListenerRegistry.unregister(virtual.interpolationHandler); @@ -310,35 +310,35 @@ void testInterpolationEnabled() { virtual.CAMERA_ANGLE.nextCameraTick(); - Triple expected = Triple.of(0f, 180f, 0f); - Triple actual = virtual.interpolationHandler.getInterpolatedState(0f, 0f, 0f, true); + CameraInterpolation expected = new CameraInterpolation(0f, 180f); + CameraInterpolation actual = virtual.interpolationHandler.getInterpolatedState(0f, 0f, 0f, true); assertEquals(expected, actual); - expected = Triple.of(0f, 180f, 0f); + expected = new CameraInterpolation(0f, 180f); actual = virtual.interpolationHandler.getInterpolatedState(0.1f, 0f, 0f, true); assertEquals(expected, actual); - expected = Triple.of(10f, 190f, 0f); + expected = new CameraInterpolation(10f, 190f); actual = virtual.interpolationHandler.getInterpolatedState(0.199f, 0f, 0f, true); assertEquals(expected, actual); - expected = Triple.of(10f, 190f, 0f); + expected = new CameraInterpolation(10f, 190f); actual = virtual.interpolationHandler.getInterpolatedState(0.2f, 0f, 0f, true); assertEquals(expected, actual); - expected = Triple.of(20f, 200f, 0f); + expected = new CameraInterpolation(20f, 200f); actual = virtual.interpolationHandler.getInterpolatedState(0.3f, 0f, 0f, true); assertEquals(expected, actual); - expected = Triple.of(30f, 210f, 0f); + expected = new CameraInterpolation(30f, 210f); actual = virtual.interpolationHandler.getInterpolatedState(0.4f, 0f, 0f, true); assertEquals(expected, actual); - expected = Triple.of(40f, 220f, 0f); + expected = new CameraInterpolation(40f, 220f); actual = virtual.interpolationHandler.getInterpolatedState(0.5f, 0f, 0f, true); assertEquals(expected, actual); - expected = Triple.of(50f, 230f, 0f); + expected = new CameraInterpolation(50f, 230f); actual = virtual.interpolationHandler.getInterpolatedState(0.6f, 0f, 0f, true); assertEquals(expected, actual); From 8722ef801a8ab409c5ce954d20bb2f928f1366c5 Mon Sep 17 00:00:00 2001 From: Scribble Date: Fri, 18 Jul 2025 23:09:31 +0200 Subject: [PATCH 9/9] [PlaybackController] Replace a method with event --- .../com/minecrafttas/tasmod/events/EventClient.java | 12 ++++++++++++ .../tasmod/mixin/playbackhooks/MixinGuiScreen.java | 4 +++- .../tasmod/playback/PlaybackControllerClient.java | 6 +++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/minecrafttas/tasmod/events/EventClient.java b/src/main/java/com/minecrafttas/tasmod/events/EventClient.java index fdd53517..7c4a4a6e 100644 --- a/src/main/java/com/minecrafttas/tasmod/events/EventClient.java +++ b/src/main/java/com/minecrafttas/tasmod/events/EventClient.java @@ -3,6 +3,7 @@ import com.minecrafttas.mctcommon.events.EventListenerRegistry.EventBase; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; /** * TASmod specific events fired on the client side @@ -22,6 +23,17 @@ public static interface EventDrawHotbar extends EventBase { public void onDrawHotbar(); } + /** + * Fired when a screen in a gui is drawn + */ + @FunctionalInterface + public static interface EventDrawScreen extends EventBase { + /** + * Fired when a screen in a gui is drawn + */ + public void onDrawScreen(GuiScreen screen, int xCoordinate, int yCoordinate); + } + /** * Fired when drawing something on screen. Ignores F1 */ diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinGuiScreen.java b/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinGuiScreen.java index 7702333d..ed386307 100644 --- a/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinGuiScreen.java +++ b/src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinGuiScreen.java @@ -7,7 +7,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.EventDrawScreen; import com.minecrafttas.tasmod.util.Ducks.GuiScreenDuck; import com.minecrafttas.tasmod.virtual.VirtualInput; import com.minecrafttas.tasmod.virtual.event.VirtualKeyboardEvent; @@ -107,7 +109,7 @@ private static boolean redirectIsAltKeyDown(int i) { @Inject(method = "drawScreen", at = @At("HEAD")) private void injectDrawScreen(int i, int j, float f, CallbackInfo ci) { - TASmodClient.controller.onDrawScreen((GuiScreen) (Object) this, i, j); // TODO Replace with event + EventListenerRegistry.fireEvent(EventDrawScreen.class, (GuiScreen) (Object) this, i, j); } @Shadow diff --git a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java index 6bad3ba5..07684e67 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java @@ -38,6 +38,7 @@ import com.minecrafttas.tasmod.TASmod; import com.minecrafttas.tasmod.TASmodClient; import com.minecrafttas.tasmod.events.EventClient.EventClientTickPost; +import com.minecrafttas.tasmod.events.EventClient.EventDrawScreen; import com.minecrafttas.tasmod.events.EventPlaybackClient; import com.minecrafttas.tasmod.events.EventPlaybackClient.EventControllerStateChange; import com.minecrafttas.tasmod.events.EventPlaybackClient.EventPlaybackJoinedWorld; @@ -95,6 +96,7 @@ public class PlaybackControllerClient implements EventClientInit, EventClientTickPost, + EventDrawScreen, EventVirtualInput.EventVirtualKeyboardTick, EventVirtualInput.EventVirtualMouseTick, @@ -429,8 +431,10 @@ public VirtualCameraAngle onVirtualCameraTick(VirtualCameraAngle vcamera) { } /** - * Updates the cursor location on screen + * {@inheritDoc} + *

Updates the cursor location on screen */ + @Override public void onDrawScreen(GuiScreen screen, int x, int y) { if (!isPlayingback()) return;