package jas.spawner.modern.spawner; import jas.common.JASLog; import jas.common.global.BiomeBlacklist; import jas.spawner.modern.MVELProfile; import jas.spawner.modern.spawner.CountInfo.ChunkStat; import jas.spawner.modern.spawner.Counter.SpawnCounter; import jas.spawner.modern.spawner.biome.group.BiomeHelper; import jas.spawner.modern.spawner.creature.entry.BiomeSpawnListRegistry; import jas.spawner.modern.spawner.creature.entry.SpawnListEntry; import jas.spawner.modern.spawner.creature.handler.LivingHandler; import jas.spawner.modern.spawner.creature.handler.LivingHandlerRegistry; import jas.spawner.modern.spawner.creature.type.CreatureType; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.IEntityLivingData; import net.minecraft.util.ChunkCoordinates; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.ChunkPosition; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.event.ForgeEventFactory; import org.apache.logging.log4j.Level; import cpw.mods.fml.common.eventhandler.Event.Result; public class CustomSpawner { public static SpawnCounter spawnCounter = new SpawnCounter(); /** * Performs Actual Creature Spawning inside eligibleChunks. {@link determineChunksForSpawnering} needs to be run to * populate eligibleChunksForSpawning with spawnable chunks * * @param creatureType * CreatureType spawnList that is being Spawned */ public static final void spawnCreaturesInChunks(WorldServer worldServer, LivingHandlerRegistry livingHandlerRegistry, BiomeSpawnListRegistry biomeSpawnListRegistry, CreatureType creatureType, BiomeBlacklist blacklist, CountInfo countInfo) { final int entityTypeCap = creatureType.maxNumberOfCreature * countInfo.eligibleChunkLocations().size() / 256; int globalEntityTypeCount = countInfo.getGlobalEntityTypeCount(creatureType.typeID); if (globalEntityTypeCount > entityTypeCap) { return; } ChunkCoordinates serverOriginPoint = worldServer.getSpawnPoint(); List<ChunkCoordIntPair> eligibleChunksForSpawning = new ArrayList<ChunkCoordIntPair>( countInfo.eligibleChunkLocations()); Collections.shuffle(eligibleChunksForSpawning); labelChunkStart: for (ChunkCoordIntPair chunkCoord : eligibleChunksForSpawning) { ChunkStat chunkStat = countInfo.getChunkStat(chunkCoord); if (chunkStat.isEdge) { continue; } countInfo.resetEntitiesSpawnedThisLoop(); for (int numLocAttempts = 0; numLocAttempts < creatureType.iterationsPerChunk; ++numLocAttempts) { IEntityLivingData entitylivingdata = null; ChunkPosition startSpawningPoint = creatureType.getRandomSpawningPointInChunk(worldServer, chunkCoord.chunkXPos, chunkCoord.chunkZPos); SpawnListEntry spawnlistentry = null; Class<? extends EntityLiving> livingToSpawn = null; LivingHandler handler = null; countInfo.resetEntitiesPackCount(); if (!creatureType.canSpawnHere(worldServer, countInfo, startSpawningPoint)) { continue; } for (int numEntAttempts = 0; numEntAttempts < creatureType.iterationsPerPack; ++numEntAttempts) { // Randomized on Each Attempt, but horizontally to allow a 'Pack' to spawn near each other final int horVar = 10; final int verVar = 3; ChunkPosition spawningPoint = new ChunkPosition( startSpawningPoint.chunkPosX + worldServer.rand.nextInt(horVar) - worldServer.rand.nextInt(horVar), startSpawningPoint.chunkPosY + worldServer.rand.nextInt(verVar) - worldServer.rand.nextInt(verVar), startSpawningPoint.chunkPosZ + worldServer.rand.nextInt(horVar) - worldServer.rand.nextInt(horVar)); // Biome BlackList if (blacklist.isBlacklisted(worldServer.getBiomeGenForCoords(spawningPoint.chunkPosX, spawningPoint.chunkPosY))) { break; } if (isNearPlayerOrOrigin(worldServer, serverOriginPoint, spawningPoint.chunkPosX, spawningPoint.chunkPosY, spawningPoint.chunkPosZ)) { continue; } if (!creatureType.canSpawnHere(worldServer, countInfo, spawningPoint)) { continue; } // Set SpawnList Specific attributes, set only for outer loop (when SpawnListEntry == null), is done // in inner loop after creatureType.canSpawnHere for performance reasons // (regsitry.getSpawnListEntryToSpawn is not cheap) if (spawnlistentry == null) { spawnlistentry = biomeSpawnListRegistry.getSpawnListEntryToSpawn(worldServer, creatureType, spawningPoint.chunkPosX, spawningPoint.chunkPosY, spawningPoint.chunkPosZ); if (spawnlistentry == null) { break; } Tags tags = new Tags(worldServer, countInfo, spawningPoint.chunkPosX, spawningPoint.chunkPosY, spawningPoint.chunkPosZ); livingToSpawn = livingHandlerRegistry.getRandomEntity(spawnlistentry.livingGroupID, worldServer.rand, tags); if (livingToSpawn == null) { break; } handler = livingHandlerRegistry.getLivingHandler(spawnlistentry.livingGroupID); } // LivingCap { int globalEntityClassCount = countInfo.getGlobalEntityClassCount(livingToSpawn); int livingCap = handler.getLivingCap(); if (livingCap > 0 && globalEntityClassCount >= livingCap) { spawnlistentry = null; break; } } /* Spawn is Centered Version of blockSpawn such that entity is not placed in Corner */ float spawnX = spawningPoint.chunkPosX + 0.5F; float spawnY = spawningPoint.chunkPosY; float spawnZ = spawningPoint.chunkPosZ + 0.5F; EntityLiving entityliving; try { entityliving = livingToSpawn.getConstructor(new Class[] { World.class }).newInstance( new Object[] { worldServer }); } catch (Exception exception) { exception.printStackTrace(); return; } entityliving.setLocationAndAngles(spawnX, spawnY, spawnZ, worldServer.rand.nextFloat() * 360.0F, 0.0F); if (spawnlistentry.getLivingHandler().getCanSpawnHere(entityliving, spawnlistentry, countInfo)) { worldServer.spawnEntityInWorld(entityliving); if (!ForgeEventFactory.doSpecialSpawn(entityliving, worldServer, spawnX, spawnY, spawnZ)) { entitylivingdata = entityliving.onSpawnWithEgg(entitylivingdata); } if(JASLog.log().isLogNearbyBlocksEnabled()) { int[] horRange = {0, 1, -1}; // Order determines log order int[] verRange = {0, 1, -1}; // Order determines log order int totalBlocksCounted = (horRange.length*2+1) * (verRange.length*2+1); ArrayList<Integer> nearbyX = new ArrayList<Integer>(totalBlocksCounted); ArrayList<Integer> nearbyY = new ArrayList<Integer>(totalBlocksCounted); ArrayList<Integer> nearbyZ = new ArrayList<Integer>(totalBlocksCounted); ArrayList<String> nearbyNames = new ArrayList<String>(totalBlocksCounted); for (Integer x : horRange) { for (Integer z : horRange) { for (Integer y : verRange) { nearbyNames.add(entityliving.worldObj .getBlock((int) spawnX + x, (int) spawnY + y, (int) spawnZ + z) .getLocalizedName()); nearbyX.add(x); nearbyY.add(y); nearbyZ.add(z); } } } JASLog.log().logSpawn( false, (String) EntityList.classToStringMapping.get(entityliving.getClass()), spawnlistentry.getLivingHandler().creatureTypeID, (int) entityliving.posX, (int) entityliving.posY, (int) entityliving.posZ, BiomeHelper.getPackageName(entityliving.worldObj.getBiomeGenForCoords( (int) entityliving.posX, (int) entityliving.posZ)), nearbyX, nearbyY, nearbyZ, nearbyNames); } else { JASLog.log().logSpawn( false, (String) EntityList.classToStringMapping.get(entityliving.getClass()), spawnlistentry.getLivingHandler().creatureTypeID, (int) entityliving.posX, (int) entityliving.posY, (int) entityliving.posZ, BiomeHelper.getPackageName(entityliving.worldObj.getBiomeGenForCoords( (int) entityliving.posX, (int) entityliving.posZ))); } spawnlistentry.getLivingHandler().postSpawnEntity(entityliving, spawnlistentry, countInfo); countInfo.countSpawn(entityliving, creatureType.typeID); // Living PackSize if (countInfo.getEntitiesSpawnedThisLoop() >= spawnlistentry.packSize) { continue labelChunkStart; } } } } } } private static boolean isNearPlayerOrOrigin(World world, ChunkCoordinates serverSpawnPoint, int originX, int originY, int originZ) { if (world.getClosestPlayer(originX, originY, originZ, 24.0D) == null) { float xOffset = originX - serverSpawnPoint.posX; float yOffset = originY - serverSpawnPoint.posY; float zOffset = originZ - serverSpawnPoint.posZ; float sqOffset = xOffset * xOffset + yOffset * yOffset + zOffset * zOffset; if (sqOffset < 576.0F) { return true; } return false; } return true; } /** * Called during chunk generation to spawn initial creatures. */ public static void performWorldGenSpawning(World world, CreatureType creatureType, LivingHandlerRegistry livingHandlerRegistry, BiomeGenBase biome, int par2, int par3, int par4, int par5, Random random) { if (random.nextFloat() < creatureType.chunkSpawnChance) { int j1 = par2 + random.nextInt(par4); int k1 = par3 + random.nextInt(par5); int l1 = j1; int i2 = k1; int topHeight = world.getTopSolidOrLiquidBlock(j1, k1); BiomeSpawnListRegistry biomeSpawnListRegistry = MVELProfile.worldSettings().biomeSpawnListRegistry(); SpawnListEntry spawnListEntry = biomeSpawnListRegistry.getSpawnListEntryToSpawn(world, creatureType, j1, topHeight, k1); IEntityLivingData entitylivingdata = null; if (spawnListEntry == null) { JASLog.log().debug(Level.INFO, "Entity not Spawned due to Empty %s List", creatureType.typeID); return; } else { JASLog.log().debug(Level.INFO, "Evaluating if We Should spawn entity group %s", spawnListEntry.livingGroupID); } int i1 = spawnListEntry.minChunkPack + random.nextInt(1 + spawnListEntry.maxChunkPack - spawnListEntry.minChunkPack); CountInfo countInfo = CustomSpawner.spawnCounter.countEntities(world); for (int j2 = 0; j2 < i1; ++j2) { boolean flag = false; Tags tags = new Tags(world, countInfo, j1, topHeight, k1); Class<? extends EntityLiving> livingToSpawn = livingHandlerRegistry.getRandomEntity( spawnListEntry.livingGroupID, world.rand, tags); if (livingToSpawn == null) { JASLog.log().severe("No EntityClasses appear to exist in %s", spawnListEntry.toString()); continue; } for (int k2 = 0; !flag && k2 < 4; ++k2) { int l2 = world.getTopSolidOrLiquidBlock(j1, k1); if (creatureType.canSpawnAtLocation(world, new Tags(world, countInfo, j1, l2, k1), j1, l2, k1)) { float f = j1 + 0.5F; float f1 = l2; float f2 = k1 + 0.5F; EntityLiving entityliving; try { entityliving = livingToSpawn.getConstructor(new Class[] { World.class }).newInstance( new Object[] { world }); } catch (Exception exception) { exception.printStackTrace(); continue; } entityliving.setLocationAndAngles(f, f1, f2, random.nextFloat() * 360.0F, 0.0F); if (spawnListEntry.getLivingHandler().getCanSpawnHere(entityliving, spawnListEntry, countInfo)) { JASLog.log().logSpawn( true, (String) EntityList.classToStringMapping.get(entityliving.getClass()), spawnListEntry.getLivingHandler().creatureTypeID, (int) entityliving.posX, (int) entityliving.posY, (int) entityliving.posZ, BiomeHelper.getPackageName(entityliving.worldObj.getBiomeGenForCoords( (int) entityliving.posX, (int) entityliving.posZ))); world.spawnEntityInWorld(entityliving); if (!ForgeEventFactory.doSpecialSpawn(entityliving, world, f, f1, f2)) { entitylivingdata = entityliving.onSpawnWithEgg(entitylivingdata); } spawnListEntry.getLivingHandler().postSpawnEntity(entityliving, spawnListEntry, countInfo); countInfo.countSpawn(entityliving, creatureType.typeID); flag = true; } } else { JASLog.log().debug(Level.INFO, "Entity not Spawned due to invalid creatureType location. Creature Type was %s", creatureType.typeID); } j1 += random.nextInt(5) - random.nextInt(5); for (k1 += random.nextInt(5) - random.nextInt(5); j1 < par2 || j1 >= par2 + par4 || k1 < par3 || k1 >= par3 + par4; k1 = i2 + random.nextInt(5) - random.nextInt(5)) { j1 = l1 + random.nextInt(5) - random.nextInt(5); } } } } } }