    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}