210 lines
7.1 KiB
Java
Executable file
210 lines
7.1 KiB
Java
Executable file
package server.world;
|
|
|
|
import java.util.Set;
|
|
|
|
import common.block.Block;
|
|
import common.collect.Sets;
|
|
import common.entity.npc.EntityNPC;
|
|
import common.entity.types.EntityLiving;
|
|
import common.entity.types.EntityWaterMob;
|
|
import common.init.Blocks;
|
|
import common.rng.Random;
|
|
import common.rng.WeightedList;
|
|
import common.util.BlockPos;
|
|
import common.util.ChunkPos;
|
|
import common.util.ExtMath;
|
|
import common.world.World;
|
|
import server.biome.GenBiome;
|
|
import server.biome.RngSpawn;
|
|
import server.util.ServerConfig;
|
|
|
|
public abstract class Spawner {
|
|
private static final int MOB_COUNT_DIV = (int)Math.pow(17.0D, 2.0D);
|
|
private static final Set<ChunkPos> CHUNKS = Sets.<ChunkPos>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(ServerConfig.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(ServerConfig.spawnGroupDist, 1);
|
|
// double spawnDist = (double)Config.mobSpawnDistance;
|
|
double playerDist = (double)ServerConfig.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 = ServerConfig.maxMobs * locs / MOB_COUNT_DIV;
|
|
if(cur <= max) {
|
|
typeLabel:
|
|
for(ChunkPos coord : CHUNKS) {
|
|
ChunkServer 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.getTopSegment();
|
|
if(h == Integer.MIN_VALUE)
|
|
continue;
|
|
int y = world.rand.range(chunk.getBottomSegment(), h + 16);
|
|
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 < ServerConfig.spawnGroups; ++n) {
|
|
int mx = x;
|
|
int my = y;
|
|
int mz = z;
|
|
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.min + world.rand.zrange(1 + entry.max - entry.min);
|
|
}
|
|
if(world.canCreatureTypeSpawnHere(entry, mpos)
|
|
&& canSpawnAt(EntityWaterMob.class.isAssignableFrom(entry.type), world, mpos)) {
|
|
EntityLiving entity;
|
|
try {
|
|
entity = entry.type.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, GenBiome biome, int x, int z, int sx, int sz, Random rand) {
|
|
int iters = 0;
|
|
while(rand.floatv() < biome.getMobGenChance()) {
|
|
if(iters++ == 10)
|
|
break;
|
|
WeightedList<RngSpawn> list = biome.getMobs();
|
|
if(list.isEmpty()) {
|
|
continue;
|
|
}
|
|
RngSpawn entry = list.pick(world.rand);
|
|
int count = entry.min + rand.zrange(1 + entry.max - entry.min);
|
|
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.type), world, pos)) {
|
|
EntityLiving entity;
|
|
try {
|
|
entity = entry.type.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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|