001package cpw.mods.fml.common.network;
002
003import java.io.ByteArrayInputStream;
004import java.io.ByteArrayOutputStream;
005import java.io.DataInputStream;
006import java.io.DataOutputStream;
007import java.io.IOException;
008import java.util.List;
009import java.util.logging.Level;
010
011import net.minecraft.entity.*;
012import net.minecraft.network.INetworkManager;
013import net.minecraft.network.packet.NetHandler;
014import net.minecraft.util.MathHelper;
015
016import com.google.common.io.ByteArrayDataInput;
017import com.google.common.io.ByteArrayDataOutput;
018import com.google.common.io.ByteStreams;
019
020import cpw.mods.fml.common.FMLCommonHandler;
021import cpw.mods.fml.common.FMLLog;
022import cpw.mods.fml.common.ModContainer;
023import cpw.mods.fml.common.registry.EntityRegistry;
024import cpw.mods.fml.common.registry.EntityRegistry.EntityRegistration;
025import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
026import cpw.mods.fml.common.registry.IThrowableEntity;
027
028public 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}