Fix vanilla entity update packet handling (fixes #607)
This commit is contained in:
@@ -13,6 +13,12 @@ import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.render.BufferBuilder;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
//#if MC>=11604
|
||||
//#else
|
||||
//$$ import net.minecraft.entity.Entity;
|
||||
//#endif
|
||||
|
||||
//#if MC>=11600
|
||||
import net.minecraft.resource.ResourcePackSource;
|
||||
@@ -55,7 +61,6 @@ import org.lwjgl.glfw.GLFW;
|
||||
//#if MC>=10904
|
||||
import com.replaymod.render.blend.mixin.ParticleAccessor;
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
//#endif
|
||||
|
||||
//#if MC>=10800
|
||||
@@ -297,6 +302,12 @@ public class MCVer {
|
||||
}
|
||||
//#endif
|
||||
|
||||
//#if MC<=11601
|
||||
//$$ public static Vec3d getTrackedPosition(Entity entity) {
|
||||
//$$ return new Vec3d(entity.trackedX, entity.trackedY, entity.trackedZ);
|
||||
//$$ }
|
||||
//#endif
|
||||
|
||||
public static void openFile(File file) {
|
||||
//#if MC>=11400
|
||||
Util.getOperatingSystem().open(file);
|
||||
|
||||
@@ -21,6 +21,7 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.WorldChunk;
|
||||
|
||||
@@ -563,4 +564,13 @@ class Patterns {
|
||||
return new CrashException(((MinecraftAccessor) mc).getCrashReporter());
|
||||
//#endif
|
||||
}
|
||||
|
||||
@Pattern
|
||||
private static Vec3d getTrackedPosition(Entity entity) {
|
||||
//#if MC>=11604
|
||||
return entity.getTrackedPosition();
|
||||
//#else
|
||||
//$$ return com.replaymod.core.versions.MCVer.getTrackedPosition(entity);
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
|
||||
9
src/main/java/com/replaymod/replay/ext/EntityExt.java
Normal file
9
src/main/java/com/replaymod/replay/ext/EntityExt.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.replaymod.replay.ext;
|
||||
|
||||
public interface EntityExt {
|
||||
float replaymod$getTrackedYaw();
|
||||
void replaymod$setTrackedYaw(float value);
|
||||
|
||||
float replaymod$getTrackedPitch();
|
||||
void replaymod$setTrackedPitch(float value);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.replaymod.replay.mixin.entity_tracking;
|
||||
|
||||
import com.replaymod.replay.ext.EntityExt;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
@Mixin(Entity.class)
|
||||
public abstract class Mixin_EntityExt implements EntityExt {
|
||||
|
||||
@Unique
|
||||
private float trackedYaw;
|
||||
|
||||
@Unique
|
||||
private float trackedPitch;
|
||||
|
||||
@Override
|
||||
public float replaymod$getTrackedYaw() {
|
||||
return this.trackedYaw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float replaymod$getTrackedPitch() {
|
||||
return this.trackedPitch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaymod$setTrackedYaw(float value) {
|
||||
this.trackedYaw = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaymod$setTrackedPitch(float value) {
|
||||
this.trackedPitch = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.replaymod.replay.mixin.entity_tracking;
|
||||
|
||||
import com.replaymod.replay.ext.EntityExt;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* Every Entity on the client has at least two position/rotation states: The local one and the server ("tracked") one.
|
||||
* When receiving an update from the server, the server one needs to be updated and the local one will then usually be
|
||||
* interpolated to the server one within a few ticks.
|
||||
*
|
||||
* Minecraft however incorrectly implements the server rotation update for position-only update packets by
|
||||
* interpolating to the local rotation, which might not yet match the server rotation, rather than to the previously
|
||||
* received server rotation.
|
||||
* Similarly, with 1.15 and later, it incorrectly implements the server position update for rotation-only update packets
|
||||
* by interpolating to the local position rather than the server one.
|
||||
*
|
||||
* Each of these will cause the client position to be in an incorrect state until the next update packed for the
|
||||
* respective rotation/position of that entity.
|
||||
*
|
||||
* This mixin fixes those two issues by redirecting to the server rotation/position respectively.
|
||||
* Minecraft does not currently even track the server rotation, so we need to do that as well.
|
||||
*/
|
||||
@Mixin(ClientPlayNetworkHandler.class)
|
||||
public class Mixin_FixPartialUpdates {
|
||||
|
||||
//
|
||||
// Use correct rotation for position-only updates
|
||||
//
|
||||
|
||||
//#if MC>=11700
|
||||
//$$ @Redirect(method = "onEntityUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getYaw()F"))
|
||||
//#else
|
||||
@Redirect(method = "onEntityUpdate", at = @At(value = "FIELD", target = "Lnet/minecraft/entity/Entity;yaw:F", opcode = Opcodes.GETFIELD))
|
||||
//#endif
|
||||
private float getTrackedYaw(Entity instance) {
|
||||
return ((EntityExt) instance).replaymod$getTrackedYaw();
|
||||
}
|
||||
|
||||
//#if MC>=11700
|
||||
//$$ @Redirect(method = "onEntityUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getPitch()F"))
|
||||
//#else
|
||||
@Redirect(method = "onEntityUpdate", at = @At(value = "FIELD", target = "Lnet/minecraft/entity/Entity;pitch:F", opcode = Opcodes.GETFIELD))
|
||||
//#endif
|
||||
private float getTrackedPitch(Entity instance) {
|
||||
return ((EntityExt) instance).replaymod$getTrackedPitch();
|
||||
}
|
||||
|
||||
//#if MC>=11500
|
||||
//
|
||||
// Use correct position for rotation-only updates
|
||||
//
|
||||
|
||||
@Redirect(method = "onEntityUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getX()D"))
|
||||
private double getTrackedX(Entity instance) {
|
||||
return instance.getTrackedPosition().getX();
|
||||
}
|
||||
|
||||
@Redirect(method = "onEntityUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getY()D"))
|
||||
private double getTrackedY(Entity instance) {
|
||||
return instance.getTrackedPosition().getY();
|
||||
}
|
||||
|
||||
@Redirect(method = "onEntityUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getZ()D"))
|
||||
private double getTrackedZ(Entity instance) {
|
||||
return instance.getTrackedPosition().getZ();
|
||||
}
|
||||
//#endif
|
||||
|
||||
//
|
||||
// Track server rotation
|
||||
//
|
||||
|
||||
private static final String ENTITY_UPDATE = "Lnet/minecraft/entity/Entity;updateTrackedPositionAndAngles(DDDFFIZ)V";
|
||||
|
||||
@Unique
|
||||
private Entity entity;
|
||||
|
||||
@ModifyVariable(method = "onEntityUpdate", at = @At(value = "INVOKE", target = ENTITY_UPDATE), ordinal = 0)
|
||||
private Entity captureEntity(Entity entity) {
|
||||
return this.entity = entity;
|
||||
}
|
||||
|
||||
@Inject(method = "onEntityUpdate", at = @At("RETURN"))
|
||||
private void resetEntityField(CallbackInfo ci) {
|
||||
this.entity = null;
|
||||
}
|
||||
|
||||
@ModifyArg(method = "onEntityUpdate", at = @At(value = "INVOKE", target = ENTITY_UPDATE), index = 3)
|
||||
private float captureTrackedYaw(float value) {
|
||||
((EntityExt) this.entity).replaymod$setTrackedYaw(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@ModifyArg(method = "onEntityUpdate", at = @At(value = "INVOKE", target = ENTITY_UPDATE), index = 4)
|
||||
private float captureTrackedPitch(float value) {
|
||||
((EntityExt) this.entity).replaymod$setTrackedPitch(value);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user