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