Fix vanilla 1.18 bug causing entities to get stuck outside sim range

MC uses the client-side position of an entity to determine whether it is inside
the simulation range and therefore whether it will get ticked. For some (most)
entities it interpolates the client-side position to match the server-side one
inside of the tick method... no prices for guessing where this goes wrong.

Somewhat similar to the issue we have with chunk unloads which we work around in
FullReplaySender but worse cause they'll get stuck if they ever leave the sim
range even for a single tick, rather then just when their chunk is unloaded.
This commit is contained in:
Jonas Herzig
2021-11-29 14:50:41 +01:00
parent ff5c0f594e
commit 88a23222b6
4 changed files with 56 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
package com.replaymod.replay.mixin;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.Vec3d;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
@Mixin(ClientPlayNetworkHandler.class)
public class Mixin_FixEntityNotTracking {
@ModifyVariable(method = { "onEntityPosition", "onEntity", "onEntityPassengersSet" }, at = @At("RETURN"), ordinal = 0)
private Entity updatePositionIfNotTracked$0(Entity entity) {
if (entity != null) {
entity.streamSelfAndPassengers().forEach(this::updatePositionIfNotTracked);
}
return entity;
}
private void updatePositionIfNotTracked(Entity entity) {
if (entity != null && entity.world instanceof ClientWorldAccessor world) {
if (!world.getEntityList().has(entity)) {
// Skip interpolation of position updates coming from server
// (See: newX in EntityLivingBase or otherPlayerMPX in EntityOtherPlayerMP)
int ticks = 0;
Vec3d prevPos;
do {
prevPos = entity.getPos();
if (entity.hasVehicle()) {
entity.tickRiding();
} else {
entity.tick();
}
} while (prevPos.squaredDistanceTo(entity.getPos()) > 0.0001 && ticks++ < 100);
}
}
}
}