code:
package astrotibs.notenoughpets.events;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Nullable;

import astrotibs.notenoughpets.ModNotEnoughPets;
import astrotibs.notenoughpets.capabilities.shoulderriding.IShoulderRiding;
import astrotibs.notenoughpets.capabilities.shoulderriding.ShoulderRidingProvider;
import astrotibs.notenoughpets.config.GeneralConfig;
import astrotibs.notenoughpets.entity.EntityMooshroomNEP;
import astrotibs.notenoughpets.entity.EntityOcelotNEP;
import astrotibs.notenoughpets.entity.EntityParrotNEP;
import astrotibs.notenoughpets.entity.EntityWolfNEP;
import astrotibs.notenoughpets.name.BlackCatNames;
import astrotibs.notenoughpets.network.MessageShoulderParrots;
import astrotibs.notenoughpets.util.FunctionsNEP;
import astrotibs.notenoughpets.util.LogHelper;
import astrotibs.notenoughpets.util.Reference;
import astrotibs.notenoughpets.util.SkinVariations;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.passive.EntityMooshroom;
import net.minecraft.entity.passive.EntityOcelot;
import net.minecraft.entity.passive.EntityTameable;
import net.minecraft.entity.passive.EntityWolf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Biomes;
import net.minecraft.init.Blocks;
import net.minecraft.init.SoundEvents;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.village.Village;
import net.minecraft.village.VillageCollection;
import net.minecraft.world.World;
import net.minecraft.world.gen.structure.MapGenStructureData;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent.EntityInteract;
import net.minecraftforge.event.terraingen.PopulateChunkEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.common.gameevent.TickEvent.WorldTickEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.relauncher.ReflectionHelper;

public class EventHandlerNEP {

	/**
	 * Use this to confirm entity class paths for adding them to the parrot imitation list
	 */
	@SubscribeEvent(receiveCanceled=true)
	public void printDebugClassPath(EntityInteract event)
	{
		if (
				GeneralConfig.debugMessages
				&& event.getEntity() instanceof EntityPlayer		// IF A PLAYER INITIALIZES THIS INTERACTION
				&& !event.getEntityPlayer().worldObj.isRemote	// WORLD MUST NOT BE CLIENT
				&& event.getTarget() instanceof EntityLiving		// AND THE TARGET IS A LIVING THING
				&& !(event.getTarget() instanceof EntityPlayer)	// BUT NOT A PLAYER
				) {
			EntityPlayer player = (EntityPlayer) event.getEntity(); 							// The player
			String targetClassPath = event.getTarget().getClass().toString().substring(6);	// The classpath string of the target

			player.addChatComponentMessage(new TextComponentString("Class path of this entity: " + targetClassPath));

			player.addChatComponentMessage(new TextComponentString(""));
		}
	}

	/**
	 * This is here to play particular sounds when a cat is injured by a living entity
	 */
	@SubscribeEvent
	public void onLivingHurtEvent(LivingHurtEvent event)
	{
		// summon notenoughcats.Ocelot_NEC ~ ~ ~ {Owner:AstroTibs, CatType:0}
		// summon notenoughcats.Ocelot_NEC ~ ~ ~ {Owner:AstroTibs, CatType:0, Age:-24000}
		// summon notenoughcats.Ocelot_NEC ~ ~ ~ {CatType:0}

		if (!event.getEntityLiving().worldObj.isRemote)
		{
			if (event.getEntity() instanceof EntityOcelotNEP)
			{
				EntityOcelotNEP ocelot = (EntityOcelotNEP)event.getEntity();

				if (ocelot.getHealth() <= event.getAmount())
				{ // Play a death sound depending on whether or not it's an ocelot.
					if (ocelot.getTameSkin()==0)
					     {event.getEntity().playSound(Reference.SE_ENTITY_CAT_OCELOT_DEATH, ocelot.getOcelotVolume(), FunctionsNEP.getScaledSoundPitch(ocelot));}
					else {event.getEntity().playSound(SoundEvents.ENTITY_CAT_DEATH, ocelot.getOcelotVolume(), FunctionsNEP.getScaledSoundPitch(ocelot));}
				}
				else if (
						(event.getSource().getSourceOfDamage() instanceof EntityPlayer
								||event.getSource().getSourceOfDamage() instanceof EntityLiving)
							&& event.getEntity().worldObj.rand.nextInt(4)==0)
				     {event.getEntity().playSound(Reference.SE_CAT_HISS, ocelot.getOcelotVolume(), FunctionsNEP.getScaledSoundPitch(ocelot));}
				else {event.getEntity().playSound(SoundEvents.ENTITY_CAT_HURT, ocelot.getOcelotVolume(), FunctionsNEP.getScaledSoundPitch(ocelot));}
			}

			// Parrots leave your shoulders when you're hurt
			else if (event.getEntity() instanceof EntityPlayer)
			{
				EntityPlayer player = (EntityPlayer)event.getEntity();
				if (
						!player.isEntityInvulnerable(event.getSource())
						&& (!player.capabilities.disableDamage || event.getSource().canHarmInCreative())
						&& player.getHealth() > 0.0F
						)
				{
					spawnShoulderEntities(player);
				}
			}
		}
	}

	@SubscribeEvent
	public void onLivingDeath(LivingDeathEvent event)
	{
		// Parrots leave your shoulders when you die
		if (
				!event.getEntityLiving().worldObj.isRemote
				&& event.getEntityLiving() instanceof EntityPlayer
				)
		{
			spawnShoulderEntities((EntityPlayer)event.getEntityLiving());
		}
	}

	@SubscribeEvent
	public void onLivingUpdate(LivingUpdateEvent event)
	{
		if (event.getEntityLiving().worldObj.isRemote) {return;} // Do server-side functions only

		if (event.getEntityLiving() instanceof EntityPlayer)
		{
			EntityPlayer player = (EntityPlayer)event.getEntityLiving();

			IShoulderRiding isr = player.getCapability(ShoulderRidingProvider.SHOULDER_RIDING, null);

			if (!GeneralConfig.enableNEPParrots)
			{
				isr.setLeftShoulderVariant(0);
				isr.setLeftShoulderAge(0);
				isr.setLeftShoulderEntity(new NBTTagCompound());
				isr.setRightShoulderVariant(0);
				isr.setRightShoulderAge(0);
				isr.setRightShoulderEntity(new NBTTagCompound());
				return;
			}

			NBTTagCompound leftParrot = isr.getLeftShoulderEntity();
			NBTTagCompound rightParrot = isr.getRightShoulderEntity();

			// Shoulder entities make noises
			playShoulderEntityAmbientSound(player, leftParrot);
	        playShoulderEntityAmbientSound(player, rightParrot);

	        if (
					player.fallDistance > GeneralConfig.parrotDismountFallHeight
					|| player.isInWater()
					//|| player.isRiding()
					|| player.capabilities.isFlying
					)
			{
				// Parrots leave your shoulders under certain movement conditions
				spawnShoulderEntities(player);
			}
			else if (player.isSpectator())
			{
				// Parrots leave your shoulders when you become a spectator
				spawnShoulderEntities(player);
			}
			else if (player.isPlayerSleeping())
			{
				// Parrots leave your shoulders when you sleep
				spawnShoulderEntities(player);
			}

			// Send a message to update everyone within 192 blocks
			NetworkRegistry.TargetPoint targetPoint = new NetworkRegistry.TargetPoint(player.dimension, player.lastTickPosX, player.lastTickPosY, player.lastTickPosZ, 16*12);
			ModNotEnoughPets.NECNetworkWrapper.sendToAllAround(
					new MessageShoulderParrots(player.getEntityId(),
							isr.getLeftShoulderVariant(), isr.getLeftShoulderAge(),
							isr.getRightShoulderVariant(), isr.getRightShoulderAge()
							), targetPoint);
		}
		// Convert ocelot if using the "vanilla when (un)tamed" config settings
		else if (
    			event.getEntity().getClass().toString().substring(6).equals(Reference.ENTITY_OCELOT_CLASSPATH)
    			&& GeneralConfig.enableNECCats
    			&& !GeneralConfig.revertAnimalTypes
    			)
    	{
    		EntityOcelot ocelotVanilla = (EntityOcelot) event.getEntity();

    		// If ocelots are flagged to remain vanilla, don't convert
    		if (
    				//(ocelotVanilla.isTamed() && !GeneralConfig.tamedOcelotsRemainVanilla) ||
    				(!ocelotVanilla.isTamed() && !GeneralConfig.untamedOcelotsRemainVanilla)
    				)
    		{
    			convertVanillaOcelotToNEP(ocelotVanilla);
    			return;
    		}

    		return;
    	}
		// De-convert ocelot if using the "vanilla when (un)tamed" config settings
    	else if (event.getEntityLiving() instanceof EntityOcelotNEP)
    	{
    		EntityOcelotNEP ocelotNEC = (EntityOcelotNEP) event.getEntityLiving();

    		// If ocelots are flagged to remain NEP, don't convert
			if (
					(ocelotNEC.getTameSkin()==0
					&& (
							// (ocelotNEC.isTamed() && GeneralConfig.tamedOcelotsRemainVanilla) ||
							(!ocelotNEC.isTamed() && GeneralConfig.untamedOcelotsRemainVanilla)
							))

					|| GeneralConfig.revertAnimalTypes || !GeneralConfig.enableNECCats
					)
			{
				convertNEPOcelotToVanilla(ocelotNEC);
    			return;
			}

			return;
    	}
		// De-convert wolf if using the "vanilla when (un)tamed" config settings
    	else if (event.getEntityLiving() instanceof EntityWolfNEP)
    	{
    		EntityWolfNEP wolfNEC = (EntityWolfNEP) event.getEntityLiving();

    		// If wolves are flagged to remain NEP, don't convert
			if (
					(wolfNEC.getTameSkin()==0
					&& ((wolfNEC.isTamed() && GeneralConfig.tamedWolvesRemainVanilla)
							|| (!wolfNEC.isTamed() && GeneralConfig.untamedWolvesRemainVanilla)))

					|| GeneralConfig.revertAnimalTypes || !GeneralConfig.enableNECDogs
					)
			{
				convertNEPWolfToVanilla(wolfNEC);
				return;
			}

			return;
    	}
		// Convert wolf if using the "vanilla when (un)tamed" config settings
    	else if (
    			event.getEntity().getClass().toString().substring(6).equals(Reference.ENTITY_WOLF_CLASSPATH)
    			&& GeneralConfig.enableNECDogs
    			&& !GeneralConfig.revertAnimalTypes
    			)
    	{
    		EntityWolf wolfVanilla = (EntityWolf) event.getEntity();

    		if (
    				(wolfVanilla.isTamed() && !GeneralConfig.tamedWolvesRemainVanilla)
    				|| (!wolfVanilla.isTamed() && !GeneralConfig.untamedWolvesRemainVanilla)
    				)
    		{
    			convertVanillaWolfToNEP(wolfVanilla);
    			return;
    		}

    		return;
    	}
	}

    private void playShoulderEntityAmbientSound(EntityPlayer player, @Nullable NBTTagCompound shoulderEntityTag)
    {
        if (
        		shoulderEntityTag != null
        		&& (
        				!shoulderEntityTag.hasKey("Silent")
        				|| (shoulderEntityTag.hasKey("Silent") && !shoulderEntityTag.getBoolean("Silent"))
        				)
        		)
        {
            String s = shoulderEntityTag.getString("id");

            if (s.equals(Reference.MOD_ID + "." + Reference.MOB_PARROT_NEP))
            {
            	int entityAge = 0;

            	if (shoulderEntityTag.hasKey("Age")) {entityAge = shoulderEntityTag.getInteger("Age");}

            	EntityParrotNEP.playAmbientSound(player.worldObj, player, entityAge);
            }
        }
    }

    public void spawnShoulderEntities(EntityPlayer player)
    {
    	IShoulderRiding isr = player.getCapability(ShoulderRidingProvider.SHOULDER_RIDING, null);

    	// Left Shoulder
        spawnShoulderEntity(player, isr.getLeftShoulderEntity());
        isr.setLeftShoulderEntity(new NBTTagCompound());
        isr.setLeftShoulderVariant(0); // 0 means "none" in this case
        // Right Shoulder
        spawnShoulderEntity(player, isr.getRightShoulderEntity());
        isr.setRightShoulderEntity(new NBTTagCompound());
        isr.setRightShoulderVariant(0); // 0 means "none" in this case
    }

