tcr/java/src/game/world/Spawner.java
2025-03-16 17:40:47 +01:00

210 lines
7.2 KiB
Java
Executable file

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<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(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<Biome.RngSpawn> 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);
}
}
}
}
}
}