Fix vanilla entity update packet handling (fixes #607)

This commit is contained in:
Jonas Herzig
2021-12-07 13:50:53 +01:00
parent b10b4fd25a
commit 29ef38213f
6 changed files with 178 additions and 1 deletions

View File

@@ -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);

View 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
}
}

View 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);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}