    private void spawnShoulderEntity(@Nullable EntityPlayer player, NBTTagCompound tagcompound)
    {
        if (!player.worldObj.isRemote)
        {
        	if(!(tagcompound==null) && !tagcompound.hasNoTags())
        	{
        		// Add failsafe
        		try
        		{
        			tagcompound.setBoolean("NoGravity", true); // Added manually to force flying from shoulders
                    Entity entity = EntityList.createEntityFromNBT(tagcompound, player.worldObj);

                    if (entity instanceof EntityTameable)
                    {
                        ((EntityTameable)entity).setOwnerId(player.getUniqueID());
                    }

                    entity.setPosition(player.posX, player.posY + 0.699999988079071D, player.posZ);
                    player.worldObj.spawnEntityInWorld(entity);
        		}
        		catch (Exception e) {}
        	}
        }
    }

	/**
	 * This method intercepts every spawned cat/dog and replaces it with my version.
	 * Alternately, you can reverse this.
	 *
	 * In addition, there is a limiter to prevent ocelot/wolf spawns
	 */
    @SubscribeEvent
    public void onEntityJoinWorld(EntityJoinWorldEvent event)
    {
    	if (!event.getWorld().isRemote)
    	{

			/*
			 * This section below actively prevents vanilla Ocelots and Wolves from spawning when there are too many in the region
			 */
    		if (
    				event.getEntity() instanceof EntityLiving
    				&& !GeneralConfig.revertAnimalTypes
    				&& !((EntityLiving)event.getEntity()).isNoDespawnRequired()
    				&& !event.getEntity().getClass().toString().substring(6).equals("com.emoniph.witchery.entity.EntityWitchCat")
    				)
    		{
    			Class entityNEC = null;
    			int regionLimit = 0;

    			if (
    					event.getEntity() instanceof EntityOcelot && !(event.getEntity() instanceof EntityOcelotNEP) && GeneralConfig.enableNECCats && !((EntityOcelot)event.getEntity()).isTamed()
    					&& GeneralConfig.spawnLimitOcelot > -1
    					)
    			{
    				entityNEC = EntityOcelot.class;
    				regionLimit = GeneralConfig.spawnLimitOcelot;
    			}
    			else if (
    					event.getEntity() instanceof EntityWolf && !(event.getEntity() instanceof EntityWolfNEP) && GeneralConfig.enableNECDogs && !((EntityWolf)event.getEntity()).isTamed()
    					&& GeneralConfig.spawnLimitWolf > -1
    					)
    			{
    				entityNEC = EntityWolf.class;
    				regionLimit = GeneralConfig.spawnLimitWolf;
    			}
    			else if (
    					event.getEntity() instanceof EntityMooshroom && !(event.getEntity() instanceof EntityMooshroomNEP) && GeneralConfig.enableNECMooshrooms
    					&& GeneralConfig.spawnLimitMooshroom > -1
    					)
    			{
    				entityNEC = EntityMooshroom.class;
    				regionLimit = GeneralConfig.spawnLimitMooshroom;
    			}

    			else if (
    					event.getEntity() instanceof EntityParrotNEP
    					&& GeneralConfig.spawnLimitParrot > -1
    					)
    			{
    				entityNEC = EntityParrotNEP.class;
    				regionLimit = GeneralConfig.spawnLimitParrot;
    			}

    			if (entityNEC != null)
    			{
    				// Get the entity's position
    				double eventX = event.getEntity().posX;
    				double eventY = event.getEntity().posY;
    				double eventZ = event.getEntity().posZ;

    				// Check to see if it's over the regional limit
    				if (
    						event.getEntity().worldObj.getEntitiesWithinAABB(entityNEC, // Changed this from EntityAnimal.class
    								new AxisAlignedBB(eventX-128, 0, eventZ-128, eventX+128, event.getEntity().worldObj.getHeight(), eventZ+128)).size() >= regionLimit
    						)
    				{
    					event.setCanceled(true);
    					if (GeneralConfig.debugMessages) {LogHelper.info(event.getEntity() + " denied from spawning; number of that entity in surrounding area: " + event.getEntity().worldObj.getEntitiesWithinAABB(entityNEC, new AxisAlignedBB(eventX-128, 0, eventZ-128, eventX+128, event.getEntity().worldObj.getHeight(), eventZ+128)).size());}
    					return; // No need to do the below section where you substitute vanilla for NEC or vice-versa
    				}
    			}
    		}

    		// -------------------------------------------------------- //
    		// --- Inter-conversion between vanilla and NEC ocelots --- //
    		// -------------------------------------------------------- //
        	if (
        			event.getEntity().getClass().toString().substring(6).equals(Reference.ENTITY_OCELOT_CLASSPATH)
        			&& GeneralConfig.enableNECCats
        			&& !GeneralConfig.revertAnimalTypes
        			)
        	{
        		EntityOcelot ocelotVanilla = (EntityOcelot) event.getEntity();

        		// If ocelots are flagged to remain vanilla, don't convert
        		if (
        				(!ocelotVanilla.isTamed() && !GeneralConfig.untamedOcelotsRemainVanilla)
        				)
        		{
        			convertVanillaOcelotToNEP(ocelotVanilla);
        			return;
        		}

        		return;
        	}
        	else if (event.getEntity() instanceof EntityOcelotNEP)
        	{
        		EntityOcelotNEP ocelotNEC = (EntityOcelotNEP) event.getEntity();

        		// If ocelots are flagged to remain NEP, don't convert
    			if (
    					(ocelotNEC.getTameSkin()==0
    						&& (
    								(!ocelotNEC.isTamed() && GeneralConfig.untamedOcelotsRemainVanilla)
    							))
    					|| GeneralConfig.revertAnimalTypes || !GeneralConfig.enableNECCats
    					)
    			{
    				convertNEPOcelotToVanilla(ocelotNEC);
    				return;
    			}

        		return;
        	}

        	// ------------------------------------------------------- //
    		// --- Inter-conversion between vanilla and NEC wolves --- //
    		// ------------------------------------------------------- //
        	else if (
        			//event.getEntity() instanceof EntityWolf
        			//&& !(event.getEntity() instanceof EntityWolfNEC)
        			event.getEntity().getClass().toString().substring(6).equals(Reference.ENTITY_WOLF_CLASSPATH)
        			&& GeneralConfig.enableNECDogs
        			&& !GeneralConfig.revertAnimalTypes
        			)
        	{
        		EntityWolf wolfVanilla = (EntityWolf) event.getEntity();

        		// If wolves are flagged to remain vanilla, don't convert
        		if (
        				(wolfVanilla.isTamed() && !GeneralConfig.tamedWolvesRemainVanilla)
        				|| (!wolfVanilla.isTamed() && !GeneralConfig.untamedWolvesRemainVanilla)
        				)
        		{
        			convertVanillaWolfToNEP(wolfVanilla);
        			return;
        		}

        		return;
        	}
        	else if (event.getEntity() instanceof EntityWolfNEP)
        	{
        		EntityWolfNEP wolfNEC = (EntityWolfNEP) event.getEntity();

        		// If wolves are flagged to remain NEP, don't convert
    			if (
    					(wolfNEC.getTameSkin()==0
    					&& ((wolfNEC.isTamed() && GeneralConfig.tamedWolvesRemainVanilla)
    							|| (!wolfNEC.isTamed() && GeneralConfig.untamedWolvesRemainVanilla)))
    					|| GeneralConfig.revertAnimalTypes || !GeneralConfig.enableNECDogs
    					)
    			{
    				convertNEPWolfToVanilla(wolfNEC);
    				return;
    			}

        		return;
        	}

        	// ----------------------------------------------------------- //
    		// --- Inter-conversion between vanilla and NEC mooshrooms --- //
    		// ----------------------------------------------------------- //
        	else if (
        			event.getEntity().getClass().toString().substring(6).equals(Reference.ENTITY_MOOSHROOM_CLASSPATH)
        			&& GeneralConfig.enableNECMooshrooms
        			&& !GeneralConfig.revertAnimalTypes
        			)
        	{
        		EntityMooshroom mooshroomVanilla = (EntityMooshroom) event.getEntity();

        		mooshroomVanilla.lastTickPosX = mooshroomVanilla.posX;
        		mooshroomVanilla.lastTickPosY = mooshroomVanilla.posY;
        		mooshroomVanilla.lastTickPosZ = mooshroomVanilla.posZ;

        		EntityMooshroomNEP mooshroomNEC = new EntityMooshroomNEP(mooshroomVanilla.worldObj);
        		mooshroomNEC.setLocationAndAngles(mooshroomVanilla.posX, mooshroomVanilla.posY, mooshroomVanilla.posZ, mooshroomVanilla.rotationYaw, 0.0F);

        		mooshroomNEC.setGrowingAge(mooshroomVanilla.getGrowingAge());

        		// Set other properties
        		mooshroomNEC.setCustomNameTag(mooshroomVanilla.getCustomNameTag());

        		//ocelot.setHealth(0);
        		mooshroomVanilla.setDead();
        		mooshroomNEC.worldObj.spawnEntityInWorld(mooshroomNEC);

        		return;
        	}
        	else if (
        			(GeneralConfig.revertAnimalTypes || !GeneralConfig.enableNECMooshrooms)
        			&& (event.getEntity() instanceof EntityMooshroomNEP)
        			)
        	{
        		EntityMooshroomNEP mooshroomNEC = (EntityMooshroomNEP) event.getEntity();

        		mooshroomNEC.lastTickPosX = mooshroomNEC.posX;
        		mooshroomNEC.lastTickPosY = mooshroomNEC.posY;
        		mooshroomNEC.lastTickPosZ = mooshroomNEC.posZ;

        		EntityMooshroom mooshroomVanilla = new EntityMooshroom(mooshroomNEC.worldObj);
        		mooshroomVanilla.setLocationAndAngles(mooshroomNEC.posX, mooshroomNEC.posY, mooshroomNEC.posZ, mooshroomNEC.rotationYaw, 0.0F);

        		mooshroomVanilla.setGrowingAge(mooshroomNEC.getGrowingAge());

        		// Set other properties
        		mooshroomVanilla.setCustomNameTag(mooshroomNEC.getCustomNameTag());

        		//ocelot.setHealth(0);
        		mooshroomNEC.setDead();
        		mooshroomVanilla.worldObj.spawnEntityInWorld(mooshroomVanilla);

        		return;
        	}
    	}
    }

	/**
	 * This method is intended to randomly spawn feral cats and dogs into villages
	 */
	@SubscribeEvent
	public void spawnStraysWithVillageTick(WorldTickEvent event)
	{
		if (
				Arrays.binarySearch(GeneralConfig.strayDimensions, event.world.provider.getDimension()) >= 0 // Don't spawn a stray in the wrong dimension
						&& (((GeneralConfig.enableNECCats && !GeneralConfig.revertAnimalTypes) ? GeneralConfig.villageSpawnCapCat : 0) + ((GeneralConfig.enableNECDogs && !GeneralConfig.revertAnimalTypes)? GeneralConfig.villageSpawnCapDog : 0)) > 0 // Only allowed if the player allows strays
				&& !event.world.isRemote
				&& event.phase == Phase.END
				)
		{
			VillageCollection vc = event.world.villageCollectionObj;

			int vcTickCounter = ReflectionHelper.getPrivateValue(VillageCollection.class, vc, new String[]{"tickCounter", "field_75553_e"}); // The MCP mapping for this field name

			if (vcTickCounter % 30 == 0)
			{
				Iterator iterator = vc.getVillageList().iterator();

				while (iterator.hasNext())
		        {
		            Village village = (Village)iterator.next();

					if (GeneralConfig.debugMessages && vcTickCounter%90==0) {LogHelper.info("Village " + village + " cats: " + countEntityAroundVillage(EntityOcelot.class, village, event.world, Reference.VILLAGE_RADIUS_BUFFER) + ", dogs: " + countEntityAroundVillage(EntityWolf.class, village, event.world, Reference.VILLAGE_RADIUS_BUFFER));}

					// Prevent spawning of animals whose NEP versions aren't enabled
		            if (((GeneralConfig.enableNECCats && !GeneralConfig.revertAnimalTypes && GeneralConfig.villageSpawnCapCat > 0 ? countEntityAroundVillage(EntityOcelotNEP.class, village, event.world, Reference.VILLAGE_RADIUS_BUFFER) : 0) +
		            		(GeneralConfig.enableNECDogs && !GeneralConfig.revertAnimalTypes && GeneralConfig.villageSpawnCapDog > 0 ? countEntityAroundVillage(EntityWolfNEP.class, village, event.world, Reference.VILLAGE_RADIUS_BUFFER) : 0))
		            		< Math.min(GeneralConfig.strayCapFromVillageRadius ? (village.getVillageRadius()*village.getVillageRadius())/Reference.VILLAGE_BLOCKS_PER_STRAY_LIMIT : Math.min(village.getNumVillagers(), village.getNumVillageDoors()/4), GeneralConfig.revertAnimalTypes ? 0 : Math.max(GeneralConfig.enableNECCats ? GeneralConfig.villageSpawnCapCat : 0, GeneralConfig.enableNECDogs ? GeneralConfig.villageSpawnCapDog : 0))
		            		&& (event.world.rand.nextInt(100) < GeneralConfig.villageSpawnRatePercent)
		            		)
		            {
		            	trySpawnStray(village, event.world);
		            }
		        }
			}
		}
	}

