package jas.spawner.refactor.spawning; import jas.common.JASLog; import jas.common.global.BiomeBlacklist; import jas.spawner.modern.spawner.CountInfo; import jas.spawner.modern.spawner.Tags; import jas.spawner.modern.spawner.CountInfo.ChunkStat; import jas.spawner.modern.spawner.biome.group.BiomeHelper; import jas.spawner.refactor.BiomeSpawnLists; import jas.spawner.refactor.LivingTypeBuilder.LivingType; import jas.spawner.refactor.SpawnSettings.BiomeSettings; import jas.spawner.refactor.SpawnSettings.LivingSettings; import jas.spawner.refactor.SpawnerHelper.Counter; import jas.spawner.refactor.SpawnerHelper.SpawnerLogic; import jas.spawner.refactor.SpawnerHelper.Counter.SpawnCounter; import jas.spawner.refactor.biome.list.SpawnListEntryBuilder.SpawnListEntry; import jas.spawner.refactor.entities.LivingHandlerBuilder.LivingHandler; import jas.spawner.refactor.mvel.MVELExpression; import jas.spawner.refactor.structure.StructureHandlers; import jas.spawner.refactor.structure.StructureHandlerBuilder.StructureHandler; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; 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.chunk.Chunk; import net.minecraftforge.event.ForgeEventFactory; import com.google.common.base.Optional; import cpw.mods.fml.common.eventhandler.Event.Result; public class WorldSpawningLogic implements SpawnerLogic { @Override public Counter counter(World world) { return new SpawnCounter(); } @Override public void spawnCycle(World worldServer, CountInfo countInfo, LivingType creatureType) { } public static void spawnCycle(World world, CountInfo countInfo, LivingType livingType, BiomeBlacklist blacklist, BiomeSettings biomeSettings, LivingSettings livingSettings, BiomeSpawnLists biomesSpawns, StructureHandlers structureSpawns) { ChunkCoordinates serverOriginPoint = world.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 < livingType.iterationsPerChunk; ++numLocAttempts) { IEntityLivingData entitylivingdata = null; ChunkPosition startSpawningPoint = getRandomSpawningPointInChunk(world, chunkCoord.chunkXPos, chunkCoord.chunkZPos); SpawnListEntry spawnlistentry = null; Class<? extends EntityLiving> livingToSpawn = null; LivingHandler handler = null; countInfo.resetEntitiesPackCount(); if (livingType.quickCheck.isPresent()) { Tags tags = new Tags(world, countInfo, startSpawningPoint.chunkPosX, startSpawningPoint.chunkPosY, startSpawningPoint.chunkPosZ); Optional<Boolean> quickCheckCanSpawn = MVELExpression.execute(livingType.quickCheck, tags, "Error processing spawnExpression compiled expression for " + livingType.livingTypeID + ": " + livingType.quickCheck.expression); if (quickCheckCanSpawn.isPresent() && !quickCheckCanSpawn.get()) { continue; } } for (int numEntAttempts = 0; numEntAttempts < livingType.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 + world.rand.nextInt(horVar) - world.rand.nextInt(horVar), startSpawningPoint.chunkPosY + world.rand.nextInt(verVar) - world.rand.nextInt(verVar), startSpawningPoint.chunkPosZ + world.rand.nextInt(horVar) - world.rand.nextInt(horVar)); // Biome BlackList if (blacklist.isBlacklisted(world.getBiomeGenForCoords(spawningPoint.chunkPosX, spawningPoint.chunkPosY))) { break; } if (isNearPlayerOrOrigin(world, serverOriginPoint, spawningPoint.chunkPosX, spawningPoint.chunkPosY, spawningPoint.chunkPosZ)) { 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 = getRandomSpawnListEntryToSpawn(world, structureSpawns, biomesSpawns, biomeSettings, livingType, spawningPoint.chunkPosX, spawningPoint.chunkPosY, spawningPoint.chunkPosZ); if (spawnlistentry == null) { break; } int randomElement = spawnlistentry.entityMappings.size(); String livingMappingToSpawn_JASName = spawnlistentry.entityMappings.get(randomElement); String livingMappingToSpawn_FMLName = livingSettings.livingMappings().mappingToKey() .get(livingMappingToSpawn_JASName); livingToSpawn = (Class<? extends EntityLiving>) EntityList.stringToClassMapping .get(livingMappingToSpawn_FMLName); } /* 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[] { world }); } catch (Exception exception) { exception.printStackTrace(); return; } entityliving.setLocationAndAngles(spawnX, spawnY, spawnZ, world.rand.nextFloat() * 360.0F, 0.0F); if (canSpawn(entityliving, spawnlistentry, countInfo, livingType, spawningPoint.chunkPosX, spawningPoint.chunkPosY, spawningPoint.chunkPosZ)) { world.spawnEntityInWorld(entityliving); if (!ForgeEventFactory.doSpecialSpawn(entityliving, world, spawnX, spawnY, spawnZ)) { entitylivingdata = entityliving.onSpawnWithEgg(entitylivingdata); } JASLog.log().logSpawn( false, (String) EntityList.classToStringMapping.get(entityliving.getClass()), livingType.livingTypeID, (int) entityliving.posX, (int) entityliving.posY, (int) entityliving.posZ, BiomeHelper.getPackageName(entityliving.worldObj.getBiomeGenForCoords( (int) entityliving.posX, (int) entityliving.posZ))); Tags tags = new Tags(entityliving.worldObj, countInfo, spawningPoint.chunkPosX, spawningPoint.chunkPosY, spawningPoint.chunkPosZ, entityliving); if (spawnlistentry.postSpawn.isPresent()) { MVELExpression.execute(spawnlistentry.postSpawn.get(), tags, "Error processing compiled handler postSpawn expression for " + livingType.livingTypeID + ": " + spawnlistentry.postSpawn.get().expression); } countInfo.countSpawn(entityliving, livingType.livingTypeID); // Living PackSize Optional<Integer> packSize = MVELExpression.execute(spawnlistentry.passivePackSize, tags, "Error processing compiled handler postSpawn expression for " + livingType.livingTypeID + ": " + spawnlistentry.postSpawn.get().expression); if (!packSize.isPresent() || countInfo.getEntitiesSpawnedThisLoop() >= packSize.get()) { continue labelChunkStart; } } } } } } private static ChunkPosition getRandomSpawningPointInChunk(World world, int chunkX, int chunkZ) { Chunk chunk = world.getChunkFromChunkCoords(chunkX, chunkZ); int xCoord = chunkX * 16 + world.rand.nextInt(16); int zCoord = chunkZ * 16 + world.rand.nextInt(16); int yCoord = world.rand.nextInt(chunk == null ? world.getActualHeight() : chunk.getTopFilledSegment() + 16 - 1); return new ChunkPosition(xCoord, yCoord, zCoord); } 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; } private static SpawnListEntry getRandomSpawnListEntryToSpawn(World world, StructureHandlers structures, BiomeSpawnLists spawnLists, BiomeSettings biomeSettings, LivingType livingType, int xCoord, int yCoord, int zCoord) { Collection<SpawnListEntry> spawnList = getSpawnList(world, structures, spawnLists, biomeSettings, livingType, xCoord, yCoord, zCoord); int totalWeight = 0; for (SpawnListEntry entry : spawnList) { totalWeight += entry.weight; } if (totalWeight <= 0) { return null; } else { int selectedWeight = world.rand.nextInt(totalWeight) + 1; SpawnListEntry resultEntry = null; for (SpawnListEntry spawnListEntry : spawnList) { resultEntry = spawnListEntry; selectedWeight -= spawnListEntry.weight; if (selectedWeight <= 0) { return resultEntry; } } return resultEntry; } } private static Collection<SpawnListEntry> getSpawnList(World world, StructureHandlers structures, BiomeSpawnLists spawnLists, BiomeSettings biomeSettings, LivingType livingType, int xCoord, int yCoord, int zCoord) { for (StructureHandler handler : structures.handlers()) { Collection<SpawnListEntry> spawnList = handler.getStructureSpawnList(world, xCoord, yCoord, zCoord); if (!spawnList.isEmpty()) { return spawnList; } } return spawnLists.getSpawnList(world, biomeSettings, world.getBiomeGenForCoords(xCoord, zCoord), livingType); } private static boolean canSpawn(EntityLiving entity, SpawnListEntry sle, CountInfo countInfo, LivingType livingType, int xCoord, int yCoord, int zCoord) { Tags tags = new Tags(entity.worldObj, countInfo, xCoord, yCoord, zCoord, entity); Optional<Boolean> canSpawnType = MVELExpression.execute(livingType.canSpawn, tags, "Error processing spawnExpression compiled expression for " + livingType.livingTypeID + ": " + livingType.quickCheck.expression); if (canSpawnType.isPresent() && canSpawnType.get()) { Result canSpawn = ForgeEventFactory.canEntitySpawn(entity, entity.worldObj, (int) entity.posX, (int) entity.posY, (int) entity.posZ); Optional<Boolean> canSpawnSLE = Optional.absent(); if (sle.canSpawn.isPresent()) { canSpawnSLE = MVELExpression.execute(sle.canSpawn.get(), tags, "Error processing spawnExpression compiled expression for " + livingType.livingTypeID + ": " + livingType.quickCheck.expression); } if (!canSpawnSLE.isPresent()) { return canSpawn != Result.DENY; } else { return canSpawnSLE.get(); } } else { return false; } } }