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}