	/**
	 * Spawns a black cat in every Swamp Hut
	 */
	@SubscribeEvent
	public void onPopulateChunkPost(PopulateChunkEvent.Post event)
	{
		if (
				GeneralConfig.swampHutCat
				&& GeneralConfig.enableNECCats && !GeneralConfig.revertAnimalTypes
				&& !event.getWorld().isRemote
				&& event.getWorld().provider.getDimension() == 0
				&& event.getWorld().getBiomeGenForCoords(new BlockPos(event.getChunkX()<<4, 64, event.getChunkZ()<<4)) == Biomes.SWAMPLAND
				)
		{
			MapGenStructureData structureData = null;

			try
			{
				NBTTagCompound nbttagcompound = null;

				try
				{
					structureData = (MapGenStructureData)event.getWorld().getPerWorldStorage().getOrLoadData(MapGenStructureData.class, "Temple");
	    			nbttagcompound = structureData.getTagCompound();
				}
				catch (Exception e)
	    		{
					try
	        		{
						structureData = (MapGenStructureData)event.getWorld().getPerWorldStorage().getOrLoadData(MapGenStructureData.class, "OTGTemple");
	        			nbttagcompound = structureData.getTagCompound();
	        		}
	        		catch (Exception e1) {}
	    		}

				Iterator itr = nbttagcompound.getKeySet().iterator();
				while (itr.hasNext())
				{
					Object element = itr.next();
					NBTBase nbtbase = nbttagcompound.getTag(element.toString());

					if (nbtbase.getId() == 10)
					{
						NBTTagCompound nbttagcompound2 = (NBTTagCompound)nbtbase;

						try
						{
							int[] boundingBox = nbttagcompound2.getIntArray("BB");
							if (searchNBTAndAddCat(nbttagcompound2, boundingBox, event.getWorld(), (event.getChunkX()<<4), (event.getChunkZ()<<4), 8, structureData)) {return;}
						}
						catch (Exception e2) {if (GeneralConfig.debugMessages) LogHelper.warn("Failed to evaluate Temple (Swamp Hut) bounding box");}
					}
				}
			}
			catch (Exception e3) {} // This fails when the Temple list is empty (i.e. none have been generated).
		}
	}

	/**
	 * Searches within a given swamp hut to see if a cat hasn't yet spawned and can spawn
	 */
	private static boolean searchNBTAndAddCat(NBTTagCompound nbttagcompound2, int[] boundingBox, World world, int xChunkCenter, int zChunkCenter, int buffer, MapGenStructureData structureData)
	{
		// Swamp hut seed 7892649471625196211

		if (
				   xChunkCenter >= boundingBox[0]-buffer
				//&& event.y >= boundingBox[1]
				&& zChunkCenter >= boundingBox[2]-buffer
				&& xChunkCenter <= boundingBox[3]+buffer
				//&& event.y <= boundingBox[4]
				&& zChunkCenter <= boundingBox[5]+buffer
				)
		{
			Block blocktoscan;

			for (int k = 50; k <= 80; k++) {
				for (int i=-8; i < 8; i++) {
					for (int j=-8; j < 8; j++) {

						blocktoscan = world.getBlockState(new BlockPos(xChunkCenter+i, k, zChunkCenter+j)).getBlock();

						// Put cat on or near the crafting table
						if (blocktoscan == Blocks.CRAFTING_TABLE)
						{
							for (int k1 = 0; k1 < 26; ++k1)
					        {
								int l = world.rand.nextInt(3)-1;
								int n = world.rand.nextInt(3)-1;
								int m = world.rand.nextInt(3)-1;

								if (
										world.getBlockState( new BlockPos(xChunkCenter+i+l, k+n, zChunkCenter+j+m) ).getBlock().isAir(world.getBlockState( new BlockPos(xChunkCenter+i+l, k+n, zChunkCenter+j+m) ), world, new BlockPos(xChunkCenter+i+l, k+n, zChunkCenter+j+m))
										&& world.getBlockState(new BlockPos(xChunkCenter+i+l, k+n-1, zChunkCenter+j+m)).isSideSolid(world, new BlockPos(xChunkCenter+i+l, k+n-1, zChunkCenter+j+m), EnumFacing.UP)
										)
								{
									EntityOcelotNEP entityBlackCat = new EntityOcelotNEP(world);

						    		((EntityOcelotNEP)entityBlackCat).setTameSkin(10); // Black cat

									entityBlackCat.setLocationAndAngles((double)(xChunkCenter+i+l)+Reference.SPAWN_BLOCK_OFFSET, (double)(k+n), (double)(zChunkCenter+j+m)+Reference.SPAWN_BLOCK_OFFSET, world.rand.nextFloat()*360, 0.0F);
					            	entityBlackCat.setTamed(false);
					            	// Persistence enabled on this cat
					            	entityBlackCat.enablePersistence();

					            	if (GeneralConfig.swampHutCatName) {entityBlackCat.setCustomNameTag(BlackCatNames.newRandomName(world.rand));}

					            	world.spawnEntityInWorld(entityBlackCat);

					            	if (GeneralConfig.debugMessages) {LogHelper.info("Adding black cat to swamp hut at " + (xChunkCenter+i+l) + " " + (k+n) + " " + (zChunkCenter+j+m));}

									return true;
								}
					        }
							if (GeneralConfig.debugMessages) {LogHelper.warn("Failed to add black cat to swamp hut at " + (xChunkCenter+i) + " " + (k) + " " + (zChunkCenter+j));}
						}
					}
				}
			}
		}
		return false;
	}

    /**
     * Counts how many stray cats and dogs are in the village and spawns one accordingly
     */
    private static void trySpawnStray(Village village, World world)
    {
    	int spawnCap;
    	Class strayClass;
    	float strayFraction;
    	EntityTameable entityStray;

    	// Select a cat or a dog
    	if (world.rand.nextFloat() < (!GeneralConfig.enableNECDogs ? 1 : GeneralConfig.strayFractionCat) && GeneralConfig.enableNECCats)
		{
    		// Selected "cat"
    		spawnCap = GeneralConfig.villageSpawnCapCat;
    		strayClass = EntityOcelot.class;
    		strayFraction = !GeneralConfig.enableNECDogs ? 1 : GeneralConfig.strayFractionCat;
    		entityStray = new EntityOcelotNEP(world);

    		((EntityOcelotNEP)entityStray).setTameSkin(
    				world.rand.nextInt(
    						((GeneralConfig.enableNECCats && !GeneralConfig.revertAnimalTypes) ? SkinVariations.catSkinArray.length : 4)-1)+1
    				);

		}
    	else if (GeneralConfig.enableNECDogs)
    	{
    		// Selected "dog"
    		spawnCap = GeneralConfig.villageSpawnCapDog;
    		strayClass = EntityWolf.class;
    		strayFraction = GeneralConfig.enableNECCats ? (1F-GeneralConfig.strayFractionCat) : 1F;
    		entityStray = new EntityWolfNEP(world);

    		((EntityWolfNEP)entityStray).setTameSkin(
    				(GeneralConfig.enableNECDogs && !GeneralConfig.revertAnimalTypes) ? world.rand.nextInt(SkinVariations.dogSkinArray.length-1)+1 : 0
    				);
    	}
    	else {return;}

        // Check and spawn stray
    	if (
    			spawnCap > 0 &&
    			countEntityAroundVillage(strayClass, village, world, Reference.VILLAGE_RADIUS_BUFFER)
    				< Math.min((int)Math.round(GeneralConfig.strayCapFromVillageRadius ? (village.getVillageRadius()*village.getVillageRadius())/Reference.VILLAGE_BLOCKS_PER_STRAY_LIMIT : Math.min(village.getNumVillagers(), village.getNumVillageDoors()/4)*strayFraction), spawnCap))
        {
    		Vec3d vec3 = findRandomSpawnPos(village, world, 2, 4, 2);

            if (vec3 != null)
            {
            	entityStray.setLocationAndAngles(vec3.xCoord, vec3.yCoord, vec3.zCoord, world.rand.nextFloat()*360, 0.0F);
            	entityStray.setTamed(false);
            	// 50% of the time, it's got an age between newborn and adult
            	entityStray.setGrowingAge(Math.min(24000-world.rand.nextInt(48001),0));
            	world.spawnEntityInWorld(entityStray);
            }
        }
    }

	/**
	 * Returns the count of occurrences of a particular class (and its derivatives) within and surrounding a town
	 */
    private static int countEntityAroundVillage(Class entityClass, Village village, World world, int villageBuffer)
    {
    	int vilX = village.getCenter().getX();
    	int vilY = village.getCenter().getY();
    	int vilZ = village.getCenter().getZ();
    	int vilR = village.getVillageRadius();

        List list = world.getEntitiesWithinAABB(entityClass,
        		new AxisAlignedBB(
	        		(double)(vilX - vilR - villageBuffer),
	        		(double)(vilY - 4),
	        		(double)(vilZ - vilR - villageBuffer),
	        		(double)(vilX + vilR + villageBuffer),
	        		(double)(vilY + 4),
	        		(double)(vilZ + vilR + villageBuffer)
        		));
        if (list != null) {return list.size();}
        else {return 0;}
    }

    /*
     * These three methods were taken from net.minecraft.village.Village, used to determine Iron Golem spawning
     */

    /**
     * Tries up to 10 times to get a valid spawning location before eventually failing and returning null.
     */

    private static Vec3d findRandomSpawnPos(Village village, World world, int x, int y, int z)
    {
    	int vilCenterX = village.getCenter().getX();
    	int vilCenterY = village.getCenter().getY();
    	int vilCenterZ = village.getCenter().getZ();
    	int vilRadius = village.getVillageRadius();

        for (int i = 0; i < 10; ++i)
        {
            BlockPos blockpos = new BlockPos(
            		vilCenterX + world.rand.nextInt(2*vilRadius+1) - vilRadius,
            		vilCenterY + world.rand.nextInt(8) - 4,
            		vilCenterZ + world.rand.nextInt(2*vilRadius+1) - vilRadius
            		);

            if (village.isBlockPosWithinSqVillageRadius(blockpos) && isAreaClearAround(world, new BlockPos(x, y, z), blockpos))
            {
                return new Vec3d((double)blockpos.getX(), (double)blockpos.getY(), (double)blockpos.getZ());
            }
        }

        return null;
    }

