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