    001    package cpw.mods.fml.common.network;
    002
    003    import java.io.ByteArrayInputStream;
    004    import java.io.ByteArrayOutputStream;
    005    import java.io.DataInputStream;
    006    import java.io.DataOutputStream;
    007    import java.io.IOException;
    008    import java.util.List;
    009    import java.util.logging.Level;
    010
    011    import net.minecraft.entity.*;
    012    import net.minecraft.network.INetworkManager;
    013    import net.minecraft.network.packet.NetHandler;
    014    import net.minecraft.util.MathHelper;
    015
    016    import com.google.common.io.ByteArrayDataInput;
    017    import com.google.common.io.ByteArrayDataOutput;
    018    import com.google.common.io.ByteStreams;
    019
    020    import cpw.mods.fml.common.FMLCommonHandler;
    021    import cpw.mods.fml.common.FMLLog;
    022    import cpw.mods.fml.common.ModContainer;
    023    import cpw.mods.fml.common.registry.EntityRegistry;
    024    import cpw.mods.fml.common.registry.EntityRegistry.EntityRegistration;
    025    import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
    026    import cpw.mods.fml.common.registry.IThrowableEntity;
    027
    028    public class EntitySpawnPacket extends FMLPacket
    029    {
    030
    031        public int networkId;
    032        public int modEntityId;
    033        public int entityId;
    034        public double scaledX;
    035        public double scaledY;
    036        public double scaledZ;
    037        public float scaledYaw;
    038        public float scaledPitch;
    039        public float scaledHeadYaw;
    040        public List metadata;
    041        public int throwerId;
    042        public double speedScaledX;
    043        public double speedScaledY;
    044        public double speedScaledZ;
    045        public ByteArrayDataInput dataStream;
    046        public int rawX;
    047        public int rawY;
    048        public int rawZ;
    049
    050        public EntitySpawnPacket()
    051        {
    052            super(Type.ENTITYSPAWN);
    053        }
    054
    055        @Override
    056        public byte[] generatePacket(Object... data)
    057        {
    058            EntityRegistration er = (EntityRegistration) data[0];
    059            Entity ent = (Entity) data[1];
    060            NetworkModHandler handler = (NetworkModHandler) data[2];
    061            ByteArrayDataOutput dat = ByteStreams.newDataOutput();
    062
    063            dat.writeInt(handler.getNetworkId());
    064            dat.writeInt(er.getModEntityId());
    065            // entity id
    066            dat.writeInt(ent.entityId);
    067
    068            // entity pos x,y,z
    069            dat.writeInt(MathHelper.floor_double(ent.posX * 32D));
    070            dat.writeInt(MathHelper.floor_double(ent.posY * 32D));
    071            dat.writeInt(MathHelper.floor_double(ent.posZ * 32D));
    072
    073            // yaw, pitch
    074            dat.writeByte((byte) (ent.rotationYaw * 256.0F / 360.0F));
    075            dat.writeByte((byte) (ent.rotationPitch * 256.0F / 360.0F));
    076
    077            // head yaw
    078            if (ent instanceof EntityLiving)
    079            {
    080                dat.writeByte((byte) (((EntityLiving)ent).rotationYawHead * 256.0F / 360.0F));
    081            }
    082            else
    083            {
    084                dat.writeByte(0);
    085            }
    086            ByteArrayOutputStream bos = new ByteArrayOutputStream();
    087            DataOutputStream dos = new DataOutputStream(bos);
    088            try
    089            {
    090                ent.getDataWatcher().writeWatchableObjects(dos);
    091            }
    092            catch (IOException e)
    093            {
    094                // unpossible
    095            }
    096
    097            dat.write(bos.toByteArray());
    098
    099            if (ent instanceof IThrowableEntity)
    100            {
    101                Entity owner = ((IThrowableEntity)ent).getThrower();
    102                dat.writeInt(owner == null ? ent.entityId : owner.entityId);
    103                double maxVel = 3.9D;
    104                double mX = ent.motionX;
    105                double mY = ent.motionY;
    106                double mZ = ent.motionZ;
    107                if (mX < -maxVel) mX = -maxVel;
    108                if (mY < -maxVel) mY = -maxVel;
    109                if (mZ < -maxVel) mZ = -maxVel;
    110                if (mX >  maxVel) mX =  maxVel;
    111                if (mY >  maxVel) mY =  maxVel;
    112                if (mZ >  maxVel) mZ =  maxVel;
    113                dat.writeInt((int)(mX * 8000D));
    114                dat.writeInt((int)(mY * 8000D));
    115                dat.writeInt((int)(mZ * 8000D));
    116            }
    117            else
    118            {
    119                dat.writeInt(0);
    120            }
    121            if (ent instanceof IEntityAdditionalSpawnData)
    122            {
    123                ((IEntityAdditionalSpawnData)ent).writeSpawnData(dat);
    124            }
    125
    126            return dat.toByteArray();
    127        }
    128
    129        @Override
    130        public FMLPacket consumePacket(byte[] data)
    131        {
    132            ByteArrayDataInput dat = ByteStreams.newDataInput(data);
    133            networkId = dat.readInt();
    134            modEntityId = dat.readInt();
    135            entityId = dat.readInt();
    136            rawX = dat.readInt();
    137            rawY = dat.readInt();
    138            rawZ = dat.readInt();
    139            scaledX = rawX / 32D;
    140            scaledY = rawY / 32D;
    141            scaledZ = rawZ / 32D;
    142            scaledYaw = dat.readByte() * 360F / 256F;
    143            scaledPitch = dat.readByte() * 360F / 256F;
    144            scaledHeadYaw = dat.readByte() * 360F / 256F;
    145            ByteArrayInputStream bis = new ByteArrayInputStream(data, 27, data.length - 27);
    146            DataInputStream dis = new DataInputStream(bis);
    147            try
    148            {
    149                metadata = DataWatcher.readWatchableObjects(dis);
    150            }
    151            catch (IOException e)
    152            {
    153                // Nope
    154            }
    155            dat.skipBytes(data.length - bis.available() - 27);
    156            throwerId = dat.readInt();
    157            if (throwerId != 0)
    158            {
    159                speedScaledX = dat.readInt() / 8000D;
    160                speedScaledY = dat.readInt() / 8000D;
    161                speedScaledZ = dat.readInt() / 8000D;
    162            }
    163
    164            this.dataStream = dat;
    165            return this;
    166        }
    167
    168        @Override
    169        public void execute(INetworkManager network, FMLNetworkHandler handler, NetHandler netHandler, String userName)
    170        {
    171            NetworkModHandler nmh = handler.findNetworkModHandler(networkId);
    172            ModContainer mc = nmh.getContainer();
    173
    174            EntityRegistration registration = EntityRegistry.instance().lookupModSpawn(mc, modEntityId);
    175            Class<? extends Entity> cls =  registration.getEntityClass();
    176            if (cls == null)
    177            {
    178                FMLLog.log(Level.WARNING, "Missing mod entity information for %s : %d", mc.getModId(), modEntityId);
    179                return;
    180            }
    181
    182
    183            Entity entity = FMLCommonHandler.instance().spawnEntityIntoClientWorld(registration, this);
    184        }
    185
    186    }