    /**
     * Checks to see if the volume around blockLocation is clear and able to fit blockSize
     */
    private static boolean isAreaClearAround(World world, BlockPos blockSize, BlockPos blockLocation)
    {
        if (!world.getBlockState(blockLocation.down()).isFullyOpaque())
        {
            return false;
        }
        else
        {
            int i = blockLocation.getX() - blockSize.getX() / 2;
            int j = blockLocation.getZ() - blockSize.getZ() / 2;

            for (int k = i; k < i + blockSize.getX(); ++k)
            {
                for (int l = blockLocation.getY(); l < blockLocation.getY() + blockSize.getY(); ++l)
                {
                    for (int i1 = j; i1 < j + blockSize.getZ(); ++i1)
                    {
                        if (world.getBlockState(new BlockPos(k, l, i1)).isNormalCube())
                        {
                            return false;
                        }
                    }
                }
            }

            return true;
        }
    }

    /**
     * Checks to see if the distance squared between this BlockPos and the center of this Village is less than this
     * Village's villageRadius squared
     */
    public boolean isBlockPosWithinSqVillageRadius(Village village, BlockPos pos)
    {
        return village.getCenter().distanceSq(pos) < (double)(village.getVillageRadius() * village.getVillageRadius());
    }

    // Helper function to convert vanilla ocelots to NEP since that's a bit more complicated now
    public void convertVanillaOcelotToNEP(EntityOcelot ocelotVanilla)
    {
		ocelotVanilla.lastTickPosX = ocelotVanilla.posX;
		ocelotVanilla.lastTickPosY = ocelotVanilla.posY;
		ocelotVanilla.lastTickPosZ = ocelotVanilla.posZ;

		EntityOcelotNEP ocelotNEC = new EntityOcelotNEP(ocelotVanilla.worldObj);
		ocelotNEC.setLocationAndAngles(ocelotVanilla.posX, ocelotVanilla.posY, ocelotVanilla.posZ, ocelotVanilla.rotationYaw, 0.0F);
		// Set age, in the event that the ocelot is followed along by babies
		ocelotNEC.setGrowingAge(ocelotVanilla.getGrowingAge());

		// Target stuff
		ocelotNEC.setAttackTarget(ocelotVanilla.getAttackTarget());
		ocelotNEC.setRevengeTarget(ocelotVanilla.getAITarget());

		// Owner stuff
		ocelotNEC.setTamed(ocelotVanilla.isTamed());
		if (ocelotVanilla.getOwnerId() != null)
        	//{ocelotNEC.setOwnerId("");}
        //else
        	{ocelotNEC.setOwnerId(ocelotVanilla.getOwnerId());}

		// Set other properties
		ocelotNEC.setCustomNameTag(ocelotVanilla.getCustomNameTag());
		ocelotNEC.setSitting(ocelotVanilla.isSitting());
		ocelotNEC.setTameSkin(ocelotVanilla.getTameSkin());

		//ocelot.setHealth(0);
		ocelotVanilla.setDead();
		ocelotNEC.worldObj.spawnEntityInWorld(ocelotNEC);
    }

    // Helper function to revert NEP ocelots to vanilla since that's a bit more complicated now
    public void convertNEPOcelotToVanilla(EntityOcelotNEP ocelotNEC)
    {
		ocelotNEC.lastTickPosX = ocelotNEC.posX;
		ocelotNEC.lastTickPosY = ocelotNEC.posY;
		ocelotNEC.lastTickPosZ = ocelotNEC.posZ;

		EntityOcelot ocelotVanilla = new EntityOcelot(ocelotNEC.worldObj);
		ocelotVanilla.setLocationAndAngles(ocelotNEC.posX, ocelotNEC.posY, ocelotNEC.posZ, ocelotNEC.rotationYaw, 0.0F);
		// Set age, in the event that the ocelot is followed along by babies
		ocelotVanilla.setGrowingAge(ocelotNEC.getGrowingAge());

		// Target stuff
		ocelotVanilla.setAttackTarget(ocelotNEC.getAttackTarget());
		ocelotVanilla.setRevengeTarget(ocelotNEC.getAITarget());

		// Owner stuff
		ocelotVanilla.setTamed(ocelotNEC.isTamed());
		if (ocelotNEC.getOwnerId() != null)
        	//{ocelotVanilla.setOwnerId("");}
        //else
        	{ocelotVanilla.setOwnerId(ocelotNEC.getOwnerId());}

		// Set other properties
		ocelotVanilla.setCustomNameTag(ocelotNEC.getCustomNameTag());
		ocelotVanilla.setSitting(ocelotNEC.isSitting());
		ocelotVanilla.setTameSkin(ocelotNEC.getTameSkin());

		//ocelot.setHealth(0);
		ocelotNEC.setDead();
		ocelotVanilla.worldObj.spawnEntityInWorld(ocelotVanilla);
    }

    // Helper function to convert vanilla wolves to NEP since that's a bit more complicated now
    public void convertVanillaWolfToNEP(EntityWolf wolfVanilla)
    {
		wolfVanilla.lastTickPosX = wolfVanilla.posX;
		wolfVanilla.lastTickPosY = wolfVanilla.posY;
		wolfVanilla.lastTickPosZ = wolfVanilla.posZ;

		EntityWolfNEP wolfNEC = new EntityWolfNEP(wolfVanilla.worldObj);
		wolfNEC.setLocationAndAngles(wolfVanilla.posX, wolfVanilla.posY, wolfVanilla.posZ, wolfVanilla.rotationYaw, 0.0F);

		wolfNEC.setGrowingAge(wolfVanilla.getGrowingAge());

		// Aggression stuff
		wolfNEC.setAngry(wolfVanilla.isAngry());
		wolfNEC.setAttackTarget(wolfVanilla.getAttackTarget());
		wolfNEC.setRevengeTarget(wolfVanilla.getAITarget());

		// Owner stuff
		wolfNEC.setTamed(wolfVanilla.isTamed());
		if (wolfVanilla.getOwnerId() != null)
			//{wolfNEC.setOwnerId("");}
        //else
        	{wolfNEC.setOwnerId(wolfVanilla.getOwnerId());}
		wolfNEC.setCollarColor(wolfVanilla.getCollarColor());

		// Set other properties
		wolfNEC.setCustomNameTag(wolfVanilla.getCustomNameTag());
		wolfNEC.setSitting(wolfVanilla.isSitting());
		//wolfNEC.setTameSkin(wolfVanilla.getTameSkin());

		//ocelot.setHealth(0);
		wolfVanilla.setDead();
		wolfNEC.worldObj.spawnEntityInWorld(wolfNEC);
    }

    // Helper function to revert NEP wolves to vanilla since that's a bit more complicated now
    public void convertNEPWolfToVanilla(EntityWolfNEP wolfNEC)
    {
		wolfNEC.lastTickPosX = wolfNEC.posX;
		wolfNEC.lastTickPosY = wolfNEC.posY;
		wolfNEC.lastTickPosZ = wolfNEC.posZ;

		EntityWolf wolfVanilla = new EntityWolf(wolfNEC.worldObj);
		wolfVanilla.setLocationAndAngles(wolfNEC.posX, wolfNEC.posY, wolfNEC.posZ, wolfNEC.rotationYaw, 0.0F);

		wolfVanilla.setGrowingAge(wolfNEC.getGrowingAge());

		// Aggression stuff
		wolfVanilla.setAngry(wolfNEC.isAngry());
		wolfVanilla.setAttackTarget(wolfNEC.getAttackTarget());
		wolfVanilla.setRevengeTarget(wolfNEC.getAITarget());

		// Owner stuff
		wolfVanilla.setTamed(wolfNEC.isTamed());
		if (wolfNEC.getOwnerId() != null)
        	//{wolfVanilla.setOwnerId("");}
        //else
        	{wolfVanilla.setOwnerId(wolfNEC.getOwnerId());}
		wolfVanilla.setCollarColor(wolfNEC.getCollarColor());

		// Set other properties
		wolfVanilla.setCustomNameTag(wolfNEC.getCustomNameTag());
		wolfVanilla.setSitting(wolfNEC.isSitting());
		//wolfVanilla.setTameSkin(wolfNEC.getTameSkin());

		//ocelot.setHealth(0);
		wolfNEC.setDead();
		wolfVanilla.worldObj.spawnEntityInWorld(wolfVanilla);
    }
}


code:
package astrotibs.notenoughpets.network;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;

//Added in v2.0.0
public abstract class MessageBase<REQ extends IMessage> implements IMessage, IMessageHandler<REQ, REQ>{

    @Override
    public REQ onMessage(REQ message, MessageContext ctx){
        if(ctx.side == Side.SERVER) {
            handleServerSide(message, ctx.getServerHandler().playerEntity);
        } else {
        	//SCREW IT. THE BELOW LINE WILL NOT WORK FOR WHATEVER REASON
            //handleClientSide(message, VillageNames.proxy.getClientPlayer());
        }
        return null;
    }

    /*
     * Handle a packet on the client side. Note this occurs after decoding has completed.
     * @param message
     * @param player the player reference
     */
    public abstract void handleClientSide(REQ message, EntityPlayer player);

    /*
     * Handle a packet on the server side. Note this occurs after decoding has completed.
     * @param message
     * @param player the player reference
     */
    public abstract void handleServerSide(REQ message, EntityPlayer player);
}

license: unknown


code:
package astrotibs.notenoughpets.network;

import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;

/**
 * Adapted from Villager Tweaks by sidben:
 * https://github.com/sidben/VillagerTweaks/blob/master/src/main/java/sidben/villagertweaks/network/MessageZombieVillagerProfession.java
 * @author AstroTibs
 *
 * Used to notify the client of the zombie villager profession,
 * so it can render the correct skin.
 *
 */
//Added in v2.0.0
public class MessageShoulderParrots implements IMessage
{
	// Constructors
	public MessageShoulderParrots() {}
    public MessageShoulderParrots(int entityID, int leftShoulderVariant, int leftShoulderAge, int rightShoulderVariant, int rightShoulderAge)
    {
        this.playerEntityID = entityID;

        this.leftShoulderVariant = leftShoulderVariant;
        this.leftShoulderAge = leftShoulderAge;

        this.rightShoulderVariant = rightShoulderVariant;
        this.rightShoulderAge = rightShoulderAge;
    }

    // Fields to be used by this message
    private int playerEntityID;

    private int leftShoulderAge;
    private int leftShoulderVariant;

    private int rightShoulderVariant;
    private int rightShoulderAge;

    // Getters
    public int getPlayerEntityID() {return this.playerEntityID;}

    public int getLeftShoulderVariant() {return this.leftShoulderVariant;}
    public int getLeftShoulderAge() {return this.leftShoulderAge;}

    public int getRightShoulderVariant() {return this.rightShoulderVariant;}
    public int getRightShoulderAge() {return this.rightShoulderAge;}

    // Reads the packet
    @Override
    public void fromBytes(ByteBuf buf)
    {
        this.playerEntityID = buf.readInt();

        this.leftShoulderVariant = buf.readInt();
        this.leftShoulderAge = buf.readInt();

        this.rightShoulderVariant = buf.readInt();
        this.rightShoulderAge = buf.readInt();
    }

    // Write the packet
    @Override
    public void toBytes(ByteBuf buf)
    {
        buf.writeInt(this.playerEntityID);

        buf.writeInt(this.leftShoulderVariant);
        buf.writeInt(this.leftShoulderAge);

        buf.writeInt(this.rightShoulderVariant);
        buf.writeInt(this.rightShoulderAge);
    }

    // Builds a string
    @Override
    public String toString() {

    	StringBuilder r = new StringBuilder();

        r.append("Player Entity ID = ");
        r.append(this.getPlayerEntityID());

        r.append(", Left Shoulder Variant = ");
        r.append(this.getLeftShoulderVariant());
        r.append(", Left Shoulder Age = ");
        r.append(this.getLeftShoulderAge());

        r.append(", Right Shoulder Variant = ");
        r.append(this.getRightShoulderVariant());
        r.append(", Right Shoulder Age = ");
        r.append(this.getRightShoulderAge());

        return r.toString();
    }
}


code:
package astrotibs.notenoughpets.network;

import astrotibs.notenoughpets.util.Reference;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;

//Added in v2.0.0
public class NetworkHandler {
	private static SimpleNetworkWrapper INSTANCE;

    public static void init(){
        INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel(Reference.MOD_ID);
	}

    public static void sendToServer(IMessage message){
        INSTANCE.sendToServer(message);
    }

