Merge branch 1.8.9-dev into 1.9.4-dev

8fad02c Merge branch 1.8-dev into 1.8.9-dev
1c888aa Add minVersion to mixin configs and bump bundled mixin version
10ce71e Fix mapwriter crash when opening replay for <MC1.12 (fixes #96)
5fb1cf3 Fix half-despawned player entities (see #93) when the entity is moved greater distances
adfe6a2 Fix NPE when spectated non-player entity despawns (fixes #94)
b27af27 Fix player entities being half-despawned after jumping in time (fixes #93)
This commit is contained in:
Jonas Herzig
2017-10-28 11:24:47 +02:00
11 changed files with 108 additions and 1 deletions

View File

@@ -61,7 +61,7 @@ configurations {
dependencies { dependencies {
compile 'org.projectlombok:lombok:1.16.4' 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 'com.googlecode.mp4parser:isoparser:1.1.7'
shade 'org.apache.commons:commons-exec:1.3' shade 'org.apache.commons:commons-exec:1.3'
shade 'com.google.apis:google-api-services-youtube:v3-rev178-1.22.0' shade 'com.google.apis:google-api-services-youtube:v3-rev178-1.22.0'

View File

@@ -0,0 +1,35 @@
package com.replaymod.compat.mapwriter.mixin;
import com.replaymod.replay.ReplayModReplay;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraftforge.fml.common.Loader;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
/**
* Approximately this for <1.12: https://github.com/Vectron/mapwriter/commit/68234520c7a3a0ae8201a085d7e66369900586ac
*/
@Mixin(Minecraft.class)
public abstract class MixinMinecraft {
@Shadow
private ServerData currentServerData;
@Inject(method = "getCurrentServerData", cancellable = true, at = @At("HEAD"))
private void replayModCompat_fixBug96(CallbackInfoReturnable<ServerData> 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", false));
return;
}
}
}
}
}

View File

@@ -19,6 +19,7 @@ public class LoadingPlugin implements IFMLLoadingPlugin {
Mixins.addConfiguration("mixins.recording.replaymod.json"); Mixins.addConfiguration("mixins.recording.replaymod.json");
Mixins.addConfiguration("mixins.render.replaymod.json"); Mixins.addConfiguration("mixins.render.replaymod.json");
Mixins.addConfiguration("mixins.replay.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.compat.shaders.replaymod.json");
Mixins.addConfiguration("mixins.extras.playeroverview.replaymod.json"); Mixins.addConfiguration("mixins.extras.playeroverview.replaymod.json");

View File

@@ -21,11 +21,15 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.*; import net.minecraft.network.*;
import net.minecraft.network.play.server.*; import net.minecraft.network.play.server.*;
import net.minecraft.util.ClassInheritanceMultiMap;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.EnumDifficulty; import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.WorldSettings.GameType; import net.minecraft.world.WorldSettings.GameType;
import net.minecraft.world.WorldType; import net.minecraft.world.WorldType;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.common.gameevent.TickEvent;
@@ -33,6 +37,7 @@ import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import java.io.*; import java.io.*;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -816,6 +821,50 @@ public class ReplaySender extends ChannelDuplexHandler {
} }
protected Packet processPacketSync(Packet p) { protected Packet processPacketSync(Packet p) {
if (p instanceof SPacketUnloadChunk) {
SPacketUnloadChunk packet = (SPacketUnloadChunk) p;
// 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.getX(), packet.getZ());
if (!chunk.isEmpty()) {
List<Entity> entitiesInChunk = new ArrayList<>();
// Gather all entities in that chunk
for (ClassInheritanceMultiMap<Entity> entityList : chunk.getEntityLists()) {
entitiesInChunk.addAll(entityList);
}
for (Entity entity : entitiesInChunk) {
// Skip interpolation of position updates coming from server
// (See: newX in EntityLivingBase or otherPlayerMPX in EntityOtherPlayerMP)
// 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);
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);
Chunk newChunk = chunkProvider.getLoadedChunk(chunkX, chunkZ);
if (newChunk != null) {
newChunk.addEntity(entity);
} else {
// Entity has left all loaded chunks
entity.addedToChunk = false;
}
}
}
}
}
return p; // During synchronous playback everything is sent normally return p; // During synchronous playback everything is sent normally
} }

View File

@@ -160,6 +160,11 @@ public class CameraEntity extends EntityPlayerSP {
if (spectating != null && (view.getUniqueID() != spectating if (spectating != null && (view.getUniqueID() != spectating
|| view.worldObj != worldObj) || view.worldObj != worldObj)
|| worldObj.getEntityByID(view.getEntityId()) != view) { || worldObj.getEntityByID(view.getEntityId()) != view) {
if (spectating == null) {
// Entity (non-player) died, stop spectating
ReplayModReplay.instance.getReplayHandler().spectateEntity(this);
return;
}
view = worldObj.getPlayerEntityByUUID(spectating); view = worldObj.getPlayerEntityByUUID(spectating);
if (view != null) { if (view != null) {
mc.setRenderViewEntity(view); mc.setRenderViewEntity(view);

View File

@@ -0,0 +1,12 @@
{
"required": false,
"package": "com.replaymod.compat.mapwriter.mixin",
"mixins": [],
"server": [],
"client": [
"MixinMinecraft"
],
"compatibilityLevel": "JAVA_8",
"minVersion": "0.6.11",
"refmap": "mixins.replaymod.refmap.json"
}

View File

@@ -10,5 +10,6 @@
"MixinShadersRender" "MixinShadersRender"
], ],
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"minVersion": "0.6.11",
"refmap": "mixins.replaymod.refmap.json" "refmap": "mixins.replaymod.refmap.json"
} }

View File

@@ -7,5 +7,6 @@
"MixinRender" "MixinRender"
], ],
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"minVersion": "0.6.11",
"refmap": "mixins.replaymod.refmap.json" "refmap": "mixins.replaymod.refmap.json"
} }

View File

@@ -12,5 +12,6 @@
"MixinWorldClient" "MixinWorldClient"
], ],
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"minVersion": "0.6.11",
"refmap": "mixins.replaymod.refmap.json" "refmap": "mixins.replaymod.refmap.json"
} }

View File

@@ -12,5 +12,6 @@
"server": [], "server": [],
"client": [], "client": [],
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"minVersion": "0.6.11",
"refmap": "mixins.replaymod.refmap.json" "refmap": "mixins.replaymod.refmap.json"
} }

View File

@@ -16,5 +16,6 @@
"server": [], "server": [],
"client": [], "client": [],
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"minVersion": "0.6.11",
"refmap": "mixins.replaymod.refmap.json" "refmap": "mixins.replaymod.refmap.json"
} }