Skip to content

[VirtualInput] Fix crash when playing back while changing dimensions #248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,19 @@ public static interface EventDoneLoadingWorld extends EventBase {
}

/**
* Fired when the player is done loading, after the position has been loaded from the server side
* Fired when the player is done loading, after the position has been loaded from the server side.<br>
* This also fires every time the player switches dimensions.
*
* @author Scribble
* @see NetHandlerPlayClient#handlePlayerPosLook(net.minecraft.network.play.server.SPacketPlayerPosLook)
*/
@FunctionalInterface
public static interface EventDoneLoadingPlayer extends EventBase {

/**
* Fired when the player is done loading, after the position has been loaded from the server side
* Fired when the player is done loading, after the position has been loaded from the server side.<br>
* This also fires every time the player switches dimensions.
*
* @see NetHandlerPlayClient#handlePlayerPosLook(net.minecraft.network.play.server.SPacketPlayerPosLook)
*/
public void onDoneLoadingPlayer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,23 @@
import com.minecrafttas.mctcommon.events.EventClient.EventDoneLoadingPlayer;
import com.minecrafttas.mctcommon.events.EventClient.EventDoneLoadingWorld;
import com.minecrafttas.mctcommon.events.EventClient.EventLaunchIntegratedServer;
import com.minecrafttas.mctcommon.events.EventClient.EventPlayerJoinedClientSide;
import com.minecrafttas.mctcommon.events.EventClient.EventPlayerLeaveClientSide;
import com.minecrafttas.tasmod.TASmod;
import com.minecrafttas.tasmod.TASmodClient;
import com.minecrafttas.tasmod.mixin.playbackhooks.MixinEntityRenderer;
import com.minecrafttas.tasmod.playback.PlaybackControllerClient;
import com.minecrafttas.tasmod.util.LoggerMarkers;
import com.minecrafttas.tasmod.virtual.VirtualInput;
import com.minecrafttas.tasmod.virtual.VirtualInput.VirtualCameraAngleInput;

import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;

/**
* Handles logic during a loading screen to transition between states.
*
* @author Scribble
*/
public class LoadingScreenHandler implements EventLaunchIntegratedServer, EventClientGameLoop, EventDoneLoadingWorld, EventDoneLoadingPlayer {
public class LoadingScreenHandler implements EventLaunchIntegratedServer, EventClientGameLoop, EventDoneLoadingWorld, EventDoneLoadingPlayer, EventPlayerJoinedClientSide, EventPlayerLeaveClientSide {

private boolean waszero;
private boolean isLoading;
Expand Down Expand Up @@ -75,22 +77,40 @@ public boolean isLoading() {
/**
* {@inheritDoc}
*
* <p>Fixes an issue, where the look position of the player is reset to 0 -180,<br>
* As well as removing any keyboard inputs present in the main menu
*
* <p>{@link MixinEntityRenderer#runUpdate(float)} rewrites the camera input,<br>
* So that it can be used with interpolation. <br>
* However, when you start the game, this camera input needs to be initialised with the current look position from the server.<br>
* So a special condition is set, that if the {@link VirtualInput#CAMERA_ANGLE} is null,<br>
* it intialises the {@link VirtualInput#CAMERA_ANGLE CAMERA_ANGLE} with the current player camera angle.
*
* <p>So {@link VirtualInput#clear()} has to be called at the right moment in the player initialisation<br>
* to set the correct values. Before that, the playerRotation defaults to 0 -180
* <p>Initializes the virtual camera to be in line with the vanilla camera.
*/
@Override
public void onDoneLoadingPlayer() {
LOGGER.debug(LoggerMarkers.Event, "Finished loading the player position on the client");
TASmodClient.virtual.clear();
VirtualCameraAngleInput cameraAngle = TASmodClient.virtual.CAMERA_ANGLE;
if (cameraAngle.getCurrentPitch() == null || cameraAngle.getCurrentYaw() == null) {
LOGGER.debug("Setting the initial pitch and yaw");
Minecraft mc = Minecraft.getMinecraft();
EntityPlayerSP player = mc.player;
cameraAngle.setCamera(player.rotationPitch, player.rotationYaw);
}
}

/**
* {@inheritDoc}
*
* <p>Fixes stuck keys when loading the world
*/
@Override
public void onPlayerJoinedClientSide(EntityPlayerSP player) {
TASmodClient.virtual.clearKeys();
}

/**
* {@inheritDoc}
*
* <p>Resets the camera angle when leaving the world.
* <p>If you later rejoin the world {@link #onDoneLoadingPlayer()} will re-initialise the camera angle
*/
@Override
public void onPlayerLeaveClientSide(EntityPlayerSP player) {
LOGGER.debug(LoggerMarkers.Event, "Finished leaving on the on the client side");
LOGGER.debug("Resetting the camera angle on leaving the world");
TASmodClient.virtual.CAMERA_ANGLE.clearNext();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@

import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalFloatRef;
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 net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.renderer.GlStateManager;

Expand Down Expand Up @@ -114,11 +117,19 @@ public void runUpdate(float partialTicks) {
Float newPitch = TASmodClient.virtual.CAMERA_ANGLE.getCurrentPitch();
Float newYaw = TASmodClient.virtual.CAMERA_ANGLE.getCurrentYaw();

// If the pitch or yaw is null (usually on initialize or when the player joins the world),
// set nextCameraAngle to the current absolute camera coordinates.
// This ensures that the camera position is loaded correctly
/*
* If the pitch or yaw is null,
* usually on initialize or when the player joins the world),
* do not update the camera angle.
*
* This is called during the loading screen for 2 game loops,
* at which point the player is not initialized,
* hence we do not have the correct camera angle yet.
*
* The angle is instead initialized in LoadingScreenHandler#onDoneLoadingPlayer.
*/
if (newPitch == null || newYaw == null) {
TASmodClient.virtual.CAMERA_ANGLE.setCamera(prevPitch, prevYaw);
// TASmodClient.virtual.CAMERA_ANGLE.setCamera(prevPitch, prevYaw);
return;
}

Expand All @@ -138,7 +149,7 @@ public void runUpdate(float partialTicks) {
* @return 0f for disabeling this method
*/
@ModifyArg(method = "orientCamera", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;rotate(FFFF)V", ordinal = 8), index = 0)
public float redirect_orientCameraPitch(float pitch, @Share("pitch") LocalFloatRef sharedPitch) {
public float playback_orientCameraPitch(float pitch, @Share("pitch") LocalFloatRef sharedPitch) {
sharedPitch.set(pitch);
return 0f;
}
Expand All @@ -150,7 +161,7 @@ public float redirect_orientCameraPitch(float pitch, @Share("pitch") LocalFloatR
* @return The redirected yaw
*/
@ModifyArg(method = "orientCamera", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;rotate(FFFF)V", ordinal = 9), index = 0)
public float redirect_orientCameraYawAnimal(float yawAnimal, @Share("pitch") LocalFloatRef sharedPitch) {
public float playback_orientCameraYawAnimal(float yawAnimal, @Share("pitch") LocalFloatRef sharedPitch) {
return redirectCam(sharedPitch.get(), yawAnimal);
}

Expand All @@ -161,10 +172,27 @@ public float redirect_orientCameraYawAnimal(float yawAnimal, @Share("pitch") Loc
* @return The redirected yaw
*/
@ModifyArg(method = "orientCamera", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;rotate(FFFF)V", ordinal = 10), index = 0)
public float redirect_orientCameraYaw(float yaw, @Share("pitch") LocalFloatRef sharedPitch) {
public float playback_orientCameraYaw(float yaw, @Share("pitch") LocalFloatRef sharedPitch) {
return redirectCam(sharedPitch.get(), yaw);
}

/**
* Updates the game overlay and adds an event
* @param ci CallBackInfo
*/
@Inject(method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V"))
public void playback_updateOverlay(CallbackInfo ci) {
ScaledResolution scaledResolution = new ScaledResolution(this.mc);
GlStateManager.clear(256);
GlStateManager.matrixMode(5889);
GlStateManager.loadIdentity();
GlStateManager.ortho(0.0, scaledResolution.getScaledWidth_double(), scaledResolution.getScaledHeight_double(), 0.0, 1000.0, 3000.0);
GlStateManager.matrixMode(5888);
GlStateManager.loadIdentity();
GlStateManager.translate(0.0F, 0.0F, -2000.0F);
EventListenerRegistry.fireEvent(EventDrawHotbarAlways.class);
}

/**
* Turns the camera via GLStateManager
* @param pitch The pi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ public String setTASStateClient(TASstate stateIn, boolean verbose) {
LOGGER.debug(LoggerMarkers.Playback, "Pausing a playback");
state = TASstate.PAUSED;
stateAfterPause = TASstate.PLAYBACK;
TASmodClient.virtual.clear();
TASmodClient.virtual.clearKeys();
return verbose ? TextFormatting.GREEN + "Pausing a playback" : "";
case NONE:
stopPlayback(true);
Expand Down Expand Up @@ -291,7 +291,7 @@ private void startRecording() {

private void stopRecording() {
LOGGER.debug(LoggerMarkers.Playback, "Stopping a recording");
TASmodClient.virtual.clear();
TASmodClient.virtual.clearKeys();
}

private void startPlayback() {
Expand All @@ -305,7 +305,7 @@ private void stopPlayback(boolean clearInputs) {
LOGGER.debug(LoggerMarkers.Playback, "Stopping a playback");
Minecraft.getMinecraft().gameSettings.chatLinks = true;
if (clearInputs) {
TASmodClient.virtual.clear();
TASmodClient.virtual.clearKeys();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ public static void loadstate(String nameOfSavestate) throws Exception {

preload(savestateContainerList, index);
controller.setInputs(savestateContainerList, index);
TASmodClient.virtual.clear();
TASmodClient.virtual.clearKeys();
}
/*
* When loading a savestate during a playback 2 different scenarios can happen.
Expand Down Expand Up @@ -237,7 +237,7 @@ else if (state == TASstate.PLAYBACK) {

preload(controller.getInputs(), index);
controller.setIndex(index);
TASmodClient.virtual.clear();
TASmodClient.virtual.clearKeys();
}
/*
* Scenario 2:
Expand Down
27 changes: 23 additions & 4 deletions src/main/java/com/minecrafttas/tasmod/virtual/VirtualInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,9 @@ public boolean willKeyBeDown(int keycode) {
/**
* Unpresses all keys in {@link VirtualKeyboardInput#nextKeyboard} and {@link VirtualMouseInput#nextMouse}
*/
public void clear() {
KEYBOARD.nextKeyboard.clear();
MOUSE.nextMouse.clear();
CAMERA_ANGLE.nextCameraAngle.clear();
public void clearKeys() {
KEYBOARD.clearNext();
MOUSE.clearNext();
}

public void preloadInput(VirtualKeyboard keyboardToPreload, VirtualMouse mouseToPreload, VirtualCameraAngle angleToPreload) {
Expand Down Expand Up @@ -340,6 +339,13 @@ public boolean isKeyDown(int keycode) {
public boolean willKeyBeDown(int keycode) {
return nextKeyboard.isKeyDown(keycode);
}

/**
* Clears the {@link #nextKeyboard}
*/
public void clearNext() {
nextKeyboard.clear();
}
}

/**
Expand Down Expand Up @@ -531,6 +537,12 @@ public boolean willKeyBeDown(int keycode) {
return nextMouse.isKeyDown(keycode);
}

/**
* Clears the {@link #nextMouse}
*/
public void clearNext() {
nextMouse.clear();
}
}

/**
Expand Down Expand Up @@ -710,5 +722,12 @@ public Triple<Float, Float, Float> getInterpolatedState(float partialTick, float
}
return Triple.of(interpolatedPitch, interpolatedYaw, 0f);
}

/**
* Clears the {@link #nextCameraAngle}
*/
public void clearNext() {
nextCameraAngle.clear();
}
}
}
1 change: 0 additions & 1 deletion src/main/resources/tasmod.mixin.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@

// Events
"events.MixinGuiIngame",
"events.MixinEntityRenderer",
"events.MixinNetHandlerPlayClient",

"clientcommands.MixinEntityPlayerSP",
Expand Down
Loading