    public static void sendTo(IMessage message, EntityPlayerMP player){
        INSTANCE.sendTo(message, player);
    }

}


code:
package astrotibs.notenoughpets.network;

import astrotibs.notenoughpets.ModNotEnoughPets;
import astrotibs.notenoughpets.capabilities.shoulderriding.IShoulderRiding;
import astrotibs.notenoughpets.network.tracker.ClientInfoTracker;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;

/**
 * Adapted from Villager Tweaks by sidben:
 * https://github.com/sidben/VillagerTweaks/blob/master/src/main/java/sidben/villagertweaks/network/NetworkHelper.java
 * @author AstroTibs
 *
 * Responsible for sending and receiving packets / messages between client and server.
 *
 */
//Added in v2.0.0
public class NetworkHelper {

	/**
	 * Used to update client to a villager's career value
	 * Server -> Client
	 */
	// Deployment
    public static void sendShoulderParrotVariantMessage(int playerEntityID, IShoulderRiding isr, EntityPlayer target) {
        if (
				playerEntityID > 0
				&& isr != null
        		)
        {
        	MessageShoulderParrots message = new MessageShoulderParrots(
            		playerEntityID,

            		isr.getLeftShoulderVariant(),
            		isr.getLeftShoulderAge(),

            		isr.getRightShoulderVariant(),
            		isr.getRightShoulderAge()
            		);

            // Sends a message to the player, with the zombie extra info
            ModNotEnoughPets.NECNetworkWrapper.sendTo(message, (EntityPlayerMP)target);
        }
    }

    // Reception
    public static class ShoulderParrotsHandler implements IMessageHandler<MessageShoulderParrots, IMessage> {

        @Override
        public IMessage onMessage(MessageShoulderParrots message, net.minecraftforge.fml.common.network.simpleimpl.MessageContext ctx) {

            if (
					message.getPlayerEntityID() > 0
					//&& (message.getLeftShoulderVariant() != 0 || message.getRightShoulderVariant() != 0)
            		) {
                // Saves the info to be used later, when the entity actually loads
                ClientInfoTracker.addShoulderParrotsMessage(message);
                ClientInfoTracker.syncShoulderParrotsMessage(message.getPlayerEntityID());
                //return message;
            }
            return null;
        }
    }

}


code:
package astrotibs.notenoughpets.network.tracker;

import java.util.HashMap;

import astrotibs.notenoughpets.capabilities.shoulderriding.IShoulderRiding;
import astrotibs.notenoughpets.capabilities.shoulderriding.ShoulderRidingProvider;
import astrotibs.notenoughpets.network.MessageShoulderParrots;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

/**
 * Adapted from Villager Tweaks by sidben:
 * https://github.com/sidben/VillagerTweaks/blob/master/src/main/java/sidben/villagertweaks/tracker/ClientInfoTracker.java
 *
 * @author AstroTibs
 *
 * Helper class to manage client-side information.
 *
 */
public class ClientInfoTracker
{

    /*
     * This map holds packets sent from Server to Client indicating which mob
     * has the extended properties, so the client can load the correct skin / overlay / particles.
     *
     * The info comes from [MetworkHelper.Hanlder] methods and must be loaded
     * when the client executes [EntityJoinWorldEvent].
     *
     * I can't use the info before that because when the client receives the packet,
     * the local world still haven't loaded all entities (at least on the first load of the world).
     *
     */

    @SideOnly(Side.CLIENT)
    private static HashMap<Integer, MessageShoulderParrots> loadedPlayers = new HashMap<Integer, MessageShoulderParrots>();

    @SideOnly(Side.CLIENT)
    public static void addShoulderParrotsMessage(MessageShoulderParrots message)
    {
        ClientInfoTracker.loadedPlayers.put(message.getPlayerEntityID(), message);
    }

    @SideOnly(Side.CLIENT)
    public static MessageShoulderParrots getShoulderParrotsMessage(int entityID)
    {
    	MessageShoulderParrots msg = ClientInfoTracker.loadedPlayers.get(entityID);
        ClientInfoTracker.loadedPlayers.remove(entityID);         // removes from the list, it's not needed anymore
        return msg;
    }

    /**
     * Attempts to locate the entity by its ID and apply the
     * extended properties.
     */
    @SideOnly(Side.CLIENT)
    public static void syncShoulderParrotsMessage(int entityID)
    {
        // Seeks if the entity ID is loaded
        WorldClient world = Minecraft.getMinecraft().theWorld;
        if (world == null) return;
        Entity entity = world.getEntityByID(entityID);

        // If found the entity, attempt to sync with info sent by the server
        if (
        		entity instanceof EntityPlayer
        		//&& ((EntityVillager)entity).getProfession() >=0
        		)
        {
            ClientInfoTracker.syncShoulderParrotsMessage((EntityPlayer)entity);
        }
    }

    /**
     * Attempts to locate a message with Extended Properties and apply to the villager.
     */
    @SideOnly(Side.CLIENT)
    public static void syncShoulderParrotsMessage(EntityPlayer player)
    {
        // Try to locate messages sent by the server, containing special villager info
    	MessageShoulderParrots msg = ClientInfoTracker.getShoulderParrotsMessage(player.getEntityId());

        // If a message was found, update the local villager with that info
        if (msg != null)
        {
        	IShoulderRiding isr = player.getCapability(ShoulderRidingProvider.SHOULDER_RIDING, null);
        	isr.setLeftShoulderVariant(msg.getLeftShoulderVariant());
        	isr.setLeftShoulderAge(msg.getLeftShoulderAge());
        	isr.setRightShoulderVariant(msg.getRightShoulderVariant());
        	isr.setRightShoulderAge(msg.getRightShoulderAge());
        }
    }

}


code:
package astrotibs.notenoughpets.pathfinding.minecraft;

import java.lang.reflect.Method;
import java.util.EnumSet;
import java.util.Set;

import javax.annotation.Nullable;

import com.google.common.collect.Sets;

import net.minecraft.block.Block;
import net.minecraft.block.BlockRailBase;
import net.minecraft.entity.EntityLiving;
import net.minecraft.init.Blocks;
import net.minecraft.pathfinding.PathNodeType;
import net.minecraft.pathfinding.PathPoint;
import net.minecraft.pathfinding.WalkNodeProcessor;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.fml.relauncher.ReflectionHelper;

//Added in v2.0.0
public class FlyingNodeProcessor extends WalkNodeProcessor
{
    public void init(IBlockAccess sourceIn, EntityLiving mob)
    {
        super.initProcessor(sourceIn, mob);

        //this.avoidsWater = mob.getPathPriority(PathNodeType.WATER);
        //ReflectionHelper.setPrivateValue(WalkNodeProcessor.class, this, mob.getPathPriority(PathNodeType.WATER), new String[]{"avoidsWater", "field_176183_h"});
    }

    /**
     * This method is called when all nodes have been processed and PathEntity is created.
     * {@link net.minecraft.world.pathfinder.WalkNodeProcessor WalkNodeProcessor} uses this to change its field {@link
     * net.minecraft.world.pathfinder.WalkNodeProcessor#avoidsWater avoidsWater}
     */
    /*
    public void postProcess()
    {
    	float avoidsWater_reflected = ReflectionHelper.getPrivateValue( WalkNodeProcessor.class, this, new String[]{"avoidsWater", "field_176183_h"} );

        this.entity.setPathPriority(PathNodeType.WATER, avoidsWater_reflected);
        super.postProcess();
    }
    */
    @Override
    public PathPoint getStart()
    {
        int i;

        if (this.getCanSwim() && this.entity.isInWater())
        {
            i = (int)this.entity.getEntityBoundingBox().minY;
            BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(MathHelper.floor_double(this.entity.posX), i, MathHelper.floor_double(this.entity.posZ));

            for (Block block = this.blockaccess.getBlockState(blockpos$mutableblockpos).getBlock(); block == Blocks.FLOWING_WATER || block == Blocks.WATER; block = this.blockaccess.getBlockState(blockpos$mutableblockpos).getBlock())
            {
                ++i;
                blockpos$mutableblockpos.setPos(MathHelper.floor_double(this.entity.posX), i, MathHelper.floor_double(this.entity.posZ));
            }
        }
        else
        {
            i = MathHelper.floor_double(this.entity.getEntityBoundingBox().minY + 0.5D);
        }

        BlockPos blockpos1 = new BlockPos(this.entity);
        PathNodeType pathnodetype1 = this.getPathNodeType(this.entity, blockpos1.getX(), i, blockpos1.getZ());

        if (this.entity.getPathPriority(pathnodetype1) < 0.0F)
        {
            Set<BlockPos> set = Sets.<BlockPos>newHashSet();
            set.add(new BlockPos(this.entity.getEntityBoundingBox().minX, (double)i, this.entity.getEntityBoundingBox().minZ));
            set.add(new BlockPos(this.entity.getEntityBoundingBox().minX, (double)i, this.entity.getEntityBoundingBox().maxZ));
            set.add(new BlockPos(this.entity.getEntityBoundingBox().maxX, (double)i, this.entity.getEntityBoundingBox().minZ));
            set.add(new BlockPos(this.entity.getEntityBoundingBox().maxX, (double)i, this.entity.getEntityBoundingBox().maxZ));

            for (BlockPos blockpos : set)
            {
                PathNodeType pathnodetype = this.getPathNodeType(this.entity, blockpos);

                if (this.entity.getPathPriority(pathnodetype) >= 0.0F)
                {
                    return super.openPoint(blockpos.getX(), blockpos.getY(), blockpos.getZ());
                }
            }
        }

        return super.openPoint(blockpos1.getX(), i, blockpos1.getZ());
    }

    /**
     * Returns PathPoint for given coordinates
     */
    @Override
    public PathPoint getPathPointToCoords(double x, double y, double z)
    {
        return super.openPoint(MathHelper.floor_double(x), MathHelper.floor_double(y), MathHelper.floor_double(z));
    }

