The fake player now has the same entity id as the recording player as assigned by the server
This fixes arrows bumping into recording player in replay ReplaySender converts old replays on the fly Do not insert PlayerListEntry as it's already contained in the replay
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"MixinEffectRenderer",
|
||||
"MixinEntityRenderer",
|
||||
"MixinMinecraft",
|
||||
"MixinNetHandlerPlayClient",
|
||||
"MixinPlayerControllerMP",
|
||||
"MixinRender",
|
||||
"MixinRenderArrow",
|
||||
|
||||
Reference in New Issue
Block a user