    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}