    @Override
    public int findPathOptions(PathPoint[] pathOptions, PathPoint currentPoint, PathPoint targetPoint, float maxDistance)
    {
        int i = 0;
        PathPoint pathpoint = this.openPoint(currentPoint.xCoord, currentPoint.yCoord, currentPoint.zCoord + 1);
        PathPoint pathpoint1 = this.openPoint(currentPoint.xCoord - 1, currentPoint.yCoord, currentPoint.zCoord);
        PathPoint pathpoint2 = this.openPoint(currentPoint.xCoord + 1, currentPoint.yCoord, currentPoint.zCoord);
        PathPoint pathpoint3 = this.openPoint(currentPoint.xCoord, currentPoint.yCoord, currentPoint.zCoord - 1);
        PathPoint pathpoint4 = this.openPoint(currentPoint.xCoord, currentPoint.yCoord + 1, currentPoint.zCoord);
        PathPoint pathpoint5 = this.openPoint(currentPoint.xCoord, currentPoint.yCoord - 1, currentPoint.zCoord);

        if (pathpoint != null && !pathpoint.visited && pathpoint.distanceTo(targetPoint) < maxDistance)
        {
            pathOptions[i++] = pathpoint;
        }

        if (pathpoint1 != null && !pathpoint1.visited && pathpoint1.distanceTo(targetPoint) < maxDistance)
        {
            pathOptions[i++] = pathpoint1;
        }

        if (pathpoint2 != null && !pathpoint2.visited && pathpoint2.distanceTo(targetPoint) < maxDistance)
        {
            pathOptions[i++] = pathpoint2;
        }

        if (pathpoint3 != null && !pathpoint3.visited && pathpoint3.distanceTo(targetPoint) < maxDistance)
        {
            pathOptions[i++] = pathpoint3;
        }

        if (pathpoint4 != null && !pathpoint4.visited && pathpoint4.distanceTo(targetPoint) < maxDistance)
        {
            pathOptions[i++] = pathpoint4;
        }

        if (pathpoint5 != null && !pathpoint5.visited && pathpoint5.distanceTo(targetPoint) < maxDistance)
        {
            pathOptions[i++] = pathpoint5;
        }

        boolean flag = pathpoint3 == null || pathpoint3.costMalus != 0.0F;
        boolean flag1 = pathpoint == null || pathpoint.costMalus != 0.0F;
        boolean flag2 = pathpoint2 == null || pathpoint2.costMalus != 0.0F;
        boolean flag3 = pathpoint1 == null || pathpoint1.costMalus != 0.0F;
        boolean flag4 = pathpoint4 == null || pathpoint4.costMalus != 0.0F;
        boolean flag5 = pathpoint5 == null || pathpoint5.costMalus != 0.0F;

        if (flag && flag3)
        {
            PathPoint pathpoint6 = this.openPoint(currentPoint.xCoord - 1, currentPoint.yCoord, currentPoint.zCoord - 1);

            if (pathpoint6 != null && !pathpoint6.visited && pathpoint6.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint6;
            }
        }

        if (flag && flag2)
        {
            PathPoint pathpoint7 = this.openPoint(currentPoint.xCoord + 1, currentPoint.yCoord, currentPoint.zCoord - 1);

            if (pathpoint7 != null && !pathpoint7.visited && pathpoint7.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint7;
            }
        }

        if (flag1 && flag3)
        {
            PathPoint pathpoint8 = this.openPoint(currentPoint.xCoord - 1, currentPoint.yCoord, currentPoint.zCoord + 1);

            if (pathpoint8 != null && !pathpoint8.visited && pathpoint8.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint8;
            }
        }

        if (flag1 && flag2)
        {
            PathPoint pathpoint9 = this.openPoint(currentPoint.xCoord + 1, currentPoint.yCoord, currentPoint.zCoord + 1);

            if (pathpoint9 != null && !pathpoint9.visited && pathpoint9.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint9;
            }
        }

        if (flag && flag4)
        {
            PathPoint pathpoint10 = this.openPoint(currentPoint.xCoord, currentPoint.yCoord + 1, currentPoint.zCoord - 1);

            if (pathpoint10 != null && !pathpoint10.visited && pathpoint10.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint10;
            }
        }

        if (flag1 && flag4)
        {
            PathPoint pathpoint11 = this.openPoint(currentPoint.xCoord, currentPoint.yCoord + 1, currentPoint.zCoord + 1);

            if (pathpoint11 != null && !pathpoint11.visited && pathpoint11.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint11;
            }
        }

        if (flag2 && flag4)
        {
            PathPoint pathpoint12 = this.openPoint(currentPoint.xCoord + 1, currentPoint.yCoord + 1, currentPoint.zCoord);

            if (pathpoint12 != null && !pathpoint12.visited && pathpoint12.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint12;
            }
        }

        if (flag3 && flag4)
        {
            PathPoint pathpoint13 = this.openPoint(currentPoint.xCoord - 1, currentPoint.yCoord + 1, currentPoint.zCoord);

            if (pathpoint13 != null && !pathpoint13.visited && pathpoint13.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint13;
            }
        }

        if (flag && flag5)
        {
            PathPoint pathpoint14 = this.openPoint(currentPoint.xCoord, currentPoint.yCoord - 1, currentPoint.zCoord - 1);

            if (pathpoint14 != null && !pathpoint14.visited && pathpoint14.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint14;
            }
        }

        if (flag1 && flag5)
        {
            PathPoint pathpoint15 = this.openPoint(currentPoint.xCoord, currentPoint.yCoord - 1, currentPoint.zCoord + 1);

            if (pathpoint15 != null && !pathpoint15.visited && pathpoint15.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint15;
            }
        }

        if (flag2 && flag5)
        {
            PathPoint pathpoint16 = this.openPoint(currentPoint.xCoord + 1, currentPoint.yCoord - 1, currentPoint.zCoord);

            if (pathpoint16 != null && !pathpoint16.visited && pathpoint16.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint16;
            }
        }

        if (flag3 && flag5)
        {
            PathPoint pathpoint17 = this.openPoint(currentPoint.xCoord - 1, currentPoint.yCoord - 1, currentPoint.zCoord);

            if (pathpoint17 != null && !pathpoint17.visited && pathpoint17.distanceTo(targetPoint) < maxDistance)
            {
                pathOptions[i++] = pathpoint17;
            }
        }

        return i;
    }

    /**
     * Returns a mapped point or creates and adds one
     */
    @Nullable
    protected PathPoint openPoint(int x, int y, int z)
    {
        PathPoint pathpoint = null;
        PathNodeType pathnodetype = this.getPathNodeType(this.entity, x, y, z);
        float f = this.entity.getPathPriority(pathnodetype);

        if (f >= 0.0F)
        {
            pathpoint = super.openPoint(x, y, z);
            pathpoint.nodeType = pathnodetype;
            pathpoint.costMalus = Math.max(pathpoint.costMalus, f);

            if (pathnodetype == PathNodeType.WALKABLE)
            {
                ++pathpoint.costMalus;
            }
        }

        return pathnodetype != PathNodeType.OPEN && pathnodetype != PathNodeType.WALKABLE ? pathpoint : pathpoint;
    }

    @Override
    public PathNodeType getPathNodeType(IBlockAccess blockaccessIn, int x, int y, int z, EntityLiving entitylivingIn, int xSize, int ySize, int zSize, boolean canBreakDoorsIn, boolean canEnterDoorsIn)
    {
        EnumSet<PathNodeType> enumset = EnumSet.<PathNodeType>noneOf(PathNodeType.class);
        PathNodeType pathnodetype = PathNodeType.BLOCKED;
        BlockPos blockpos = new BlockPos(entitylivingIn);
        pathnodetype = this.getPathNodeType(blockaccessIn, x, y, z, xSize, ySize, zSize, canBreakDoorsIn, canEnterDoorsIn, enumset, pathnodetype, blockpos);

        if (enumset.contains(PathNodeType.FENCE))
        {
            return PathNodeType.FENCE;
        }
        else
        {
            PathNodeType pathnodetype1 = PathNodeType.BLOCKED;

            for (PathNodeType pathnodetype2 : enumset)
            {
                if (entitylivingIn.getPathPriority(pathnodetype2) < 0.0F)
                {
                    return pathnodetype2;
                }

                if (entitylivingIn.getPathPriority(pathnodetype2) >= entitylivingIn.getPathPriority(pathnodetype1))
                {
                    pathnodetype1 = pathnodetype2;
                }
            }

            if (pathnodetype == PathNodeType.OPEN && entitylivingIn.getPathPriority(pathnodetype1) == 0.0F)
            {
                return PathNodeType.OPEN;
            }
            else
            {
                return pathnodetype1;
            }
        }
    }

    public PathNodeType getPathNodeType(IBlockAccess blockaccessIn, int x, int y, int z)
    {
    	Method getPathNodeTypeRaw_reflected = ReflectionHelper.findMethod(
    			WalkNodeProcessor.class, this, new String[]{"getPathNodeTypeRaw", "func_189553_b"}, // MCP mapping for this method
    			IBlockAccess.class, Integer.TYPE, Integer.TYPE, Integer.TYPE); // The values the method takes in

        //PathNodeType pathnodetype = this.getPathNodeTypeRaw(blockaccessIn, x, y, z);
    	PathNodeType pathnodetype;
		try
		{
			pathnodetype = (PathNodeType)(getPathNodeTypeRaw_reflected.invoke(this, blockaccessIn, x, y, z));
		} catch (Exception e) {pathnodetype = null;}

        if (pathnodetype == PathNodeType.OPEN && y >= 1)
        {
            Block block = blockaccessIn.getBlockState(new BlockPos(x, y - 1, z)).getBlock();

            //PathNodeType pathnodetype1 = this.getPathNodeTypeRaw(blockaccessIn, x, y - 1, z);

            PathNodeType pathnodetype1;
            try
            {
            	pathnodetype1 = (PathNodeType)(getPathNodeTypeRaw_reflected.invoke(this, blockaccessIn, x, y - 1, z));
            }
            catch (Exception e) {pathnodetype1 = null;}

            if (pathnodetype1 != PathNodeType.DAMAGE_FIRE && pathnodetype1 != PathNodeType.LAVA) // Magma blocks not introduced until 1.10
            {
                if (pathnodetype1 == PathNodeType.DAMAGE_CACTUS)
                {
                    pathnodetype = PathNodeType.DAMAGE_CACTUS;
                }
                else
                {
                    pathnodetype = pathnodetype1 != PathNodeType.WALKABLE && pathnodetype1 != PathNodeType.OPEN && pathnodetype1 != PathNodeType.WATER ? PathNodeType.WALKABLE : PathNodeType.OPEN;
                }
            }
            else
            {
                pathnodetype = PathNodeType.DAMAGE_FIRE;
            }
        }

        pathnodetype = this.checkNeighborBlocks(blockaccessIn, x, y, z, pathnodetype);
        return pathnodetype;
    }

    private PathNodeType getPathNodeType(EntityLiving p_192559_1_, BlockPos p_192559_2_)
    {
        return this.getPathNodeType(p_192559_1_, p_192559_2_.getX(), p_192559_2_.getY(), p_192559_2_.getZ());
    }

    private PathNodeType getPathNodeType(EntityLiving entitylivingIn, int p_192558_2_, int p_192558_3_, int p_192558_4_)
    {
        return this.getPathNodeType(
        		this.blockaccess, p_192558_2_, p_192558_3_, p_192558_4_,
        		entitylivingIn, this.entitySizeX, this.entitySizeY, this.entitySizeZ,
        		this.getCanBreakDoors(), this.getCanEnterDoors()
        		);
    }

    /*
     * Pasted in from WalkNodeProcessor in 1.12
     */
    public PathNodeType checkNeighborBlocks(IBlockAccess blockaccess, int xOff, int y, int zOff, PathNodeType nodeType)
    {
        BlockPos.PooledMutableBlockPos blockpos$pooledmutableblockpos = BlockPos.PooledMutableBlockPos.retain();

        if (nodeType == PathNodeType.WALKABLE)
        {
            for (int i = -1; i <= 1; ++i)
            {
                for (int j = -1; j <= 1; ++j)
                {
                    if (i != 0 || j != 0)
                    {
                        Block block = blockaccess.getBlockState(blockpos$pooledmutableblockpos.setPos(i + xOff, y, j + zOff)).getBlock();

                        if (block == Blocks.CACTUS)
                        {
                            nodeType = PathNodeType.DANGER_CACTUS;
                        }
                        else if (block == Blocks.FIRE)
                        {
                            nodeType = PathNodeType.DANGER_FIRE;
                        }
                        else if(block.isBurning(blockaccess,blockpos$pooledmutableblockpos)) nodeType = PathNodeType.DAMAGE_FIRE;
                    }
                }
            }
        }

        blockpos$pooledmutableblockpos.release();
        return nodeType;
    }

    /*
     * Pasted in from WalkNodeProcessor in 1.12
     */
    public PathNodeType getPathNodeType(IBlockAccess blockaccess, int x, int y, int z,
    		int xSize, int ySize, int zSize,
    		boolean canOpenDoorsIn, boolean canEnterDoorsIn,
    		EnumSet<PathNodeType> enumNodeType, PathNodeType nodeType, BlockPos pos)
    {
        for (int i = 0; i < xSize; ++i)
        {
            for (int j = 0; j < ySize; ++j)
            {
                for (int k = 0; k < zSize; ++k)
                {
                    int l = i + x;
                    int i1 = j + y;
                    int j1 = k + z;
                    PathNodeType pathnodetype = this.getPathNodeType(blockaccess, l, i1, j1);

                    if (pathnodetype == PathNodeType.DOOR_WOOD_CLOSED && canOpenDoorsIn && canEnterDoorsIn)
                    {
                        pathnodetype = PathNodeType.WALKABLE;
                    }

                    if (pathnodetype == PathNodeType.DOOR_OPEN && !canEnterDoorsIn)
                    {
                        pathnodetype = PathNodeType.BLOCKED;
                    }

                    if (pathnodetype == PathNodeType.RAIL && !(blockaccess.getBlockState(pos).getBlock() instanceof BlockRailBase) && !(blockaccess.getBlockState(pos.down()).getBlock() instanceof BlockRailBase))
                    {
                        pathnodetype = PathNodeType.FENCE;
                    }

                    if (i == 0 && j == 0 && k == 0)
                    {
                        nodeType = pathnodetype;
                    }

                    enumNodeType.add(pathnodetype);
                }
            }
        }

        return nodeType;
    }

}


