package game.world; import java.util.Set; import com.google.common.collect.Sets; import game.biome.Biome; import game.block.Block; import game.entity.npc.EntityNPC; import game.entity.types.EntityLiving; import game.entity.types.EntityWaterMob; import game.init.Blocks; import game.init.Config; import game.rng.Random; import game.rng.WeightedList; import game.util.ExtMath; public abstract class Spawner { private static final int MOB_COUNT_DIV = (int)Math.pow(17.0D, 2.0D); private static final Set CHUNKS = Sets.newHashSet(); public static boolean canSpawnAt(boolean water, WorldServer world, BlockPos pos) { if(!World.isValidXZ(pos)) { return false; } Block block = world.getState(pos).getBlock(); if(water) { return block.getMaterial().isLiquid() && world.getState(pos.down()).getBlock().getMaterial().isLiquid() && !world.getState(pos.up()).getBlock().isNormalCube(); } // else if(place == SpawnRegistry.Placement.IN_AIR) { // return pos.getY() >= 118; // } else { BlockPos down = pos.down(); if(!world.isBlockSolid(down)) { return false; } else { Block below = world.getState(down).getBlock(); return below != Blocks.bedrock && !block.isNormalCube() && !block.getMaterial().isLiquid() && !world.getState(pos.up()).getBlock().isNormalCube(); } } } public static int spawn(WorldServer world) { // if(!hostile && !peaceful) { // return 0; // } CHUNKS.clear(); int locs = 0; int range = Math.max(Config.mobSpawnDist, 1); for(EntityNPC player : world.players) { // if(Config.spectatorSpawning || !player.isSpectator()) { int x = ExtMath.floord(player.posX / 16.0D); int z = ExtMath.floord(player.posZ / 16.0D); for(int cx = -range; cx <= range; ++cx) { for(int cz = -range; cz <= range; ++cz) { boolean flag = cx == -range || cx == range || cz == -range || cz == range; ChunkPos coord = new ChunkPos(cx + x, cz + z); if(!CHUNKS.contains(coord)) { ++locs; if(!flag && coord.x << 4 >= -World.MAX_SIZE + 64 && coord.z << 4 >= -World.MAX_SIZE + 64 && coord.x << 4 < World.MAX_SIZE - 64 && coord.z << 4 < World.MAX_SIZE - 64) { CHUNKS.add(coord); } } } } // } } // boolean animals = (time % Math.max(Config.animalSpawnDelay, 1)) == 0; int spawned = 0; int mobSpread = Math.max(Config.spawnGroupDist, 1); // double spawnDist = (double)Config.mobSpawnDistance; double playerDist = (double)Config.mobPlayerDist; // BlockPos spawn = world.isPrimary() ? Server.getSpawnPoint() : null; // for(EnumCreatureType type : EnumCreatureType.values()) { // if((!type.isPeaceful() || peaceful) && (type.isPeaceful() || hostile) && (!type.isAnimal() || animals)) { int cur = world.countEntities(EntityLiving.class); int max = Config.maxMobs * locs / MOB_COUNT_DIV; if(cur <= max) { typeLabel: for(ChunkPos coord : CHUNKS) { Chunk chunk = world.getChunk(coord.x, coord.z); int x = coord.x * 16 + world.rand.zrange(16); int z = coord.z * 16 + world.rand.zrange(16); int h = chunk.getHeight(new BlockPos(x, 0, z)) + 1; if(h > 0) { int m = h % 16; h = m == 0 ? h : h + 16 - m; } h = h == 0 ? 16 : (h > 0 ? h : chunk.getTopSegment() + 16 - 1); int y = world.rand.excl(h <= 8 ? 0 : 8, h); BlockPos pos = new BlockPos(x, y, z); Block block = world.getState(pos).getBlock(); if(!block.isNormalCube()) { int group = 0; Object data = null; for(int n = 0; n < Config.spawnGroups; ++n) { int mx = x; int my = y; int mz = z; Biome.RngSpawn entry = null; int cmax = 4; for(int m = 0; m < cmax; ++m) { mx += world.rand.zrange(mobSpread) - world.rand.zrange(mobSpread); my += world.rand.zrange(1) - world.rand.zrange(1); mz += world.rand.zrange(mobSpread) - world.rand.zrange(mobSpread); BlockPos mpos = new BlockPos(mx, my, mz); float fx = (float)mx + 0.5F; float fz = (float)mz + 0.5F; if(!world.isAnyPlayerWithinRangeAt((double)fx, (double)my, (double)fz, playerDist)) { // && (spawn == null || spawn.distanceSq((double)fx, (double)my, (double)fz) >= spawnDist)) { if(entry == null) { entry = world.getSpawnListEntryForTypeAt(mpos); if(entry == null) { break; } cmax = m + entry.minGroupCount + world.rand.zrange(1 + entry.maxGroupCount - entry.minGroupCount); } if(world.canCreatureTypeSpawnHere(entry, mpos) && canSpawnAt(EntityWaterMob.class.isAssignableFrom(entry.entityClass), world, mpos)) { EntityLiving entity; try { entity = entry.entityClass.getConstructor(World.class).newInstance(world); } catch(Exception e) { e.printStackTrace(); return spawned + group; } entity.setLocationAndAngles((double)fx, (double)my, (double)fz, world.rand.floatv() * 360.0F, 0.0F); if(entity.getCanSpawnHere() && entity.isNotColliding()) { data = entity.onInitialSpawn(data); if(entity.isNotColliding()) { ++group; world.spawnEntityInWorld(entity); } if(group >= entity.getMaxChunkSpawns()) { spawned += group; continue typeLabel; } else if(!entity.isPropogatingSpawnData(m >= cmax - 1)) { data = null; } } } } } } spawned += group; } } // } // } } return spawned; } public static void generate(WorldServer world, Biome biome, int x, int z, int sx, int sz, Random rand) { int iters = 0; while(rand.floatv() < biome.getSpawningChance()) { if(iters++ == 10) break; WeightedList list = biome.getSpawnableList(); if(list.isEmpty()) { continue; } Biome.RngSpawn entry = list.pick(world.rand); int count = entry.minGroupCount + rand.zrange(1 + entry.maxGroupCount - entry.minGroupCount); Object data = null; int mx = x + rand.zrange(sx); int mz = z + rand.zrange(sz); int gx = mx; int gz = mz; for(int n = 0; n < count; ++n) { boolean flag = false; for(int m = 0; !flag && m < 4; ++m) { BlockPos pos = world.getTopSolidOrLiquidBlock(new BlockPos(mx, 0, mz)); if(canSpawnAt(EntityWaterMob.class.isAssignableFrom(entry.entityClass), world, pos)) { EntityLiving entity; try { entity = entry.entityClass.getConstructor(World.class).newInstance(world); } catch(Exception e) { e.printStackTrace(); continue; } entity.setLocationAndAngles((double)((float)mx + 0.5F), (double)pos.getY(), (double)((float)mz + 0.5F), rand.floatv() * 360.0F, 0.0F); if(entity.getCanSpawnHere() && entity.isNotColliding()) { data = entity.onInitialSpawn(data); if(entity.isNotColliding()) world.spawnEntityInWorld(entity); if(!entity.isPropogatingSpawnData(false)) data = null; flag = true; } } mx += rand.zrange(5) - rand.zrange(5); for(mz += rand.zrange(5) - rand.zrange(5); mx < x || mx >= x + sx || mz < z || mz >= z + sx; mz = gz + rand.zrange(5) - rand.zrange(5)) { mx = gx + rand.zrange(5) - rand.zrange(5); } } } } } }