diff --git a/src/main/java/eu/crushedpixel/replaymod/events/handlers/RecordingHandler.java b/src/main/java/eu/crushedpixel/replaymod/events/handlers/RecordingHandler.java index e33eb55c..9ca66d0b 100755 --- a/src/main/java/eu/crushedpixel/replaymod/events/handlers/RecordingHandler.java +++ b/src/main/java/eu/crushedpixel/replaymod/events/handlers/RecordingHandler.java @@ -12,12 +12,8 @@ import net.minecraft.network.Packet; import net.minecraft.network.PacketBuffer; import net.minecraft.network.play.server.*; import net.minecraft.network.play.server.S14PacketEntity.S17PacketEntityLookMove; -import net.minecraft.network.play.server.S38PacketPlayerListItem.Action; import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.util.MathHelper; -import net.minecraftforge.event.entity.EntityJoinWorldEvent; -import net.minecraftforge.event.entity.living.LivingDeathEvent; -import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.event.entity.minecart.MinecartInteractEvent; import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent; import net.minecraftforge.event.entity.player.PlayerUseItemEvent; @@ -29,8 +25,6 @@ import net.minecraftforge.fml.common.gameevent.TickEvent.PlayerTickEvent; public class RecordingHandler { - public static final int entityID = Integer.MIN_VALUE + 9001; - private final Minecraft mc = Minecraft.getMinecraft(); private Double lastX = null, lastY = null, lastZ = null; private ItemStack[] playerItems = new ItemStack[5]; @@ -39,33 +33,10 @@ public class RecordingHandler { private int lastRiding = -1; private Integer rotationYawHeadBefore = null; - @SubscribeEvent - public void onPlayerJoin(EntityJoinWorldEvent e) { + public void onPlayerJoin() { try { - if(e.entity != mc.thePlayer) return; if(!ConnectionEventHandler.isRecording()) return; - EntityPlayer player = (EntityPlayer) e.entity; - - S38PacketPlayerListItem ppli = new S38PacketPlayerListItem(); - ByteBuf buf = Unpooled.buffer(); - PacketBuffer pbuf = new PacketBuffer(buf); - - pbuf.writeEnumValue(Action.ADD_PLAYER); - pbuf.writeVarIntToBuffer(1); - pbuf.writeUuid(e.entity.getUniqueID()); - - pbuf.writeString(player.getName()); - pbuf.writeVarIntToBuffer(0); - pbuf.writeVarIntToBuffer(mc.playerController.getCurrentGameType().getID()); - pbuf.writeVarIntToBuffer(0); - - pbuf.writeBoolean(true); - pbuf.writeChatComponent(player.getDisplayName()); - - ppli.readPacketData(pbuf); - ConnectionEventHandler.insertPacket(ppli); - ConnectionEventHandler.insertPacket(spawnPlayer(mc.thePlayer)); } catch(Exception e1) { e1.printStackTrace(); @@ -79,7 +50,7 @@ public class RecordingHandler { ByteBuf bb = Unpooled.buffer(); PacketBuffer pb = new PacketBuffer(bb); - pb.writeVarIntToBuffer(entityID); + pb.writeVarIntToBuffer(player.getEntityId()); pb.writeUuid(EntityPlayer.getUUID(player.getGameProfile())); pb.writeInt(MathHelper.floor_double(player.posX * 32.0D)); @@ -144,12 +115,12 @@ public class RecordingHandler { int z = MathHelper.floor_double(e.player.posZ * 32.0D); byte yaw = (byte) ((int) (e.player.rotationYaw * 256.0F / 360.0F)); byte pitch = (byte) ((int) (e.player.rotationPitch * 256.0F / 360.0F)); - packet = new S18PacketEntityTeleport(entityID, x, y, z, yaw, pitch, e.player.onGround); + packet = new S18PacketEntityTeleport(e.player.getEntityId(), x, y, z, yaw, pitch, e.player.onGround); } else { byte newYaw = (byte) ((int) (e.player.rotationYaw * 256.0F / 360.0F)); byte newPitch = (byte) ((int) (e.player.rotationPitch * 256.0F / 360.0F)); - packet = new S17PacketEntityLookMove(entityID, + packet = new S17PacketEntityLookMove(e.player.getEntityId(), (byte) Math.round(dx * 32), (byte) Math.round(dy * 32), (byte) Math.round(dz * 32), newYaw, newPitch, e.player.onGround); } @@ -164,7 +135,7 @@ public class RecordingHandler { ByteBuf bb1 = Unpooled.buffer(); PacketBuffer pb1 = new PacketBuffer(bb1); - pb1.writeVarIntToBuffer(entityID); + pb1.writeVarIntToBuffer(e.player.getEntityId()); pb1.writeByte(rotationYawHead); head.readPacketData(pb1); @@ -174,7 +145,7 @@ public class RecordingHandler { rotationYawHeadBefore = rotationYawHead; } - S12PacketEntityVelocity vel = new S12PacketEntityVelocity(entityID, e.player.motionX, e.player.motionY, e.player.motionZ); + S12PacketEntityVelocity vel = new S12PacketEntityVelocity(e.player.getEntityId(), e.player.motionX, e.player.motionY, e.player.motionZ); ConnectionEventHandler.insertPacket(vel); //Animation Packets @@ -185,7 +156,7 @@ public class RecordingHandler { ByteBuf bb = Unpooled.buffer(); PacketBuffer pb = new PacketBuffer(bb); - pb.writeVarIntToBuffer(entityID); + pb.writeVarIntToBuffer(e.player.getEntityId()); pb.writeByte(0); pac.readPacketData(pb); @@ -216,31 +187,31 @@ public class RecordingHandler { //Inventory Handling if(playerItems[0] != mc.thePlayer.getHeldItem()) { playerItems[0] = mc.thePlayer.getHeldItem(); - S04PacketEntityEquipment pee = new S04PacketEntityEquipment(entityID, 0, playerItems[0]); + S04PacketEntityEquipment pee = new S04PacketEntityEquipment(e.player.getEntityId(), 0, playerItems[0]); ConnectionEventHandler.insertPacket(pee); } if(playerItems[1] != mc.thePlayer.inventory.armorInventory[0]) { playerItems[1] = mc.thePlayer.inventory.armorInventory[0]; - S04PacketEntityEquipment pee = new S04PacketEntityEquipment(entityID, 1, playerItems[1]); + S04PacketEntityEquipment pee = new S04PacketEntityEquipment(e.player.getEntityId(), 1, playerItems[1]); ConnectionEventHandler.insertPacket(pee); } if(playerItems[2] != mc.thePlayer.inventory.armorInventory[1]) { playerItems[2] = mc.thePlayer.inventory.armorInventory[1]; - S04PacketEntityEquipment pee = new S04PacketEntityEquipment(entityID, 2, playerItems[2]); + S04PacketEntityEquipment pee = new S04PacketEntityEquipment(e.player.getEntityId(), 2, playerItems[2]); ConnectionEventHandler.insertPacket(pee); } if(playerItems[3] != mc.thePlayer.inventory.armorInventory[2]) { playerItems[3] = mc.thePlayer.inventory.armorInventory[2]; - S04PacketEntityEquipment pee = new S04PacketEntityEquipment(entityID, 3, playerItems[3]); + S04PacketEntityEquipment pee = new S04PacketEntityEquipment(e.player.getEntityId(), 3, playerItems[3]); ConnectionEventHandler.insertPacket(pee); } if(playerItems[4] != mc.thePlayer.inventory.armorInventory[3]) { playerItems[4] = mc.thePlayer.inventory.armorInventory[3]; - S04PacketEntityEquipment pee = new S04PacketEntityEquipment(entityID, 4, playerItems[4]); + S04PacketEntityEquipment pee = new S04PacketEntityEquipment(e.player.getEntityId(), 4, playerItems[4]); ConnectionEventHandler.insertPacket(pee); } @@ -259,7 +230,7 @@ public class RecordingHandler { ByteBuf buf = Unpooled.buffer(); PacketBuffer pbuf = new PacketBuffer(buf); - pbuf.writeInt(entityID); + pbuf.writeInt(e.player.getEntityId()); pbuf.writeInt(lastRiding); pbuf.writeBoolean(false); @@ -275,7 +246,7 @@ public class RecordingHandler { ByteBuf bb = Unpooled.buffer(); PacketBuffer pb = new PacketBuffer(bb); - pb.writeVarIntToBuffer(entityID); + pb.writeVarIntToBuffer(e.player.getEntityId()); pb.writeByte(2); pac.readPacketData(pb); @@ -294,7 +265,7 @@ public class RecordingHandler { public void onPickupItem(ItemPickupEvent event) { if(!ConnectionEventHandler.isRecording()) return; try { - ConnectionEventHandler.insertPacket(new S0DPacketCollectItem(event.pickedUp.getEntityId(), entityID)); + ConnectionEventHandler.insertPacket(new S0DPacketCollectItem(event.pickedUp.getEntityId(), event.player.getEntityId())); } catch(Exception e) { e.printStackTrace(); } @@ -305,7 +276,7 @@ public class RecordingHandler { if(!ConnectionEventHandler.isRecording()) return; try { //destroy entity, then respawn - ConnectionEventHandler.insertPacket(new S13PacketDestroyEntities(entityID)); + ConnectionEventHandler.insertPacket(new S13PacketDestroyEntities(mc.thePlayer.getEntityId())); ConnectionEventHandler.insertPacket(spawnPlayer(mc.thePlayer)); } catch(Exception e) { e.printStackTrace(); @@ -322,7 +293,7 @@ public class RecordingHandler { ByteBuf bb = Unpooled.buffer(); PacketBuffer pb = new PacketBuffer(bb); - pb.writeVarIntToBuffer(entityID); + pb.writeVarIntToBuffer(event.entityPlayer.getEntityId()); pb.writeByte(3); packet.readPacketData(pb); @@ -347,7 +318,7 @@ public class RecordingHandler { ByteBuf buf = Unpooled.buffer(); PacketBuffer pbuf = new PacketBuffer(buf); - pbuf.writeVarIntToBuffer(entityID); + pbuf.writeVarIntToBuffer(event.entityPlayer.getEntityId()); pbuf.writeBlockPos(event.pos); pub.readPacketData(pbuf); @@ -374,7 +345,7 @@ public class RecordingHandler { ByteBuf buf = Unpooled.buffer(); PacketBuffer pbuf = new PacketBuffer(buf); - pbuf.writeInt(entityID); + pbuf.writeInt(event.player.getEntityId()); pbuf.writeInt(event.minecart.getEntityId()); pbuf.writeBoolean(false); diff --git a/src/main/java/eu/crushedpixel/replaymod/mixin/MixinNetHandlerPlayClient.java b/src/main/java/eu/crushedpixel/replaymod/mixin/MixinNetHandlerPlayClient.java new file mode 100644 index 00000000..d9db66b1 --- /dev/null +++ b/src/main/java/eu/crushedpixel/replaymod/mixin/MixinNetHandlerPlayClient.java @@ -0,0 +1,28 @@ +package eu.crushedpixel.replaymod.mixin; + +import eu.crushedpixel.replaymod.ReplayMod; +import eu.crushedpixel.replaymod.recording.ConnectionEventHandler; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.network.play.server.S01PacketJoinGame; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(NetHandlerPlayClient.class) +public abstract class MixinNetHandlerPlayClient { + + /** + * Record the own player entity joining the world. + * We cannot use the {@link net.minecraftforge.event.entity.EntityJoinWorldEvent} because the entity id + * of the player is set afterwards. + * @param packet The packet + * @param ci Callback info + */ + @Inject(method = "handleJoinGame", at=@At("RETURN")) + public void recordJoinGame(S01PacketJoinGame packet, CallbackInfo ci) { + if (ConnectionEventHandler.isRecording()) { + ReplayMod.recordingHandler.onPlayerJoin(); + } + } +} diff --git a/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java b/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java index 173f9971..a42f8aab 100755 --- a/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java +++ b/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java @@ -5,7 +5,6 @@ import com.google.common.io.Files; import com.google.common.util.concurrent.ListenableFutureTask; import eu.crushedpixel.replaymod.ReplayMod; import eu.crushedpixel.replaymod.entities.CameraEntity; -import eu.crushedpixel.replaymod.events.handlers.RecordingHandler; import eu.crushedpixel.replaymod.holders.PacketData; import eu.crushedpixel.replaymod.utils.ReplayFile; import eu.crushedpixel.replaymod.utils.ReplayFileIO; @@ -40,6 +39,14 @@ import java.util.concurrent.Callable; @Sharable public class ReplaySender extends ChannelInboundHandlerAdapter { + /** + * Previously packets for the client player were inserted using one fixed entity id (this one). + * This is no longer the case however to provide backwards compatibility, we have to convert + * these old packets to use the normal entity id. + * Need to punch someone? -> CrushedPixel + */ + public static final int LEGACY_ENTITY_ID = Integer.MIN_VALUE + 9001; + /** * These packets are ignored completely during replay. */ @@ -291,6 +298,8 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { } } + convertLegacyEntityIds(p); + if(p instanceof S48PacketResourcePackSend) { S48PacketResourcePackSend packet = (S48PacketResourcePackSend) p; String url = packet.func_179783_a(); @@ -311,33 +320,12 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { } } - if(p instanceof S1CPacketEntityMetadata) { - S1CPacketEntityMetadata packet = (S1CPacketEntityMetadata) p; - if(packet.field_149379_a == actualID) { - packet.field_149379_a = RecordingHandler.entityID; - } - } - - if(p instanceof S1BPacketEntityAttach) { - S1BPacketEntityAttach packet = (S1BPacketEntityAttach) p; - if(packet.func_149403_d() == actualID) { - return null; - } - } - - if(p instanceof S19PacketEntityStatus) { - S19PacketEntityStatus packet = (S19PacketEntityStatus)p; - if(packet.field_149164_a == actualID) { - packet.field_149164_a = RecordingHandler.entityID; - } - } - if(p instanceof S01PacketJoinGame) { S01PacketJoinGame packet = (S01PacketJoinGame) p; allowMovement = true; int entId = packet.getEntityId(); actualID = entId; - entId = Integer.MIN_VALUE + 9002; + entId = -1789435; // Camera entity id should be negative which is an invalid id and can't be used by servers int dimension = packet.getDimension(); EnumDifficulty difficulty = packet.getDifficulty(); int maxPlayers = packet.getMaxPlayers(); @@ -726,4 +714,65 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { return p; // During synchronous playback everything is sent normally } + /** + * This is necessary to convert packets from old replays to new replays. + * @param packet The packet to be transformed. + * @see #LEGACY_ENTITY_ID + */ + private void convertLegacyEntityIds(Packet packet) { + if (packet instanceof S0CPacketSpawnPlayer) { + S0CPacketSpawnPlayer p = (S0CPacketSpawnPlayer) packet; + if (p.field_148957_a == LEGACY_ENTITY_ID) { + p.field_148957_a = actualID; + } + } else if (packet instanceof S18PacketEntityTeleport) { + S18PacketEntityTeleport p = (S18PacketEntityTeleport) packet; + if (p.field_149458_a == LEGACY_ENTITY_ID) { + p.field_149458_a = actualID; + } + } else if (packet instanceof S14PacketEntity.S17PacketEntityLookMove) { + S14PacketEntity.S17PacketEntityLookMove p = (S14PacketEntity.S17PacketEntityLookMove) packet; + if (p.field_149074_a == LEGACY_ENTITY_ID) { + p.field_149074_a = actualID; + } + } else if (packet instanceof S19PacketEntityHeadLook) { + S19PacketEntityHeadLook p = (S19PacketEntityHeadLook) packet; + if (p.field_149384_a == LEGACY_ENTITY_ID) { + p.field_149384_a = actualID; + } + } else if (packet instanceof S12PacketEntityVelocity) { + S12PacketEntityVelocity p = (S12PacketEntityVelocity) packet; + if (p.field_149417_a == LEGACY_ENTITY_ID) { + p.field_149417_a = actualID; + } + } else if (packet instanceof S0BPacketAnimation) { + S0BPacketAnimation p = (S0BPacketAnimation) packet; + if (p.entityId == LEGACY_ENTITY_ID) { + p.entityId = actualID; + } + } else if (packet instanceof S04PacketEntityEquipment) { + S04PacketEntityEquipment p = (S04PacketEntityEquipment) packet; + if (p.field_149394_a == LEGACY_ENTITY_ID) { + p.field_149394_a = actualID; + } + } else if (packet instanceof S1BPacketEntityAttach) { + S1BPacketEntityAttach p = (S1BPacketEntityAttach) packet; + if (p.field_149408_a == LEGACY_ENTITY_ID) { + p.field_149408_a = actualID; + } + if (p.field_149406_b == LEGACY_ENTITY_ID) { + p.field_149406_b = actualID; + } + } else if (packet instanceof S0DPacketCollectItem) { + S0DPacketCollectItem p = (S0DPacketCollectItem) packet; + if (p.field_149356_b == LEGACY_ENTITY_ID) { + p.field_149356_b = actualID; + } + } else if (packet instanceof S13PacketDestroyEntities) { + S13PacketDestroyEntities p = (S13PacketDestroyEntities) packet; + if (p.field_149100_a.length == 1 && p.field_149100_a[0] == LEGACY_ENTITY_ID) { + p.field_149100_a[0] = actualID; + } + } + } } diff --git a/src/main/resources/META-INF/replaymod_at.cfg b/src/main/resources/META-INF/replaymod_at.cfg index 1f2cf852..a5d3c5f0 100644 --- a/src/main/resources/META-INF/replaymod_at.cfg +++ b/src/main/resources/META-INF/replaymod_at.cfg @@ -22,8 +22,6 @@ public net.minecraft.client.Minecraft func_147115_a(Z)V # sendClickBlockToContro # Packets public net.minecraft.network.play.server.S0FPacketSpawnMob field_149043_l # dataWatcher -public net.minecraft.network.play.server.S0CPacketSpawnPlayer field_148960_i # dataWatcher -public net.minecraft.network.play.server.S0CPacketSpawnPlayer field_179820_b # uuid public net.minecraft.network.play.server.S38PacketPlayerListItem field_179964_d # profile public net.minecraft.network.play.server.S1DPacketEntityEffect field_149434_a # entityId public net.minecraft.network.play.server.S1CPacketEntityMetadata field_149379_a # entityId @@ -31,6 +29,15 @@ public net.minecraft.network.play.server.S1CPacketEntityMetadata field_149378_b public net.minecraft.network.play.server.S0BPacketAnimation field_148981_a # entityId public net.minecraft.network.play.server.S02PacketChat field_179842_b # position public net.minecraft.network.play.server.S19PacketEntityStatus field_149164_a # entityId +public net.minecraft.network.play.server.S0CPacketSpawnPlayer * +public net.minecraft.network.play.server.S18PacketEntityTeleport * +public net.minecraft.network.play.server.S14PacketEntity * +public net.minecraft.network.play.server.S19PacketEntityHeadLook * +public net.minecraft.network.play.server.S12PacketEntityVelocity * +public net.minecraft.network.play.server.S04PacketEntityEquipment * +public net.minecraft.network.play.server.S1BPacketEntityAttach * +public net.minecraft.network.play.server.S0DPacketCollectItem * +public net.minecraft.network.play.server.S13PacketDestroyEntities * # GuiTextField public net.minecraft.client.gui.GuiTextField field_146216_j # text diff --git a/src/main/resources/mixins.replaymod.json b/src/main/resources/mixins.replaymod.json index ccd467be..72ae3dcc 100644 --- a/src/main/resources/mixins.replaymod.json +++ b/src/main/resources/mixins.replaymod.json @@ -5,6 +5,7 @@ "MixinEffectRenderer", "MixinEntityRenderer", "MixinMinecraft", + "MixinNetHandlerPlayClient", "MixinPlayerControllerMP", "MixinRender", "MixinRenderArrow",