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:
johni0702
2015-08-18 10:39:42 +02:00
parent d687748629
commit d1e55266e2
5 changed files with 129 additions and 73 deletions

View File

@@ -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);

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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

View File

@@ -5,6 +5,7 @@
"MixinEffectRenderer",
"MixinEntityRenderer",
"MixinMinecraft",
"MixinNetHandlerPlayClient",
"MixinPlayerControllerMP",
"MixinRender",
"MixinRenderArrow",