package net.minecraftforge.fml.common.network.internal;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.util.List;
import org.apache.logging.log4j.Level;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.util.IThreadListener;
import net.minecraft.world.World;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.internal.FMLMessage.EntityAdjustMessage;
import net.minecraftforge.fml.common.network.internal.FMLMessage.EntityMessage;
import net.minecraftforge.fml.common.registry.EntityRegistry;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.fml.common.registry.IThrowableEntity;
import net.minecraftforge.fml.common.registry.EntityRegistry.EntityRegistration;
import com.google.common.base.Throwables;
public class EntitySpawnHandler extends SimpleChannelInboundHandler<FMLMessage.EntityMessage> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, final EntityMessage msg) throws Exception
{
IThreadListener thread = FMLCommonHandler.instance().getWorldThread(ctx.channel().attr(NetworkRegistry.NET_HANDLER).get());
if (thread.isCallingFromMinecraftThread())
{
process(msg);
}
else
{
thread.addScheduledTask(new Runnable()
{
public void run()
{
EntitySpawnHandler.this.process(msg);
}
});
}
}
private void process(EntityMessage msg)
{
if (msg.getClass().equals(FMLMessage.EntitySpawnMessage.class))
{
spawnEntity((FMLMessage.EntitySpawnMessage)msg);
}
else if (msg.getClass().equals(FMLMessage.EntityAdjustMessage.class))
{
adjustEntity((FMLMessage.EntityAdjustMessage)msg);
}
}
private void adjustEntity(EntityAdjustMessage msg)
{
Entity ent = FMLClientHandler.instance().getWorldClient().getEntityByID(msg.entityId);
if (ent != null)
{
ent.serverPosX = msg.serverX;
ent.serverPosY = msg.serverY;
ent.serverPosZ = msg.serverZ;
}
else
{
FMLLog.fine("Attempted to adjust the position of entity %d which is not present on the client", msg.entityId);
}
}
private void spawnEntity(FMLMessage.EntitySpawnMessage spawnMsg)
{
ModContainer mc = Loader.instance().getIndexedModList().get(spawnMsg.modId);
EntityRegistration er = EntityRegistry.instance().lookupModSpawn(mc, spawnMsg.modEntityTypeId);
if (er == null)
{
throw new RuntimeException( "Could not spawn mod entity ModID: " + spawnMsg.modId + " EntityID: " + spawnMsg.modEntityTypeId +
" at ( " + spawnMsg.scaledX + "," + spawnMsg.scaledY + ", " + spawnMsg.scaledZ + ") Please contact mod author or server admin.");
}
WorldClient wc = FMLClientHandler.instance().getWorldClient();
Class<? extends Entity> cls = er.getEntityClass();
try
{
Entity entity;
if (er.hasCustomSpawning())
{
entity = er.doCustomSpawning(spawnMsg);
} else
{
entity = (Entity) (cls.getConstructor(World.class).newInstance(wc));
int offset = spawnMsg.entityId - entity.getEntityId();
entity.setEntityId(spawnMsg.entityId);
entity.setLocationAndAngles(spawnMsg.scaledX, spawnMsg.scaledY, spawnMsg.scaledZ, spawnMsg.scaledYaw, spawnMsg.scaledPitch);
if (entity instanceof EntityLiving)
{
((EntityLiving) entity).rotationYawHead = spawnMsg.scaledHeadYaw;
}
Entity parts[] = entity.getParts();
if (parts != null)
{
for (int j = 0; j < parts.length; j++)
{
parts[j].setEntityId(parts[j].getEntityId() + offset);
}
}
}
entity.serverPosX = spawnMsg.rawX;
entity.serverPosY = spawnMsg.rawY;
entity.serverPosZ = spawnMsg.rawZ;
EntityPlayerSP clientPlayer = FMLClientHandler.instance().getClientPlayerEntity();
if (entity instanceof IThrowableEntity)
{
Entity thrower = clientPlayer.getEntityId() == spawnMsg.throwerId ? clientPlayer : wc.getEntityByID(spawnMsg.throwerId);
((IThrowableEntity) entity).setThrower(thrower);
}
if (spawnMsg.dataWatcherList != null)
{
entity.getDataWatcher().updateWatchedObjectsFromList((List<?>) spawnMsg.dataWatcherList);
}
if (spawnMsg.throwerId > 0)
{
entity.setVelocity(spawnMsg.speedScaledX, spawnMsg.speedScaledY, spawnMsg.speedScaledZ);
}
if (entity instanceof IEntityAdditionalSpawnData)
{
((IEntityAdditionalSpawnData) entity).readSpawnData(spawnMsg.dataStream);
}
wc.addEntityToWorld(spawnMsg.entityId, entity);
} catch (Exception e)
{
FMLLog.log(Level.ERROR, e, "A severe problem occurred during the spawning of an entity at ( " + spawnMsg.scaledX + "," + spawnMsg.scaledY + ", " + spawnMsg.scaledZ +")");
throw Throwables.propagate(e);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
{
FMLLog.log(Level.ERROR, cause, "EntitySpawnHandler exception");
super.exceptionCaught(ctx, cause);
}
}