code:
package astrotibs.notenoughpets.pathfinding.minecraft;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.pathfinding.Path;
import net.minecraft.pathfinding.PathFinder;
import net.minecraft.pathfinding.PathNavigate;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.ReflectionHelper;

//Added in v2.0.0
public class PathNavigateFlying extends PathNavigate
{
    public PathNavigateFlying(EntityLiving p_i47412_1_, World p_i47412_2_)
    {
        super(p_i47412_1_, p_i47412_2_);
    }

    protected PathFinder getPathFinder()
    {
        this.nodeProcessor = new FlyingNodeProcessor();
        this.nodeProcessor.setCanEnterDoors(true);
        return new PathFinder(this.nodeProcessor);
    }

    /**
     * If on ground or swimming and can swim
     */
    protected boolean canNavigate()
    {
        return this.canFloat() && this.isInLiquid() || !this.theEntity.isRiding();
    }

    protected Vec3d getEntityPosition()
    {
        return new Vec3d(this.theEntity.posX, this.theEntity.posY, this.theEntity.posZ);
    }

    /**
     * Returns the path to the given EntityLiving. Args : entity
     */
    public Path getPathToEntityLiving(Entity entityIn)
    {
        return this.getPathToPos(new BlockPos(entityIn));
    }

    public void onUpdateNavigation()
    {

        //++this.totalTicks;
        int totalTicks_reflected = ReflectionHelper.getPrivateValue( PathNavigate.class, this, new String[]{"totalTicks", "field_75510_g"} );
    	ReflectionHelper.setPrivateValue(PathNavigate.class, this, totalTicks_reflected+1, new String[]{"totalTicks", "field_75510_g"});

        boolean tryUpdatePath_reflected = ReflectionHelper.getPrivateValue( PathNavigate.class, this, new String[]{"tryUpdatePath", "field_188562_p"} );
        if (tryUpdatePath_reflected)
        {
            this.updatePath();
        }

        if (!this.noPath())
        {
            if (this.canNavigate())
            {
                this.pathFollow();
            }
            else if (this.currentPath != null && this.currentPath.getCurrentPathIndex() < this.currentPath.getCurrentPathLength())
            {
                Vec3d vec3d = this.currentPath.getVectorFromIndex(this.theEntity, this.currentPath.getCurrentPathIndex());

                if (
                		MathHelper.floor_double(this.theEntity.posX) == MathHelper.floor_double(vec3d.xCoord)
                		&& MathHelper.floor_double(this.theEntity.posY) == MathHelper.floor_double(vec3d.yCoord)
                		&& MathHelper.floor_double(this.theEntity.posZ) == MathHelper.floor_double(vec3d.zCoord)
                		)
                {
                    this.currentPath.setCurrentPathIndex(this.currentPath.getCurrentPathIndex() + 1);
                }
            }

            // I don't think this exists in 1.12 anymore
            //this.debugPathFinding();

            if (!this.noPath())
            {
                Vec3d vec3d1 = this.currentPath.getPosition(this.theEntity);
                this.theEntity.getMoveHelper().setMoveTo(vec3d1.xCoord, vec3d1.yCoord, vec3d1.zCoord, this.speed);
            }
        }
    }

    /**
     * Checks if the specified entity can safely walk to the specified location.
     */
    protected boolean isDirectPathBetweenPoints(Vec3d posVec31, Vec3d posVec32, int sizeX, int sizeY, int sizeZ)
    {
        int i = MathHelper.floor_double(posVec31.xCoord);
        int j = MathHelper.floor_double(posVec31.yCoord);
        int k = MathHelper.floor_double(posVec31.zCoord);
        double d0 = posVec32.xCoord - posVec31.xCoord;
        double d1 = posVec32.yCoord - posVec31.yCoord;
        double d2 = posVec32.zCoord - posVec31.zCoord;
        double d3 = d0 * d0 + d1 * d1 + d2 * d2;

        if (d3 < 1.0E-8D)
        {
            return false;
        }
        else
        {
            double d4 = 1.0D / Math.sqrt(d3);
            d0 = d0 * d4;
            d1 = d1 * d4;
            d2 = d2 * d4;
            double d5 = 1.0D / Math.abs(d0);
            double d6 = 1.0D / Math.abs(d1);
            double d7 = 1.0D / Math.abs(d2);
            double d8 = (double)i - posVec31.xCoord;
            double d9 = (double)j - posVec31.yCoord;
            double d10 = (double)k - posVec31.zCoord;

            if (d0 >= 0.0D)
            {
                ++d8;
            }

            if (d1 >= 0.0D)
            {
                ++d9;
            }

            if (d2 >= 0.0D)
            {
                ++d10;
            }

            d8 = d8 / d0;
            d9 = d9 / d1;
            d10 = d10 / d2;
            int l = d0 < 0.0D ? -1 : 1;
            int i1 = d1 < 0.0D ? -1 : 1;
            int j1 = d2 < 0.0D ? -1 : 1;
            int k1 = MathHelper.floor_double(posVec32.xCoord);
            int l1 = MathHelper.floor_double(posVec32.yCoord);
            int i2 = MathHelper.floor_double(posVec32.zCoord);
            int j2 = k1 - i;
            int k2 = l1 - j;
            int l2 = i2 - k;

            while (j2 * l > 0 || k2 * i1 > 0 || l2 * j1 > 0)
            {
                if (d8 < d10 && d8 <= d9)
                {
                    d8 += d5;
                    i += l;
                    j2 = k1 - i;
                }
                else if (d9 < d8 && d9 <= d10)
                {
                    d9 += d6;
                    j += i1;
                    k2 = l1 - j;
                }
                else
                {
                    d10 += d7;
                    k += j1;
                    l2 = i2 - k;
                }
            }

            return true;
        }
    }

    //Renamed from setCanOpenDoors in 1.12
    public void setCanBreakDoors(boolean p_192879_1_)
    {
        this.nodeProcessor.setCanBreakDoors(p_192879_1_);
    }

    public void setCanEnterDoors(boolean p_192878_1_)
    {
        this.nodeProcessor.setCanEnterDoors(p_192878_1_);
    }

    public void setCanFloat(boolean p_192877_1_)
    {
        this.nodeProcessor.setCanSwim(p_192877_1_);
    }

    public boolean canFloat()
    {
        return this.nodeProcessor.getCanSwim();
    }

    public boolean canEntityStandOnPos(BlockPos pos)
    {
        return this.worldObj.getBlockState(pos).isSideSolid(this.worldObj, pos.down(), EnumFacing.UP);
    }
}


code:
package astrotibs.notenoughpets.proxy;

import astrotibs.notenoughpets.client.render.layers.LayerEntityOnShoulder;
import astrotibs.notenoughpets.spawnegg.SpawnEggInfo;
import astrotibs.notenoughpets.spawnegg.SpawnEggRegistry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.color.IItemColor;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;

public class ClientProxy extends CommonProxy {

	@Override
	public void preInit(FMLPreInitializationEvent e) {
		super.preInit(e);
	}

	@Override
	public void init(FMLInitializationEvent e) {
		super.init(e);

		// The below block is for registering spawn egg colors
		// See:
		// https://www.minecraftforge.net/forum/topic/37984-19-solved-color-from-itemstack/
		// https://gist.github.com/williewillus/e37edde85dc78d2e138c
		// https://github.com/OpenMods/OpenBlocks/blob/c90141626490293cc0f4d0f4b7f113e35aea29d5/src/main/java/openblocks/client/BlockColorHandlerRegistration.java

		FMLClientHandler.instance().getClient().getItemColors().registerItemColorHandler(new IItemColor()
        {
            public int getColorFromItemstack(ItemStack stack, int renderPass)
            {
            	SpawnEggInfo info = SpawnEggRegistry.getEggInfo((short) stack.getItemDamage());

    			if (info == null) {return renderPass==0 ? 0xdb9c3e : 0x423b32;} // Calico colors

    			int color = (renderPass == 0) ? info.primaryColor : info.secondaryColor;

    			if (stack.hasTagCompound())
    			{
    				NBTTagCompound compound = stack.getTagCompound();

    				if (renderPass == 0 && compound.hasKey("primaryColor")) {color = compound.getInteger("primaryColor");}
    				if (renderPass != 0 && compound.hasKey("secondaryColor")) {color = compound.getInteger("secondaryColor");}
    			}

    			return color;
            }
        }, new Item[] {SpawnEggRegistry.SPAWN_EGG});

		// To render a new layer onto the player
		// See https://github.com/SleepyTrousers/EnderIO/blob/release/1.11/src/main/java/crazypants/enderio/ClientProxy.java
		//MinecraftForge.EVENT_BUS.register(UpgradeRenderDispatcher.instance);
		MinecraftForge.EVENT_BUS.register(new LayerEntityOnShoulder(Minecraft.getMinecraft().getRenderManager()));
	}
}


code:
package astrotibs.notenoughpets.proxy;

import astrotibs.notenoughpets.capabilities.CapabilityAttach;
import astrotibs.notenoughpets.capabilities.shoulderriding.IShoulderRiding;
import astrotibs.notenoughpets.capabilities.shoulderriding.ShoulderRiding;
import astrotibs.notenoughpets.capabilities.shoulderriding.ShoulderRidingStorage;
import astrotibs.notenoughpets.config.GeneralConfig;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;

public class CommonProxy {

	public void preInit(FMLPreInitializationEvent e) {

    }

	public void init(FMLInitializationEvent e) {

		// Event listeners
		MinecraftForge.EVENT_BUS.register(new GeneralConfig());
		MinecraftForge.EVENT_BUS.register(new CapabilityAttach()); // Added in v2.0.0
		registerCapabilities(); // Added in v2.0.0
	}

	public void postInit(FMLPostInitializationEvent e)  {

	}

	// Added in v2.0.0
	protected void registerCapabilities()
	{
		CapabilityManager.INSTANCE.register(IShoulderRiding.class, new ShoulderRidingStorage(), ShoulderRiding.class);
	}

	public void registerRender() {
	}

}


code:
package astrotibs.notenoughpets.proxy;

import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;

public class ServerProxy extends CommonProxy {

	@Override
	public void preInit(FMLPreInitializationEvent e) {
		super.preInit(e);
	}

	@Override
	public void init(FMLInitializationEvent e) {
		super.init(e);
	}

	@Override
	public void postInit(FMLPostInitializationEvent e) {
		super.postInit(e);
	}

}


code:
package astrotibs.notenoughpets.spawnegg;

import net.minecraft.block.BlockDispenser;
import net.minecraft.dispenser.BehaviorDefaultDispenseItem;
import net.minecraft.dispenser.IBlockSource;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;

/**
 * Adapted from Better Spawn Eggs:
 * https://github.com/DavidGoldman/BetterSpawnEggs/blob/master/com/mcf/davidee/spawneggs/eggs/DispenserBehaviorSpawnEgg.java
 * @author AstroTibs
 */

public final class DispenserBehavior extends BehaviorDefaultDispenseItem {

	public ItemStack dispenseStack(IBlockSource blockSource, ItemStack stack)
	{
		EnumFacing enumfacing = BlockDispenser.getFacing(blockSource.getBlockMetadata());
		double x = blockSource.getX() + (double)enumfacing.getFrontOffsetX();
		double y = (double)((float)blockSource.getY() + 0.2F);
		double z = blockSource.getZ() + (double)enumfacing.getFrontOffsetZ();
		Entity entity = ItemSpawnEggNEP.spawnCreature(blockSource.getWorld(), stack, x, y, z);
		if (entity instanceof EntityLiving && stack.hasDisplayName())
		{
			((EntityLiving)entity).setCustomNameTag(stack.getDisplayName());
		}
		stack.splitStack(1);

		return stack;
	}
}


code:
package astrotibs.notenoughpets.spawnegg;

import java.util.List;
import java.util.Set;
import java.util.UUID;

import javax.annotation.Nullable;

import astrotibs.notenoughpets.ModNotEnoughPets;
import astrotibs.notenoughpets.name.BlackCatNames;
import astrotibs.notenoughpets.util.Reference;
import net.minecraft.block.BlockFence;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IEntityLivingData;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemMonsterPlacer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.stats.StatList;
import net.minecraft.tileentity.MobSpawnerBaseLogic;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityMobSpawner;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.text.translation.I18n;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

