diff --git a/src/main/java/net/minecraft/entity/Entity.java b/src/main/java/net/minecraft/entity/Entity.java index 9ae9ae6..813d106 100644 --- a/src/main/java/net/minecraft/entity/Entity.java +++ b/src/main/java/net/minecraft/entity/Entity.java @@ -2478,17 +2478,42 @@ /* ===================================== ULTRAMINE START =====================================*/ public boolean isEntityLiving() - { - return false; - } - - public boolean isEntityPlayer() - { - return false; - } - - public boolean isEntityPlayerMP() - { - return false; - } + { + return false; + } + + public boolean isEntityPlayer() + { + return false; + } + + public boolean isEntityPlayerMP() + { + return false; + } + + public boolean isEntityMonster() + { + return this instanceof net.minecraft.entity.monster.IMob; + } + + public boolean isEntityAnimal() + { + return false; + } + + public boolean isEntityAmbient() + { + return false; + } + + public boolean isEntityWater() + { + return false; + } + + public double getEntityDespawnDistance() + { + return 9216d;//16384.0d; + } } diff --git a/src/main/java/net/minecraft/entity/EntityLiving.java b/src/main/java/net/minecraft/entity/EntityLiving.java index 8220928..6c1f720 100644 --- a/src/main/java/net/minecraft/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/entity/EntityLiving.java @@ -480,6 +480,8 @@ protected void despawnEntity() { + if(!canDespawn()) + return; //Зачем события кидать лишний раз? Если моду надо, в своих классах реализует метод по-своему Result result = null; if (this.persistenceRequired) { @@ -507,7 +509,7 @@ double d2 = entityplayer.posZ - this.posZ; double d3 = d0 * d0 + d1 * d1 + d2 * d2; - if (this.canDespawn() && d3 > 16384.0D) + if (this.canDespawn() && d3 > getEntityDespawnDistance()) { this.setDead(); } diff --git a/src/main/java/net/minecraft/entity/monster/EntityMob.java b/src/main/java/net/minecraft/entity/monster/EntityMob.java index d15ce5e..71d7c7e 100644 --- a/src/main/java/net/minecraft/entity/monster/EntityMob.java +++ b/src/main/java/net/minecraft/entity/monster/EntityMob.java @@ -201,4 +201,12 @@ { return true; } + + /*===================================== ULTRAMINE START =====================================*/ + + @Override + public boolean isEntityMonster() + { + return true; + } } \ No newline at end of file diff --git a/src/main/java/net/minecraft/entity/passive/EntityAmbientCreature.java b/src/main/java/net/minecraft/entity/passive/EntityAmbientCreature.java index 99895d5..b1bfce0 100644 --- a/src/main/java/net/minecraft/entity/passive/EntityAmbientCreature.java +++ b/src/main/java/net/minecraft/entity/passive/EntityAmbientCreature.java @@ -22,4 +22,18 @@ { return false; } + + /*===================================== ULTRAMINE START =====================================*/ + + @Override + public boolean isEntityAmbient() + { + return true; + } + + @Override + public double getEntityDespawnDistance() + { + return 4096d; //4 chunks square + } } \ No newline at end of file diff --git a/src/main/java/net/minecraft/entity/passive/EntityAnimal.java b/src/main/java/net/minecraft/entity/passive/EntityAnimal.java index f112c10..3beed01 100644 --- a/src/main/java/net/minecraft/entity/passive/EntityAnimal.java +++ b/src/main/java/net/minecraft/entity/passive/EntityAnimal.java @@ -2,7 +2,9 @@ import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; + import java.util.List; + import net.minecraft.entity.Entity; import net.minecraft.entity.EntityAgeable; import net.minecraft.entity.SharedMonsterAttributes; @@ -380,4 +382,12 @@ super.handleHealthUpdate(p_70103_1_); } } + + /*===================================== ULTRAMINE START =====================================*/ + + @Override + public boolean isEntityAnimal() + { + return true; + } } \ No newline at end of file diff --git a/src/main/java/net/minecraft/entity/passive/EntityWaterMob.java b/src/main/java/net/minecraft/entity/passive/EntityWaterMob.java index 5f17f7a..a642a7a 100644 --- a/src/main/java/net/minecraft/entity/passive/EntityWaterMob.java +++ b/src/main/java/net/minecraft/entity/passive/EntityWaterMob.java @@ -60,4 +60,12 @@ this.setAir(300); } } + + /*===================================== ULTRAMINE START =====================================*/ + + @Override + public boolean isEntityWater() + { + return true; + } } \ No newline at end of file diff --git a/src/main/java/net/minecraft/world/World.java b/src/main/java/net/minecraft/world/World.java index 51e8427..75da45d 100644 --- a/src/main/java/net/minecraft/world/World.java +++ b/src/main/java/net/minecraft/world/World.java @@ -4053,8 +4053,30 @@ return activeChunkSet.size(); } + public TIntByteMap getActiveChunkSet() + { + return activeChunkSet; + } + protected boolean isChunkLoaderEnabled() { return true; } + + public int countEntitiesByType(EnumCreatureType type, int cx, int cz, int radius) + { + int count = 0; + + for(int x = cx - radius; x <= cx + radius; x++) + { + for(int z = cz - radius; z <= cz + radius; z++) + { + Chunk chunk = getChunkIfExists(x, z); + if(chunk == null) + return Integer.MAX_VALUE; + count += chunk.getEntityCountByType(type); + } + } + return count; + } } diff --git a/src/main/java/net/minecraft/world/WorldServer.java b/src/main/java/net/minecraft/world/WorldServer.java index 62cf636..6c7f4cf 100644 --- a/src/main/java/net/minecraft/world/WorldServer.java +++ b/src/main/java/net/minecraft/world/WorldServer.java @@ -77,6 +77,7 @@ import org.ultramine.server.WorldsConfig.WorldConfig.Settings.WorldTime; import org.ultramine.server.chunk.ChunkHash; import org.ultramine.server.chunk.PendingBlockUpdate; +import org.ultramine.server.mobspawn.MobSpawnManager; public class WorldServer extends World { @@ -169,7 +170,10 @@ if (this.getGameRules().getGameRuleBooleanValue("doMobSpawning")) { - this.animalSpawner.findChunksForSpawning(this, this.spawnHostileMobs, this.spawnPeacefulMobs, this.worldInfo.getWorldTotalTime() % 400L == 0L); + if(isServer && mobSpawner != null) + mobSpawner.performSpawn(spawnHostileMobs, spawnPeacefulMobs, worldInfo.getWorldTotalTime()); + else + this.animalSpawner.findChunksForSpawning(this, this.spawnHostileMobs, this.spawnPeacefulMobs, this.worldInfo.getWorldTotalTime() % 400L == 0L); } this.theProfiler.endStartSection("chunkSource"); @@ -975,6 +979,8 @@ private static final boolean isServer = FMLCommonHandler.instance().getSide().isServer(); private WorldConfig config; + @SideOnly(Side.SERVER) + private MobSpawnManager mobSpawner; @Override public void checkSessionLock() throws MinecraftException @@ -1037,6 +1043,12 @@ public void setConfig(WorldConfig config) { this.config = config; + if(isServer && config.mobSpawn.spawnEngine == WorldConfig.MobSpawn.MobSpawnEngine.NEW) + { + if(mobSpawner == null) + mobSpawner = new MobSpawnManager(this); + mobSpawner.configure(config); + } } public WorldConfig getConfig() diff --git a/src/main/java/net/minecraft/world/chunk/Chunk.java b/src/main/java/net/minecraft/world/chunk/Chunk.java index 2733434..62e3e4e 100644 --- a/src/main/java/net/minecraft/world/chunk/Chunk.java +++ b/src/main/java/net/minecraft/world/chunk/Chunk.java @@ -24,6 +24,7 @@ import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; import net.minecraft.entity.Entity; +import net.minecraft.entity.EnumCreatureType; import net.minecraft.init.Blocks; import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntity; @@ -803,6 +804,7 @@ p_76612_1_.chunkCoordY = k; p_76612_1_.chunkCoordZ = this.zPosition; this.entityLists[k].add(p_76612_1_); + onEntityAdd(p_76612_1_); } public void removeEntity(Entity p_76622_1_) @@ -822,7 +824,8 @@ p_76608_2_ = this.entityLists.length - 1; } - this.entityLists[p_76608_2_].remove(p_76608_1_); + if(this.entityLists[p_76608_2_].remove(p_76608_1_)) + onEntityRemove(p_76608_1_); } public boolean canBlockSeeTheSky(int p_76619_1_, int p_76619_2_, int p_76619_3_) @@ -923,6 +926,7 @@ { Entity entity = (Entity)iterator.next(); entity.onChunkLoad(); + onEntityAdd(entity); } this.worldObj.addLoadedEntities(this.entityLists[i]); @@ -949,6 +953,7 @@ this.worldObj.unloadEntities(this.entityLists[i]); } MinecraftForge.EVENT_BUS.post(new ChunkEvent.Unload(this)); + resetEntityCounters(); } public void setChunkModified() @@ -1546,6 +1551,12 @@ private boolean wasActive; private int lastsavePendingCount; + private short entityLivingCount; + private short entityMonsterCount; + private short entityAnimalCount; + private short entityAmbientCount; + private short entityWaterCount; + public PendingBlockUpdate pollPending(long time) { if(pendingUpdatesQueue == null || pendingUpdatesQueue.size() == 0) return null; @@ -1635,4 +1646,59 @@ { return isModified || pendingUpdatesSet != null && lastsavePendingCount != pendingUpdatesSet.size() || wasActive && hasEntities; } + + private void onEntityAdd(Entity e) + { + if(e.isEntityLiving() && !e.isEntityPlayerMP()) + { + entityLivingCount++; + if(e.isEntityMonster()) ++entityMonsterCount; + else if(e.isEntityAnimal()) ++entityAnimalCount; + else if(e.isEntityAmbient()) ++entityAmbientCount; + else if(e.isEntityWater()) ++entityWaterCount; + } + } + + private void onEntityRemove(Entity e) + { + if(e.isEntityLiving() && !e.isEntityPlayerMP()) + { + entityLivingCount--; + if(e.isEntityMonster()) --entityMonsterCount; + else if(e.isEntityAnimal()) --entityAnimalCount; + else if(e.isEntityAmbient()) --entityAmbientCount; + else if(e.isEntityWater()) --entityWaterCount; + } + } + + private void resetEntityCounters() + { + entityLivingCount = 0; + entityMonsterCount = 0; + entityAnimalCount = 0; + entityAmbientCount = 0; + entityWaterCount = 0; + } + + public int getEntityCount() + { + return entityLivingCount; + } + + public int getEntityCountByType(EnumCreatureType type) + { + switch(type) + { + case monster: + return entityMonsterCount; + case creature: + return entityAnimalCount; + case ambient: + return entityAmbientCount; + case waterCreature: + return entityWaterCount; + default: + return 0; + } + } } diff --git a/src/main/java/org/ultramine/commands/basic/TechCommands.java b/src/main/java/org/ultramine/commands/basic/TechCommands.java index 45d7700..382dbeb 100644 --- a/src/main/java/org/ultramine/commands/basic/TechCommands.java +++ b/src/main/java/org/ultramine/commands/basic/TechCommands.java @@ -1,5 +1,6 @@ package org.ultramine.commands.basic; +import net.minecraft.entity.EnumCreatureType; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; @@ -7,6 +8,7 @@ import net.minecraft.util.ChatComponentTranslation; import static net.minecraft.util.EnumChatFormatting.*; import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; import org.ultramine.commands.Command; import org.ultramine.commands.CommandContext; @@ -54,13 +56,25 @@ permissions = {"command.debuginfo"}, syntax = { "", + "[chunk]", "", "" } ) public static void debuginfo(CommandContext ctx) { - if(ctx.contains("world") || ctx.getArgs().length == 0) + if(ctx.getAction().equals("chunk")) + { + EntityPlayerMP player = ctx.getSenderAsPlayer(); + Chunk chunk = player.worldObj.getChunkFromChunkCoords(player.chunkCoordX, player.chunkCoordZ); + ctx.sendMessage("Chunk: %s %s", chunk.xPosition, chunk.zPosition); + ctx.sendMessage("EntityLiving: %s", chunk.getEntityCount()); + ctx.sendMessage("EntityMonster: %s", chunk.getEntityCountByType(EnumCreatureType.monster)); + ctx.sendMessage("EntityAnimal: %s", chunk.getEntityCountByType(EnumCreatureType.creature)); + ctx.sendMessage("EntityAmbient: %s", chunk.getEntityCountByType(EnumCreatureType.ambient)); + ctx.sendMessage("EntityWater: %s", chunk.getEntityCountByType(EnumCreatureType.waterCreature)); + } + else if(ctx.contains("world") || ctx.getArgs().length == 0) { WorldServer world = ctx.contains("world") ? ctx.get("world").asWorld() : ctx.getSenderAsPlayer().getServerForPlayer(); ctx.sendMessage("World: %s, Dimension: %s", world.getWorldInfo().getWorldName(), world.provider.dimensionId); diff --git a/src/main/java/org/ultramine/server/WorldsConfig.java b/src/main/java/org/ultramine/server/WorldsConfig.java index 0b566e6..4484f30 100644 --- a/src/main/java/org/ultramine/server/WorldsConfig.java +++ b/src/main/java/org/ultramine/server/WorldsConfig.java @@ -31,6 +31,36 @@ public boolean spawnAnimals = true; public boolean spawnMonsters = true; public boolean allowNPCs = true; + public MobSpawnEngine spawnEngine = MobSpawnEngine.OLD; + public NewEngineSettings newEngineSettings; + + public static enum MobSpawnEngine + { + OLD, NEW, NONE + } + + public static class NewEngineSettings + { + public MonsterSettings monsters; + public PerTypeMobSpawnSettings animals; + public PerTypeMobSpawnSettings water; + public PerTypeMobSpawnSettings ambient; + + public static class PerTypeMobSpawnSettings + { + public int minRadius; + public int maxRadius; + public int minPlayerDistance; + public int performInterval; + public int localCheckRadius; + public int localLimit; + } + + public static class MonsterSettings extends PerTypeMobSpawnSettings + { + public int nightlyLocalLimit; + } + } } public static class Settings diff --git a/src/main/java/org/ultramine/server/mobspawn/MobSpawnManager.java b/src/main/java/org/ultramine/server/mobspawn/MobSpawnManager.java new file mode 100644 index 0000000..b071f34 --- /dev/null +++ b/src/main/java/org/ultramine/server/mobspawn/MobSpawnManager.java @@ -0,0 +1,53 @@ +package org.ultramine.server.mobspawn; + +import org.ultramine.server.WorldsConfig.WorldConfig; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.world.WorldProviderEnd; +import net.minecraft.world.WorldProviderHell; +import net.minecraft.world.WorldServer; + +@SideOnly(Side.SERVER) +public class MobSpawnManager +{ + private final WorldServer world; + private final MobSpawner spawnerMonsters; + private MobSpawner spawnerAnimals; + private MobSpawner spawnerWater; + private MobSpawner spawnerAmbient; + + public MobSpawnManager(WorldServer world) + { + this.world = world; + spawnerMonsters = new MobSpawnerMonsters(world); + if(!(world.provider instanceof WorldProviderEnd) && !(world.provider instanceof WorldProviderHell)) + { + spawnerAnimals = new MobSpawnerAnimals(world); + spawnerWater = new MobSpawnerWater(world); + spawnerAmbient = new MobSpawnerAmbient(world); + } + } + + public void configure(WorldConfig config) + { + spawnerMonsters.configure(config); + if(spawnerAnimals != null) + { + spawnerAnimals.configure(config); + spawnerWater.configure(config); + spawnerAmbient.configure(config); + } + } + + public void performSpawn(boolean spawnMonsters, boolean spawnAnimals, long currentTick) + { + spawnerMonsters.performSpawn(currentTick); + if(spawnerAnimals != null) + { + spawnerAnimals.performSpawn(currentTick); + spawnerWater.performSpawn(currentTick); + spawnerAmbient.performSpawn(currentTick); + } + } +} diff --git a/src/main/java/org/ultramine/server/mobspawn/MobSpawner.java b/src/main/java/org/ultramine/server/mobspawn/MobSpawner.java new file mode 100644 index 0000000..2dad35a --- /dev/null +++ b/src/main/java/org/ultramine/server/mobspawn/MobSpawner.java @@ -0,0 +1,192 @@ +package org.ultramine.server.mobspawn; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.ultramine.server.WorldsConfig.WorldConfig; +import org.ultramine.server.WorldsConfig.WorldConfig.MobSpawn.NewEngineSettings.PerTypeMobSpawnSettings; +import org.ultramine.server.chunk.ChunkHash; + +import cpw.mods.fml.common.eventhandler.Event.Result; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gnu.trove.iterator.TIntByteIterator; +import gnu.trove.list.TIntList; +import gnu.trove.list.array.TIntArrayList; +import net.minecraft.block.Block; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EnumCreatureType; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.init.Blocks; +import net.minecraft.world.SpawnerAnimals; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.biome.BiomeGenBase.SpawnListEntry; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.event.ForgeEventFactory; + +@SideOnly(Side.SERVER) +public abstract class MobSpawner +{ + private static final Logger log = LogManager.getLogger(); + protected final WorldServer world; + protected final EnumCreatureType type; + protected PerTypeMobSpawnSettings set; + + private final TIntList chunks = new TIntArrayList(); + private int listIndex; + private int perTickLimit; + private long nextPerformTick; + + public MobSpawner(WorldServer world, EnumCreatureType type) + { + this.world = world; + this.type = type; + } + + protected void setConstants(PerTypeMobSpawnSettings set) + { + this.set = set; + } + + public abstract void configure(WorldConfig config); + + protected int getLocalLimit() + { + return set.localLimit; + } + + protected void rebuildList() + { + listIndex = 0; + chunks.clear(); + for(TIntByteIterator it = world.getActiveChunkSet().iterator(); it.hasNext();) + { + it.advance(); + int prior = it.value(); + if(prior >= set.minRadius && prior <= set.maxRadius) + chunks.add(it.key()); + } + chunks.shuffle(world.rand); + perTickLimit = Math.min(40, chunks.size() / set.performInterval + 1); + } + + protected abstract boolean shouldPerform(); + + public void performSpawn(long currentTick) + { + if(set != null && shouldPerform()) + { + if(listIndex == chunks.size()) + { + if(currentTick >= nextPerformTick) + { + rebuildList(); + nextPerformTick = currentTick + set.performInterval; + } + else + { + return; + } + } + + for(int i = 0, s = chunks.size(); listIndex < s && i < perTickLimit; listIndex++, i++) + { + int key = chunks.get(listIndex); + int cx = ChunkHash.keyToX(key); + int cz = ChunkHash.keyToZ(key); + + if(world.countEntitiesByType(type, cx, cz, set.localCheckRadius) < getLocalLimit()) + { + Chunk chunk = world.getChunkIfExists(cx, cz); + int randX = world.rand.nextInt(16); + int randZ = world.rand.nextInt(16); + int topf = chunk.getHeightValue(randX, randZ); + if(topf > 1) + processChunk(chunk, (cx << 4) + randX, (cz << 4) + randZ, chunk.getHeightValue(randX, randZ)); + } + } + } + } + + protected abstract void processChunk(Chunk chunk, int x, int z, int topf); + + /** + * @return true, если больше не следует предпринимать попыток спавнить мобов в данном чанке + */ + protected boolean trySpawnGroupAt(int x, int y, int z, int groupSize) + { + if(!isApplicableForSpawn(type, x, y, z)) + return false; + SpawnListEntry spawn = world.spawnRandomCreature(type, x, y, z); + if(spawn == null) + return true; + IEntityLivingData data = null; + int spawned = 0; + label: + while(true) + { + if(spawn == null) + spawn = world.spawnRandomCreature(type, x, y, z); + EntityLiving entity = spawn == null ? null : createEntityByType(spawn); + if(entity == null) + return true; + + entity.setLocationAndAngles(x + 0.5, y, z + 0.5, world.rand.nextFloat() * 360.0F, 0.0F); + + Result canSpawn = ForgeEventFactory.canEntitySpawn(entity, world, x + 0.5F, y, z + 0.5F); + if(canSpawn == Result.ALLOW || (canSpawn == Result.DEFAULT && entity.getCanSpawnHere())) + { + world.spawnEntityInWorld(entity); + data = creatureSpecificInit(data, entity, x, y, z); + spawned++; + if(spawned == groupSize || spawned >= ForgeEventFactory.getMaxSpawnPackSize(entity)) + return true; + + for(int i = 0; i < 4; i++) + { + x += world.rand.nextInt(3) - 1; + z += world.rand.nextInt(3) - 1; + if(isApplicableForSpawn(type, x, y, z)) + continue label; + } + } + + break; + } + + return spawned != 0; + } + + protected boolean isApplicableForSpawn(EnumCreatureType type, int x, int y, int z) + { + if(set.minPlayerDistance > 0 && world.getClosestPlayer(x, y, z, set.minPlayerDistance) != null) + return false; + Block block = world.getBlockIfExists(x, y, z); + return (!block.isNormalCube() && (block.getMaterial() == type.getCreatureMaterial() || block == Blocks.snow_layer && type == EnumCreatureType.monster)) && + (type == EnumCreatureType.ambient || SpawnerAnimals.canCreatureTypeSpawnAtLocation(type, world, x, y, z)); + } + + @SuppressWarnings("unchecked") + protected EntityLiving createEntityByType(SpawnListEntry type) + { + try + { + return (EntityLiving)type.entityClass.getConstructor(World.class).newInstance(world); + } + catch (Exception e) + { + log.error("Failed to create entity instance", e); + return null; + } + } + + protected IEntityLivingData creatureSpecificInit(IEntityLivingData data, EntityLiving entity, int x, int y, int z) + { + if (!ForgeEventFactory.doSpecialSpawn(entity, world, x + 0.5F, y, z + 0.5F)) + { + return entity.onSpawnWithEgg(data); + } + + return data; + } +} diff --git a/src/main/java/org/ultramine/server/mobspawn/MobSpawnerAmbient.java b/src/main/java/org/ultramine/server/mobspawn/MobSpawnerAmbient.java new file mode 100644 index 0000000..32d429f --- /dev/null +++ b/src/main/java/org/ultramine/server/mobspawn/MobSpawnerAmbient.java @@ -0,0 +1,61 @@ +package org.ultramine.server.mobspawn; + +import net.minecraft.entity.EnumCreatureType; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; + +import org.ultramine.server.WorldsConfig.WorldConfig; + +import cpw.mods.fml.common.functions.GenericIterableFactory; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +@SideOnly(Side.SERVER) +public class MobSpawnerAmbient extends MobSpawner +{ + public MobSpawnerAmbient(WorldServer world) + { + super(world, EnumCreatureType.ambient); + } + + @Override + public void configure(WorldConfig config) + { + setConstants(config.mobSpawn.newEngineSettings.ambient); + } + + @Override + protected boolean shouldPerform() + { + return world.getConfig().mobSpawn.spawnAnimals; + } + + @Override + protected void processChunk(Chunk chunk, int x, int z, int topf) + { + throw new UnsupportedOperationException(); + } + + protected void rebuildList() + { + for(EntityPlayerMP player : GenericIterableFactory.newCastingIterable(world.playerEntities, EntityPlayerMP.class)) + { + if(player.posY > 48) + continue; + + for(int i = 0; i < 12; i++) + { + int x = (int)player.posX + world.rand.nextInt(16) - 8 + (world.rand.nextBoolean() ? 8 : -8); + int y = (int)player.posY + world.rand.nextInt(16) - 8; + int z = (int)player.posZ + world.rand.nextInt(16) - 8 + (world.rand.nextBoolean() ? 8 : -8); + + if(world.countEntitiesByType(type, x >> 4, z >> 4, set.localCheckRadius) < getLocalLimit() && world.getBlockLightValue(x, y, z) < 7) + { + if(trySpawnGroupAt(x, y, z, 4 + world.rand.nextInt(4))) + break; + } + } + } + } +} diff --git a/src/main/java/org/ultramine/server/mobspawn/MobSpawnerAnimals.java b/src/main/java/org/ultramine/server/mobspawn/MobSpawnerAnimals.java new file mode 100644 index 0000000..013833e --- /dev/null +++ b/src/main/java/org/ultramine/server/mobspawn/MobSpawnerAnimals.java @@ -0,0 +1,40 @@ +package org.ultramine.server.mobspawn; + +import net.minecraft.entity.EnumCreatureType; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.common.util.ForgeDirection; + +import org.ultramine.server.WorldsConfig.WorldConfig; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +@SideOnly(Side.SERVER) +public class MobSpawnerAnimals extends MobSpawner +{ + public MobSpawnerAnimals(WorldServer world) + { + super(world, EnumCreatureType.creature); + } + + @Override + public void configure(WorldConfig config) + { + setConstants(config.mobSpawn.newEngineSettings.animals); + } + + @Override + protected boolean shouldPerform() + { + return world.getConfig().mobSpawn.spawnAnimals && (int)(world.getWorldInfo().getWorldTime() % 24000) < 12000; //day + } + + @Override + protected void processChunk(Chunk chunk, int x, int z, int topf) + { + if(!world.getBlock(x, topf-1, z).isSideSolid(world, x, topf-1, z, ForgeDirection.UP)) + --topf; + trySpawnGroupAt(x, topf, z, 3); + } +} diff --git a/src/main/java/org/ultramine/server/mobspawn/MobSpawnerMonsters.java b/src/main/java/org/ultramine/server/mobspawn/MobSpawnerMonsters.java new file mode 100644 index 0000000..f0dad81 --- /dev/null +++ b/src/main/java/org/ultramine/server/mobspawn/MobSpawnerMonsters.java @@ -0,0 +1,79 @@ +package org.ultramine.server.mobspawn; + +import org.ultramine.server.WorldsConfig.WorldConfig; +import org.ultramine.server.WorldsConfig.WorldConfig.MobSpawn.NewEngineSettings.MonsterSettings; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.entity.EnumCreatureType; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.common.util.ForgeDirection; + +@SideOnly(Side.SERVER) +public class MobSpawnerMonsters extends MobSpawner +{ + private MonsterSettings set; + + public MobSpawnerMonsters(WorldServer world) + { + super(world, EnumCreatureType.monster); + } + + @Override + public void configure(WorldConfig config) + { + setConstants(set = config.mobSpawn.newEngineSettings.monsters); + } + + @Override + protected boolean shouldPerform() + { + return world.getConfig().mobSpawn.spawnMonsters; + } + + @Override + protected int getLocalLimit() + { + int worldTime = (int)(world.getWorldInfo().getWorldTime() % 24000); + boolean isDay = worldTime < 14200 || worldTime > 21800; + return isDay ? super.getLocalLimit() : set.nightlyLocalLimit; + } + + @Override + protected void processChunk(Chunk chunk, int x, int z, int topf) + { + if(!world.getBlock(x, topf-1, z).isSideSolid(world, x, topf-1, z, ForgeDirection.UP)) + --topf; + int worldTime = (int)(world.getWorldInfo().getWorldTime() % 24000); + boolean isDay = worldTime < 14200 || worldTime > 21800; + + int op; + int y; + if(isDay) + { + op = 0; + y = world.rand.nextInt(topf - 2); + } + else if(world.rand.nextInt(3) == 0) + { + op = 1; + y = topf; + } + else + { + op = 2; + y = world.rand.nextInt(topf + 1); + } + + for(int i = 0; i < 12; i++) + { + if(trySpawnGroupAt(x, y, z, 1)) + break; + + if(op == 0) y = world.rand.nextInt(topf - 2); + else if(op == 1) break; + else if(op == 2) y = world.rand.nextInt(topf + 1); + } + } +} diff --git a/src/main/java/org/ultramine/server/mobspawn/MobSpawnerWater.java b/src/main/java/org/ultramine/server/mobspawn/MobSpawnerWater.java new file mode 100644 index 0000000..67fe7d4 --- /dev/null +++ b/src/main/java/org/ultramine/server/mobspawn/MobSpawnerWater.java @@ -0,0 +1,49 @@ +package org.ultramine.server.mobspawn; + +import net.minecraft.block.material.Material; +import net.minecraft.entity.EnumCreatureType; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; + +import org.ultramine.server.WorldsConfig.WorldConfig; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +@SideOnly(Side.SERVER) +public class MobSpawnerWater extends MobSpawner +{ + public MobSpawnerWater(WorldServer world) + { + super(world, EnumCreatureType.waterCreature); + } + + @Override + public void configure(WorldConfig config) + { + setConstants(config.mobSpawn.newEngineSettings.water); + } + + @Override + protected boolean shouldPerform() + { + return world.getConfig().mobSpawn.spawnAnimals; + } + + @Override + protected void processChunk(Chunk chunk, int x, int z, int topf) + { + topf--; + if(world.getBlockIfExists(z, topf, x).getMaterial() != Material.water) + return; + int y = topf - world.rand.nextInt(8); + + for(int i = 0; i < 2; i++) + { + if(trySpawnGroupAt(x, y, z, 3)) + break; + + y = topf; + } + } +} diff --git a/src/main/resources/org/ultramine/defaults/defaultworlds.yml b/src/main/resources/org/ultramine/defaults/defaultworlds.yml index 0853afc..21a8775 100644 --- a/src/main/resources/org/ultramine/defaults/defaultworlds.yml +++ b/src/main/resources/org/ultramine/defaults/defaultworlds.yml @@ -7,9 +7,39 @@ providerID: 0 seed: {seed} mobSpawn: + allowAnimals: true spawnAnimals: true spawnMonsters: true spawnNPCs: true + spawnEngine: NEW + newEngineSettings: + monsters: + minRadius: 2 + maxRadius: 2 + minPlayerDistance: 0 + performInterval: 20 + localCheckRadius: 1 + localLimit: 3 + nightlyLocalLimit: 5 + water: + minRadius: 3 + maxRadius: 5 + minPlayerDistance: 0 + performInterval: 400 + localCheckRadius: 4 + localLimit: 3 + animals: + minRadius: 5 + maxRadius: 6 + minPlayerDistance: 0 + performInterval: 401 + localCheckRadius: 5 + localLimit: 3 + ambient: + minPlayerDistance: 8 + performInterval: 1203 + localCheckRadius: 4 + localLimit: 10 settings: difficulty: 1 maxBuildHeight: 256