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    }