/**
 * Adapted from Better Spawn Eggs:
 * https://github.com/DavidGoldman/BetterSpawnEggs/blob/master/com/mcf/davidee/spawneggs/eggs/ItemSpawnEgg.java
 * @author AstroTibs
 */

public class ItemSpawnEggNEP extends Item
{

	public ItemSpawnEggNEP()
	{
		setHasSubtypes(true);
		setCreativeTab(ModNotEnoughPets.spawnEggTabNEC);
		setUnlocalizedName("spawn_egg");
	}

	@Override
	public String getItemStackDisplayName(ItemStack stack)
	{
		String name = ("" + I18n.translateToLocal("item.monsterPlacer.name")).trim();
		SpawnEggInfo info = SpawnEggRegistry.getEggInfo((short) stack.getItemDamage());

		if (info == null) {return name;}

		String mobID = info.mobID;
		String displayName = info.displayName;

		if (stack.hasTagCompound())
		{
			NBTTagCompound compound = stack.getTagCompound();
			if (compound.hasKey("mobID")) {mobID = compound.getString("mobID");}
			if (compound.hasKey("displayName")) {displayName = compound.getString("displayName");}
		}

		if (displayName == null)
		{
			name += " " + attemptToTranslate("entity." + mobID + ".name", mobID);
		}
		else
		{
			name += " " + ("" + I18n.translateToLocal("eggdisplay." + Reference.MOD_ID + "." + displayName + ".name")).trim();
		}

		return name;
	}

    /**
     * Called when a Block is right-clicked with this Item
     */
	@Override
    public EnumActionResult onItemUse(ItemStack stack, EntityPlayer playerIn, World worldIn, BlockPos pos, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ)
    {
        if (worldIn.isRemote)
        {
            return EnumActionResult.SUCCESS;
        }
        else if (!playerIn.canPlayerEdit(pos.offset(side), side, stack))
        {
            return EnumActionResult.FAIL;
        }
        else
        {
            IBlockState iblockstate = worldIn.getBlockState(pos);

            if (iblockstate.getBlock() == Blocks.MOB_SPAWNER)
            {
                TileEntity tileentity = worldIn.getTileEntity(pos);

                if (tileentity instanceof TileEntityMobSpawner)
                {
                    MobSpawnerBaseLogic mobspawnerbaselogic = ((TileEntityMobSpawner)tileentity).getSpawnerBaseLogic();
                    mobspawnerbaselogic.setEntityName(ItemMonsterPlacer.getEntityIdFromItem(stack));
                    tileentity.markDirty();
                    worldIn.notifyBlockUpdate(pos, iblockstate, iblockstate, 3);

                    if (!playerIn.capabilities.isCreativeMode)
                    {
                        --stack.stackSize;
                    }

                    return EnumActionResult.SUCCESS;
                }
            }

            pos = pos.offset(side);
            double d0 = 0.0D;

            if (side == EnumFacing.UP && iblockstate.getBlock() instanceof BlockFence) //Forge: Fix Vanilla bug comparing state instead of block
            {
                d0 = Reference.SPAWN_BLOCK_OFFSET;
            }

            Entity entity = spawnCreature(worldIn, stack, (double)pos.getX() + Reference.SPAWN_BLOCK_OFFSET, (double)pos.getY() + d0, (double)pos.getZ() + Reference.SPAWN_BLOCK_OFFSET);

            if (entity != null)
            {
                if (entity instanceof EntityLivingBase && stack.hasDisplayName())
                {
                    entity.setCustomNameTag(stack.getDisplayName());
                }

                if (!playerIn.capabilities.isCreativeMode)
                {
                    --stack.stackSize;
                }
            }

            return EnumActionResult.SUCCESS;
        }
    }

    /**
     * Applies the data in the EntityTag tag of the given ItemStack to the given Entity.
     */
    public static void applyItemEntityDataToEntity(World entityWorld, @Nullable EntityPlayer player, ItemStack stack, @Nullable Entity targetEntity)
    {
        MinecraftServer minecraftserver = entityWorld.getMinecraftServer();

        if (minecraftserver != null && targetEntity != null)
        {
            NBTTagCompound nbttagcompound = stack.getTagCompound();

            if (nbttagcompound != null && nbttagcompound.hasKey("EntityTag", 10))
            {
                if (!entityWorld.isRemote && targetEntity.ignoreItemEntityData() && (player == null || !minecraftserver.getPlayerList().canSendCommands(player.getGameProfile())))
                {
                    return;
                }

                NBTTagCompound nbttagcompound1 = targetEntity.writeToNBT(new NBTTagCompound());
                UUID uuid = targetEntity.getUniqueID();
                nbttagcompound1.merge(nbttagcompound.getCompoundTag("EntityTag"));
                targetEntity.setUniqueId(uuid);
                targetEntity.readFromNBT(nbttagcompound1);
            }
        }
    }

    @Override
    public String getUnlocalizedName()
    {
        return String.format("item.%s%s", Reference.MOD_ID.toLowerCase() + ":", getUnwrappedUnlocalizedName(super.getUnlocalizedName()));
    }

    @Override
    public String getUnlocalizedName(ItemStack itemStack)
    {
        return String.format("item.%s%s", Reference.MOD_ID.toLowerCase() + ":", getUnwrappedUnlocalizedName(super.getUnlocalizedName()));
    }

    protected String getUnwrappedUnlocalizedName(String unlocalizedName)
    {
        return unlocalizedName.substring(unlocalizedName.indexOf(".") + 1);
    }

	/**
     * Called whenever this item is equipped and the right mouse button is pressed.
     * Args: itemStack, world, entityPlayer
     */
	@Override
	public ActionResult<ItemStack> onItemRightClick(ItemStack itemStackIn, World worldIn, EntityPlayer playerIn, EnumHand hand)
	{
		if (worldIn.isRemote) {return new ActionResult(EnumActionResult.PASS, itemStackIn);}
		else
		{
			RayTraceResult raytraceresult = this.rayTrace(worldIn, playerIn, true);

			if (raytraceresult != null && raytraceresult.typeOfHit == RayTraceResult.Type.BLOCK)
			{
				BlockPos blockpos = raytraceresult.getBlockPos();

				if (!(worldIn.getBlockState(blockpos).getBlock() instanceof BlockLiquid))
				{
                    return new ActionResult(EnumActionResult.PASS, itemStackIn);
				}
				else if (worldIn.isBlockModifiable(playerIn, blockpos) && playerIn.canPlayerEdit(blockpos, raytraceresult.sideHit, itemStackIn))
                {
                    Entity entity = spawnCreature(worldIn, itemStackIn,
                    		(double)blockpos.getX() + Reference.SPAWN_BLOCK_OFFSET,
                    		(double)blockpos.getY() + Reference.SPAWN_BLOCK_OFFSET,
                    		(double)blockpos.getZ() + Reference.SPAWN_BLOCK_OFFSET);

                    if (entity == null)
                    {
                        return new ActionResult(EnumActionResult.PASS, itemStackIn);
                    }
                    else
                    {
                        if (entity instanceof EntityLivingBase && itemStackIn.hasDisplayName())
                        {
                            entity.setCustomNameTag(itemStackIn.getDisplayName());
                        }

                        applyItemEntityDataToEntity(worldIn, playerIn, itemStackIn, entity);

                        if (!playerIn.capabilities.isCreativeMode)
                        {
                            --itemStackIn.stackSize;
                        }

                        playerIn.addStat(StatList.getObjectUseStats(this));
                        return new ActionResult(EnumActionResult.SUCCESS, itemStackIn);
                    }
                }
                else
                {
                    return new ActionResult(EnumActionResult.FAIL, itemStackIn);
                }
            }
            else
            {
                return new ActionResult(EnumActionResult.PASS, itemStackIn);
            }
        }
    }

	/**
     * Spawns the creature specified by the egg's type in the location specified by the last three parameters.
     * Parameters: world, entityID, x, y, z.
     */
    @Nullable
    public static Entity spawnCreature(World world, @Nullable ItemStack stack, double x, double y, double z)
    {
    	int stackDamage = stack.getItemDamage();

    	SpawnEggInfo info = SpawnEggRegistry.getEggInfo((short) stackDamage);

		if (info == null) {return null;}

		String mobID = info.mobID;
		String displayName = info.displayName;
		NBTTagCompound spawnData = info.spawnData;

		if (stack.hasTagCompound())
		{
			NBTTagCompound compound = stack.getTagCompound();

			if (compound.hasKey("mobID"))
			{
				mobID = compound.getString("mobID");
			}
			if (compound.hasKey("displayName"))
			{
				displayName = compound.getString("displayName");
			}
			if (compound.hasKey("spawnData"))
			{
				spawnData = compound.getCompoundTag("spawnData");
			}
		}

		Entity entity = null;

		entity = EntityList.createEntityByName(Reference.MOD_ID+"."+mobID, world);

		if (entity != null && entity instanceof EntityLivingBase)
		{
			EntityLiving entityliving = (EntityLiving)entity;
			entity.setLocationAndAngles(x, y, z, MathHelper.wrapDegrees(world.rand.nextFloat() * 360.0F), 0.0F);
			entityliving.rotationYawHead = entityliving.rotationYaw;
			entityliving.renderYawOffset = entityliving.rotationYaw;
            entityliving.onInitialSpawn(world.getDifficultyForLocation(new BlockPos(entityliving)), (IEntityLivingData)null);

            if (!spawnData.hasNoTags())
			{
				addNBTData(entity, spawnData);
				// Add black cat name
				if(displayName.equals("cat.black_named"))
				{
					((EntityLiving)entity).setCustomNameTag(BlackCatNames.newRandomName(world.rand));
					((EntityLiving)entity).enablePersistence();
				}
			}

			world.spawnEntityInWorld(entity);
			entityliving.playLivingSound();
		}

		return entity;

    }

    @SuppressWarnings("unchecked")
	private static void addNBTData(Entity entity, NBTTagCompound spawnData)
	{
		NBTTagCompound newTag = new NBTTagCompound();
		entity.writeToNBTOptional(newTag);

		for (String name : (Set<String>) spawnData.getKeySet())
		{
			newTag.setTag(name, spawnData.getTag(name).copy());
		}

		entity.readFromNBT(newTag);
	}

    /**
     * returns a list of items with the same ID, but different meta (eg: dye returns 16 items)
     */
    @Override
    @SuppressWarnings({ "unchecked", "rawtypes" })
    @SideOnly(Side.CLIENT)
	public void getSubItems(Item par1, CreativeTabs par2CreativeTabs, List<ItemStack> list)
	{
		for (SpawnEggInfo info : SpawnEggRegistry.getEggInfoList())
		{
			list.add(new ItemStack(par1, 1, info.eggID));
		}
	}

    @SideOnly(Side.CLIENT)
	public static String attemptToTranslate(String key, String _default)
	{
		String result = I18n.translateToLocal(key);
		return (result.equals(key)) ? _default : result;
	}
}


code:
package astrotibs.notenoughpets.spawnegg;

import net.minecraft.nbt.NBTTagCompound;

/**
 * Adapted from Better Spawn Eggs:
 * https://github.com/DavidGoldman/BetterSpawnEggs/blob/master/com/mcf/davidee/spawneggs/eggs/SpawnEggInfo.java
 * @author AstroTibs
 */

public class SpawnEggInfo
{

	public final short eggID;
	public final String mobID;
	public final String displayName;
	public final NBTTagCompound spawnData;
	public final int primaryColor;
	public final int secondaryColor;

	public SpawnEggInfo(short eggID, String mobID, String displayName, NBTTagCompound spawnData, int primaryColor, int secondaryColor)
	{
		this.eggID = eggID;
		this.mobID =  mobID;
		this.displayName = displayName;
		this.spawnData = spawnData;
		this.primaryColor = primaryColor;
		this.secondaryColor = secondaryColor;
	}

	public SpawnEggInfo(short eggID, String mobID, NBTTagCompound compound, int primaryColor, int secondaryColor)
	{
		this(eggID, mobID, null, compound, primaryColor, secondaryColor);
	}

}