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:
@@ -0,0 +1,13 @@
|
||||
package com.replaymod.replay.mixin;
|
||||
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(ClientWorld.class)
|
||||
public interface ClientWorldAccessor {
|
||||
//#if MC>=11800
|
||||
//$$ @Accessor
|
||||
//$$ net.minecraft.world.EntityList getEntityList();
|
||||
//#endif
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
// 1.18+ only
|
||||
@@ -6,6 +6,9 @@
|
||||
"server": [],
|
||||
"client": [
|
||||
"Mixin_FixNPCSkinCaching",
|
||||
//#if MC>=11800
|
||||
//$$ "Mixin_FixEntityNotTracking",
|
||||
//#endif
|
||||
//#if MC>=11600
|
||||
"Mixin_MoveRealmsButton",
|
||||
//#endif
|
||||
@@ -13,6 +16,7 @@
|
||||
"MixinCamera",
|
||||
"MixinInGameHud",
|
||||
//#endif
|
||||
"ClientWorldAccessor",
|
||||
"EntityLivingBaseAccessor",
|
||||
//#if MC>=11400
|
||||
"Mixin_ShowSpectatedHand_NoOF",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user