From b27af2781b651b2aff8f1219a4ef3086836cdaf4 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 28 Aug 2017 10:56:37 +0200 Subject: [PATCH 1/5] Fix player entities being half-despawned after jumping in time (fixes #93) --- .../com/replaymod/replay/ReplaySender.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/main/java/com/replaymod/replay/ReplaySender.java b/src/main/java/com/replaymod/replay/ReplaySender.java index 8a42426b..9e000d3a 100755 --- a/src/main/java/com/replaymod/replay/ReplaySender.java +++ b/src/main/java/com/replaymod/replay/ReplaySender.java @@ -19,16 +19,22 @@ import net.minecraft.client.resources.I18n; import net.minecraft.entity.Entity; import net.minecraft.network.*; import net.minecraft.network.play.server.*; +import net.minecraft.util.ClassInheritanceMultiMap; import net.minecraft.util.IChatComponent; +import net.minecraft.util.MathHelper; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; import net.minecraft.world.WorldSettings.GameType; import net.minecraft.world.WorldType; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import java.io.*; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -799,6 +805,49 @@ public class ReplaySender extends ChannelDuplexHandler { } protected Packet processPacketSync(Packet p) { + if (p instanceof S21PacketChunkData) { + S21PacketChunkData packet = (S21PacketChunkData) p; + if (packet.func_149276_g() == 0) { + // If the chunk is getting unloaded, we will have to forcefully update the position of all entities + // within. Otherwise, if there wasn't a game tick recently, there may be entities that have moved + // out of the chunk by now but are still registered in it. If we do not update those, they will get + // unloaded even though they shouldn't. + // To make things worse, it seems like players were never supposed to be unloaded this way because + // they will remain glitched in the World#playerEntities list. + World world = mc.theWorld; + IChunkProvider chunkProvider = world.getChunkProvider(); + // Get the chunk that will be unloaded + Chunk chunk = chunkProvider.provideChunk(packet.func_149273_e(), packet.func_149271_f()); + if (!chunk.isEmpty()) { + List entitiesInChunk = new ArrayList<>(); + // Gather all entities in that chunk + for (ClassInheritanceMultiMap entityList : chunk.getEntityLists()) { + @SuppressWarnings("unchecked") + Collection typedEntityList = entityList; + entitiesInChunk.addAll(typedEntityList); + } + for (Entity entity : entitiesInChunk) { + // Skip interpolation of position updates coming from server + // (See: newX in EntityLivingBase or otherPlayerMPX in EntityOtherPlayerMP) + entity.onUpdate(); + + // Check whether the entity has left the chunk + int chunkX = MathHelper.floor_double(entity.posX / 16); + int chunkZ = MathHelper.floor_double(entity.posZ / 16); + if (entity.chunkCoordX != chunkX || entity.chunkCoordZ != chunkZ) { + // Entity has left the chunk + chunk.removeEntityAtIndex(entity, entity.chunkCoordY); + if (chunkProvider.chunkExists(chunkX, chunkZ)) { + chunkProvider.provideChunk(chunkX, chunkZ).addEntity(entity); + } else { + // Entity has left all loaded chunks + entity.addedToChunk = false; + } + } + } + } + } + } return p; // During synchronous playback everything is sent normally } From adfe6a2bfcabdf8b18621654ba888b7e2409856f Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 28 Aug 2017 10:58:04 +0200 Subject: [PATCH 2/5] Fix NPE when spectated non-player entity despawns (fixes #94) --- src/main/java/com/replaymod/replay/camera/CameraEntity.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/replaymod/replay/camera/CameraEntity.java b/src/main/java/com/replaymod/replay/camera/CameraEntity.java index 5db8ecb2..9935baf5 100755 --- a/src/main/java/com/replaymod/replay/camera/CameraEntity.java +++ b/src/main/java/com/replaymod/replay/camera/CameraEntity.java @@ -160,6 +160,11 @@ public class CameraEntity extends EntityPlayerSP { if (spectating != null && (view.getUniqueID() != spectating || view.worldObj != worldObj) || worldObj.getEntityByID(view.getEntityId()) != view) { + if (spectating == null) { + // Entity (non-player) died, stop spectating + ReplayModReplay.instance.getReplayHandler().spectateEntity(this); + return; + } view = worldObj.getPlayerEntityByUUID(spectating); if (view != null) { mc.setRenderViewEntity(view); From 5fb1cf34e248fd091768add3a3a76b6d0c8f0e54 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 16 Oct 2017 11:29:04 +0200 Subject: [PATCH 3/5] Fix half-despawned player entities (see #93) when the entity is moved greater distances --- src/main/java/com/replaymod/replay/ReplaySender.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/replaymod/replay/ReplaySender.java b/src/main/java/com/replaymod/replay/ReplaySender.java index 9e000d3a..92d97bd4 100755 --- a/src/main/java/com/replaymod/replay/ReplaySender.java +++ b/src/main/java/com/replaymod/replay/ReplaySender.java @@ -829,7 +829,11 @@ public class ReplaySender extends ChannelDuplexHandler { for (Entity entity : entitiesInChunk) { // Skip interpolation of position updates coming from server // (See: newX in EntityLivingBase or otherPlayerMPX in EntityOtherPlayerMP) - entity.onUpdate(); + // Needs to be called at least 4 times thanks to + // EntityOtherPlayerMP#otherPlayerMPPosRotationIncrements (max vanilla value is 3) + for (int i = 0; i < 4; i++) { + entity.onUpdate(); + } // Check whether the entity has left the chunk int chunkX = MathHelper.floor_double(entity.posX / 16); From 10ce71efe3d264a8df80185c4774abd30ceab521 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Fri, 27 Oct 2017 14:21:12 +0200 Subject: [PATCH 4/5] Fix mapwriter crash when opening replay for ci) { + if (currentServerData == null + && (Loader.isModLoaded("mapwriter") || Loader.isModLoaded("MapWriter")) + && ReplayModReplay.instance.getReplayHandler() != null) { + for (StackTraceElement elem : Thread.currentThread().getStackTrace()) { + if ("mapwriter.util.Utils".equals(elem.getClassName()) && "getWorldName".equals(elem.getMethodName())) { + ci.setReturnValue(new ServerData(null, "replay")); + return; + } + } + } + } +} diff --git a/src/main/java/com/replaymod/core/LoadingPlugin.java b/src/main/java/com/replaymod/core/LoadingPlugin.java index 9a251ed9..ebc8df0b 100755 --- a/src/main/java/com/replaymod/core/LoadingPlugin.java +++ b/src/main/java/com/replaymod/core/LoadingPlugin.java @@ -19,6 +19,7 @@ public class LoadingPlugin implements IFMLLoadingPlugin { Mixins.addConfiguration("mixins.recording.replaymod.json"); Mixins.addConfiguration("mixins.render.replaymod.json"); Mixins.addConfiguration("mixins.replay.replaymod.json"); + Mixins.addConfiguration("mixins.compat.mapwriter.replaymod.json"); Mixins.addConfiguration("mixins.compat.shaders.replaymod.json"); Mixins.addConfiguration("mixins.extras.playeroverview.replaymod.json"); diff --git a/src/main/resources/mixins.compat.mapwriter.replaymod.json b/src/main/resources/mixins.compat.mapwriter.replaymod.json new file mode 100644 index 00000000..4b5d0287 --- /dev/null +++ b/src/main/resources/mixins.compat.mapwriter.replaymod.json @@ -0,0 +1,11 @@ +{ + "required": false, + "package": "com.replaymod.compat.mapwriter.mixin", + "mixins": [], + "server": [], + "client": [ + "MixinMinecraft" + ], + "compatibilityLevel": "JAVA_8", + "refmap": "mixins.replaymod.refmap.json" +} \ No newline at end of file From 1c888aadc2b6147c05da3e7e8d21789a9a7059b2 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Fri, 27 Oct 2017 16:27:28 +0200 Subject: [PATCH 5/5] Add minVersion to mixin configs and bump bundled mixin version --- build.gradle | 2 +- src/main/resources/mixins.compat.mapwriter.replaymod.json | 1 + src/main/resources/mixins.compat.shaders.replaymod.json | 1 + src/main/resources/mixins.extras.playeroverview.replaymod.json | 1 + src/main/resources/mixins.recording.replaymod.json | 1 + src/main/resources/mixins.render.replaymod.json | 1 + src/main/resources/mixins.replay.replaymod.json | 1 + 7 files changed, 7 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3ff6b6ed..f7f77bd0 100755 --- a/build.gradle +++ b/build.gradle @@ -61,7 +61,7 @@ configurations { dependencies { compile 'org.projectlombok:lombok:1.16.4' - compile 'org.spongepowered:mixin:0.6.8-SNAPSHOT' + compile 'org.spongepowered:mixin:0.7.5-SNAPSHOT' shade 'com.googlecode.mp4parser:isoparser:1.1.7' shade 'org.apache.commons:commons-exec:1.3' shade 'com.google.apis:google-api-services-youtube:v3-rev178-1.22.0' diff --git a/src/main/resources/mixins.compat.mapwriter.replaymod.json b/src/main/resources/mixins.compat.mapwriter.replaymod.json index 4b5d0287..eb02cea2 100644 --- a/src/main/resources/mixins.compat.mapwriter.replaymod.json +++ b/src/main/resources/mixins.compat.mapwriter.replaymod.json @@ -7,5 +7,6 @@ "MixinMinecraft" ], "compatibilityLevel": "JAVA_8", + "minVersion": "0.6.11", "refmap": "mixins.replaymod.refmap.json" } \ No newline at end of file diff --git a/src/main/resources/mixins.compat.shaders.replaymod.json b/src/main/resources/mixins.compat.shaders.replaymod.json index 792af576..ed6e1a9a 100644 --- a/src/main/resources/mixins.compat.shaders.replaymod.json +++ b/src/main/resources/mixins.compat.shaders.replaymod.json @@ -10,5 +10,6 @@ "MixinShadersRender" ], "compatibilityLevel": "JAVA_8", + "minVersion": "0.6.11", "refmap": "mixins.replaymod.refmap.json" } \ No newline at end of file diff --git a/src/main/resources/mixins.extras.playeroverview.replaymod.json b/src/main/resources/mixins.extras.playeroverview.replaymod.json index 7c9a0a1f..9c9bf8e7 100644 --- a/src/main/resources/mixins.extras.playeroverview.replaymod.json +++ b/src/main/resources/mixins.extras.playeroverview.replaymod.json @@ -7,5 +7,6 @@ "MixinRender" ], "compatibilityLevel": "JAVA_8", + "minVersion": "0.6.11", "refmap": "mixins.replaymod.refmap.json" } \ No newline at end of file diff --git a/src/main/resources/mixins.recording.replaymod.json b/src/main/resources/mixins.recording.replaymod.json index 95a6738d..75e77050 100644 --- a/src/main/resources/mixins.recording.replaymod.json +++ b/src/main/resources/mixins.recording.replaymod.json @@ -10,5 +10,6 @@ "MixinRenderGlobal" ], "compatibilityLevel": "JAVA_8", + "minVersion": "0.6.11", "refmap": "mixins.replaymod.refmap.json" } \ No newline at end of file diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index a2e940c8..539d1c55 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -13,5 +13,6 @@ "server": [], "client": [], "compatibilityLevel": "JAVA_8", + "minVersion": "0.6.11", "refmap": "mixins.replaymod.refmap.json" } \ No newline at end of file diff --git a/src/main/resources/mixins.replay.replaymod.json b/src/main/resources/mixins.replay.replaymod.json index 8d02ed09..e92257fb 100644 --- a/src/main/resources/mixins.replay.replaymod.json +++ b/src/main/resources/mixins.replay.replaymod.json @@ -15,5 +15,6 @@ "server": [], "client": [], "compatibilityLevel": "JAVA_8", + "minVersion": "0.6.11", "refmap": "mixins.replaymod.refmap.json" } \ No newline at end of file