Skip to content

Commit 7fdf347

Browse files
committed
[VirtualInput] Cleanup and documentation
1 parent 729743d commit 7fdf347

File tree

5 files changed

+162
-86
lines changed

5 files changed

+162
-86
lines changed

src/main/java/com/minecrafttas/mctcommon/events/EventListenerRegistry.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,7 @@ public static Object fireEvent(Class<? extends EventListenerRegistry.EventBase>
235235
// Iterate through all methods
236236
for (Method method : methodsInListener) {
237237

238-
// Check if the current method has the same name as the method we are looking
239-
// for
238+
// Check if the current method has the same name as the method we are looking for
240239
if (!checkName(method, methodToFind.getName())) {
241240
continue;
242241
}

src/main/java/com/minecrafttas/tasmod/gui/InfoHud.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.minecrafttas.tasmod.playback.PlaybackControllerClient.TASstate;
2323
import com.minecrafttas.tasmod.playback.filecommands.builtin.DesyncMonitorFileCommandExtension;
2424
import com.minecrafttas.tasmod.virtual.VirtualInput;
25+
import com.minecrafttas.tasmod.virtual.VirtualInterpolationHandler.MouseInterpolation;
2526
import com.mojang.realmsclient.gui.ChatFormatting;
2627

2728
import net.minecraft.client.Minecraft;
@@ -390,8 +391,9 @@ public boolean checkInit() {
390391
if (Minecraft.getMinecraft().currentScreen == this)
391392
return "Mouse Position";
392393

393-
Integer xCursor = TASmodClient.virtual.interpolationHandler.getInterpolatedX(0, false);
394-
Integer yCursor = TASmodClient.virtual.interpolationHandler.getInterpolatedY(0, false);
394+
MouseInterpolation mouseInterpolation = TASmodClient.virtual.interpolationHandler.getInterpolatedMouseCursor(0, false);
395+
Integer xCursor = mouseInterpolation.getX();
396+
Integer yCursor = mouseInterpolation.getY();
395397

396398
if (Minecraft.getMinecraft().currentScreen != null)
397399
return String.format("Mouse Cursor: %s %s", xCursor == null ? "null" : xCursor, yCursor == null ? "null" : yCursor);

src/main/java/com/minecrafttas/tasmod/mixin/playbackhooks/MixinEntityRenderer.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.minecrafttas.tasmod.mixin.playbackhooks;
22

3-
import org.apache.commons.lang3.tuple.Triple;
43
import org.spongepowered.asm.mixin.Mixin;
54
import org.spongepowered.asm.mixin.Shadow;
65
import org.spongepowered.asm.mixin.injection.At;
@@ -11,11 +10,14 @@
1110

1211
import com.llamalad7.mixinextras.sugar.Share;
1312
import com.llamalad7.mixinextras.sugar.ref.LocalFloatRef;
13+
import com.llamalad7.mixinextras.sugar.ref.LocalIntRef;
1414
import com.minecrafttas.mctcommon.events.EventListenerRegistry;
1515
import com.minecrafttas.tasmod.TASmodClient;
1616
import com.minecrafttas.tasmod.events.EventClient.EventDrawHotbarAlways;
1717
import com.minecrafttas.tasmod.util.Ducks.SubtickDuck;
1818
import com.minecrafttas.tasmod.virtual.VirtualInput;
19+
import com.minecrafttas.tasmod.virtual.VirtualInterpolationHandler.CameraInterpolation;
20+
import com.minecrafttas.tasmod.virtual.VirtualInterpolationHandler.MouseInterpolation;
1921

2022
import net.minecraft.client.Minecraft;
2123
import net.minecraft.client.entity.EntityPlayerSP;
@@ -193,34 +195,32 @@ public void playback_updateOverlay(CallbackInfo ci) {
193195
EventListenerRegistry.fireEvent(EventDrawHotbarAlways.class);
194196
}
195197

198+
@Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getX()I", remap = false))
199+
public int redirect_updateCameraAndRendererX(@Share(value = "interpolatedY") LocalIntRef shared) {
200+
MouseInterpolation interpolated = TASmodClient.virtual.interpolationHandler.getInterpolatedMouseCursor(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback());
201+
shared.set(interpolated.getY());
202+
return interpolated.getX();
203+
}
204+
205+
@Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getY()I", remap = false))
206+
public int redirect_updateCameraAndRendererY(@Share(value = "interpolatedY") LocalIntRef shared) {
207+
return shared.get();
208+
}
209+
196210
/**
197211
* Turns the camera via GLStateManager
198-
* @param pitch The pi
212+
* @param pitch The pitch
199213
* @param yaw The yaw
200-
* @see com.minecrafttas.tasmod.virtual.VirtualInput.VirtualCameraAngleInput#getInterpolatedState(float, float, float, boolean)
214+
* @see com.minecrafttas.tasmod.virtual.VirtualInterpolationHandler#getInterpolatedState(float, float, float, boolean)
201215
* @return The redirected yaw
202216
*/
203217
private float redirectCam(float pitch, float yaw) {
204-
Triple<Float, Float, Float> interpolated = TASmodClient.virtual.interpolationHandler.getInterpolatedState(Minecraft.getMinecraft().timer.renderPartialTicks, pitch, yaw, TASmodClient.controller.isPlayingback());
205-
float pitch2 = interpolated.getLeft();
206-
float yaw2 = interpolated.getMiddle();
218+
CameraInterpolation interpolated = TASmodClient.virtual.interpolationHandler.getInterpolatedState(Minecraft.getMinecraft().timer.renderPartialTicks, pitch, yaw, TASmodClient.controller.isPlayingback());
219+
float pitch2 = interpolated.getPitch();
220+
float yaw2 = interpolated.getYaw();
207221
// Update pitch
208222
GlStateManager.rotate(pitch2, 1.0f, 0.0f, 0.0f);
209-
// Update roll
210-
GlStateManager.rotate(interpolated.getRight(), 0.0f, 0.0f, 1.0f);
211223
// Update yaw
212224
return yaw2;
213225
}
214-
215-
@Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getX()I", remap = false))
216-
public int redirect_updateCameraAndRendererX() {
217-
int interpolatedX = TASmodClient.virtual.interpolationHandler.getInterpolatedX(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback());
218-
return interpolatedX;
219-
}
220-
221-
@Redirect(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lorg/lwjgl/input/Mouse;getY()I", remap = false))
222-
public int redirect_updateCameraAndRendererY() {
223-
int interpolatedY = TASmodClient.virtual.interpolationHandler.getInterpolatedY(Minecraft.getMinecraft().timer.renderPartialTicks, TASmodClient.controller.isPlayingback());
224-
return interpolatedY;
225-
}
226226
}

src/main/java/com/minecrafttas/tasmod/virtual/VirtualInterpolationHandler.java

Lines changed: 125 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
import java.util.ArrayList;
44
import java.util.List;
55

6-
import org.apache.commons.lang3.tuple.Triple;
7-
86
import com.minecrafttas.tasmod.TASmodClient;
97
import com.minecrafttas.tasmod.events.EventVirtualInput;
8+
import com.minecrafttas.tasmod.playback.PlaybackControllerClient;
109
import com.minecrafttas.tasmod.util.Ducks.GuiScreenDuck;
1110
import com.minecrafttas.tasmod.util.PointerNormalizer;
1211

@@ -15,100 +14,176 @@
1514

1615
public class VirtualInterpolationHandler implements EventVirtualInput.EventVirtualMouseTick, EventVirtualInput.EventVirtualCameraAngleTick {
1716

18-
private final List<VirtualMouse> mousePointerInterpolationStates = new ArrayList<>();
1917
/**
20-
* States of the {@link #nextCameraAngle} made during the tick.<br>
21-
* Is updated in {@link #nextCameraTick()}
18+
* Copy of the {@link PlaybackControllerClient#nextPlaybackMouse}
2219
*/
23-
private final List<VirtualCameraAngle> cameraAngleInterpolationStates = new ArrayList<>();
24-
2520
private VirtualMouse nextMouse = new VirtualMouse();
21+
/**
22+
* Copy of the {@link VirtualInput#CAMERA_ANGLE#nextCameraAngle}
23+
*/
2624
private VirtualCameraAngle nextCameraAngle = new VirtualCameraAngle();
2725

28-
public int getInterpolatedX(float partialTick, boolean enable) {
29-
30-
int interpolatedPointerX = nextMouse.getCursorX();
31-
32-
if (enable && !mousePointerInterpolationStates.isEmpty()) {
33-
int index = (int) MathHelper.clampedLerp(0, mousePointerInterpolationStates.size() - 1, partialTick); // Get interpolate index
34-
35-
VirtualMouse interpolatedCamera = mousePointerInterpolationStates.get(index);
36-
37-
interpolatedPointerX = interpolatedCamera.getCursorX();
38-
39-
}
40-
Minecraft mc = Minecraft.getMinecraft();
41-
GuiScreenDuck gui = (GuiScreenDuck) mc.currentScreen;
26+
/**
27+
* States of the {@link #nextMouse} made during the tick.<br>
28+
* Is updated in {@link #onVirtualMouseTick()}
29+
*/
30+
private final List<VirtualMouse> mousePointerStates = new ArrayList<>();
31+
/**
32+
* States of the {@link #nextCameraAngle} made during the tick.<br>
33+
* Is updated in {@link #onVirtualCameraTick()}
34+
*/
35+
private final List<VirtualCameraAngle> cameraAngleStates = new ArrayList<>();
36+
// private int debugFinalIndex = 0;
4237

43-
if (gui != null) {
44-
interpolatedPointerX = gui.rescaleX(PointerNormalizer.reapplyScalingX(interpolatedPointerX));
45-
}
38+
@Override
39+
public VirtualMouse onVirtualMouseTick(VirtualMouse vmouse) {
40+
this.nextMouse = vmouse;
41+
// if (TASmodClient.controller.isPlayingback()) {
42+
// System.out.println(debugFinalIndex == mousePointerInterpolationStates.size() - 1);
43+
// }
44+
mousePointerStates.clear();
45+
TASmodClient.controller.getNextMouse().getStates(mousePointerStates);
46+
return null;
47+
}
4648

47-
return interpolatedPointerX;
49+
@Override
50+
public VirtualCameraAngle onVirtualCameraTick(VirtualCameraAngle vcamera) {
51+
this.nextCameraAngle = vcamera;
52+
cameraAngleStates.clear();
53+
nextCameraAngle.getStates(cameraAngleStates);
54+
return null;
4855
}
4956

50-
public int getInterpolatedY(float partialTick, boolean enable) {
57+
/**
58+
* Interpolates the mouse cursor inbetween ticks based on the data from the next tick
59+
*
60+
* @param partialTick The partial ticks used for interpolating
61+
* @param enable If the interpolation should be enabled. Basically if {@link PlaybackControllerClient#isPlayingback()}
62+
* @return A {@link MouseInterpolation} object with x and y coordinates
63+
*/
64+
public MouseInterpolation getInterpolatedMouseCursor(float partialTick, boolean enable) {
5165

66+
int interpolatedPointerX = nextMouse.getCursorX();
5267
int interpolatedPointerY = nextMouse.getCursorY();
5368

54-
if (enable && !mousePointerInterpolationStates.isEmpty()) {
55-
int index = (int) MathHelper.clampedLerp(0, mousePointerInterpolationStates.size() - 1, partialTick); // Get interpolate index
56-
57-
VirtualMouse interpolatedCamera = mousePointerInterpolationStates.get(index);
69+
if (enable && !mousePointerStates.isEmpty()) {
70+
partialTick = dynamicallyRound(partialTick, TASmodClient.tickratechanger.ticksPerSecond);
71+
int index = (int) MathHelper.clampedLerp(0, mousePointerStates.size() - 1, partialTick); // Get interpolate index
72+
// debugFinalIndex = index;
73+
VirtualMouse interpolatedCamera = mousePointerStates.get(index);
5874

75+
interpolatedPointerX = interpolatedCamera.getCursorX();
5976
interpolatedPointerY = interpolatedCamera.getCursorY();
6077

6178
}
62-
6379
Minecraft mc = Minecraft.getMinecraft();
6480
GuiScreenDuck gui = (GuiScreenDuck) mc.currentScreen;
6581

6682
if (gui != null) {
83+
interpolatedPointerX = gui.rescaleX(PointerNormalizer.reapplyScalingX(interpolatedPointerX));
6784
interpolatedPointerY = gui.rescaleY(PointerNormalizer.reapplyScalingY(interpolatedPointerY));
6885
}
6986

70-
return interpolatedPointerY;
87+
return new MouseInterpolation(interpolatedPointerX, interpolatedPointerY);
88+
}
89+
90+
/**
91+
* Rounds the partial tick to 1 depending on the tickrate
92+
*
93+
* To correctly play back the mouse cursor, the partial ticks have to reach 1 at some point.
94+
* However this is not the case in higher tickrates.
95+
* The solution is to round the partial ticks to 1 after a certain threshold.
96+
*
97+
* The higher the tps, the lower the threshold for rounding.
98+
*
99+
* @param partialTick The partial ticks to round
100+
* @param tps The ticks per second used for setting the threshold
101+
* @return The rounded partial ticks
102+
*/
103+
private float dynamicallyRound(float partialTick, float tps) {
104+
float percent = tps / 100;
105+
if (partialTick > 1 - percent)
106+
partialTick = 1;
107+
return partialTick;
71108
}
72109

73110
/**
74-
* Gets the absolute coordinates of the camera angle
111+
* Gets the interpolated coordinates of the camera angle
75112
*
76113
* @param partialTick The partial ticks of the timer
77114
* @param pitch The original pitch of the camera
78115
* @param yaw The original yaw of the camera
79116
* @param enable Whether the custom interpolation is enabled. Enabled during playback.
80117
* @return A triple of pitch, yaw and roll, as left, middle and right respectively
81118
*/
82-
public Triple<Float, Float, Float> getInterpolatedState(float partialTick, float pitch, float yaw, boolean enable) {
119+
public CameraInterpolation getInterpolatedState(float partialTick, float pitch, float yaw, boolean enable) {
83120

84121
float interpolatedPitch = nextCameraAngle.getPitch() == null ? pitch : nextCameraAngle.getPitch();
85122
float interpolatedYaw = nextCameraAngle.getYaw() == null ? yaw : nextCameraAngle.getYaw() + 180;
86123

87-
if (enable && !cameraAngleInterpolationStates.isEmpty()) {
88-
int index = (int) MathHelper.clampedLerp(0, cameraAngleInterpolationStates.size() - 1, partialTick); // Get interpolate index
124+
if (enable && !cameraAngleStates.isEmpty()) {
125+
int index = (int) MathHelper.clampedLerp(0, cameraAngleStates.size() - 1, partialTick); // Get interpolate index
89126

90-
VirtualCameraAngle interpolatedCamera = cameraAngleInterpolationStates.get(index);
127+
VirtualCameraAngle interpolatedCamera = cameraAngleStates.get(index);
91128

92129
interpolatedPitch = interpolatedCamera.getPitch() == null ? 0 : interpolatedCamera.getPitch();
93130
interpolatedYaw = interpolatedCamera.getYaw() == null ? 0 : interpolatedCamera.getYaw() + 180;
94131

95132
}
96-
return Triple.of(interpolatedPitch, interpolatedYaw, 0f);
133+
return new CameraInterpolation(interpolatedPitch, interpolatedYaw);
97134
}
98135

99-
@Override
100-
public VirtualMouse onVirtualMouseTick(VirtualMouse vmouse) {
101-
this.nextMouse = vmouse;
102-
mousePointerInterpolationStates.clear();
103-
TASmodClient.controller.getNextMouse().getStates(mousePointerInterpolationStates);
104-
return null;
136+
public static class MouseInterpolation {
137+
final Integer x;
138+
final Integer y;
139+
140+
public MouseInterpolation(Integer x, Integer y) {
141+
this.x = x;
142+
this.y = y;
143+
}
144+
145+
public Integer getX() {
146+
return x;
147+
}
148+
149+
public Integer getY() {
150+
return y;
151+
}
152+
153+
@Override
154+
public boolean equals(Object obj) {
155+
if (obj instanceof MouseInterpolation) {
156+
MouseInterpolation other = (MouseInterpolation) obj;
157+
return this.x.equals(other.x) && this.y.equals(other.y);
158+
}
159+
return super.equals(obj);
160+
}
105161
}
106162

107-
@Override
108-
public VirtualCameraAngle onVirtualCameraTick(VirtualCameraAngle vcamera) {
109-
this.nextCameraAngle = vcamera;
110-
cameraAngleInterpolationStates.clear();
111-
nextCameraAngle.getStates(cameraAngleInterpolationStates);
112-
return null;
163+
public static class CameraInterpolation {
164+
final Float pitch;
165+
final Float yaw;
166+
167+
public CameraInterpolation(Float pitch, Float yaw) {
168+
this.pitch = pitch;
169+
this.yaw = yaw;
170+
}
171+
172+
public Float getPitch() {
173+
return pitch;
174+
}
175+
176+
public Float getYaw() {
177+
return yaw;
178+
}
179+
180+
@Override
181+
public boolean equals(Object obj) {
182+
if (obj instanceof CameraInterpolation) {
183+
CameraInterpolation other = (CameraInterpolation) obj;
184+
return this.pitch.equals(other.pitch) && this.yaw.equals(other.yaw);
185+
}
186+
return super.equals(obj);
187+
}
113188
}
114189
}

0 commit comments

Comments
 (0)