From df5eaaafd25ed43b37cbc8073538fa9a362616e6 Mon Sep 17 00:00:00 2001 From: md_5 Date: Fri, 21 Jun 2013 17:29:54 +1000 Subject: [PATCH] Fix Mob Spawning Relative to View Distance Changes the mob spawning algorithm to properly account for view distance and the range around players. Needs better documentation. diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java index 8345e87..e4725b0 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -43,6 +43,7 @@ public class Chunk { private long v; private int w; private ConcurrentLinkedQueue x; + protected gnu.trove.map.hash.TObjectIntHashMap entityCount = new gnu.trove.map.hash.TObjectIntHashMap(); // Spigot // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking private int neighbors = 0x1 << 12; @@ -606,6 +607,22 @@ public class Chunk { entity.ac = k; entity.ad = this.locZ; this.entitySlices[k].add(entity); + // Spigot start - increment creature type count + // Keep this synced up with World.a(Class) + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent()) { + return; + } + } + for ( EnumCreatureType creatureType : EnumCreatureType.values() ) + { + if ( creatureType.a().isAssignableFrom( entity.getClass() ) ) + { + this.entityCount.adjustOrPutValue( creatureType.a(), 1, 1 ); + } + } + // Spigot end } public void b(Entity entity) { @@ -622,6 +639,22 @@ public class Chunk { } this.entitySlices[i].remove(entity); + // Spigot start - decrement creature type count + // Keep this synced up with World.a(Class) + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent()) { + return; + } + } + for ( EnumCreatureType creatureType : EnumCreatureType.values() ) + { + if ( creatureType.a().isAssignableFrom( entity.getClass() ) ) + { + this.entityCount.adjustValue( creatureType.a(), -1 ); + } + } + // Spigot end } public boolean c(BlockPosition blockposition) { diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java index b3cb8bb..9e19dfd 100644 --- a/src/main/java/net/minecraft/server/SpawnerCreature.java +++ b/src/main/java/net/minecraft/server/SpawnerCreature.java @@ -17,6 +17,25 @@ public final class SpawnerCreature { public SpawnerCreature() {} + // Spigot start - get entity count only from chunks being processed in b + private int getEntityCount(WorldServer server, Class oClass) + { + int i = 0; + Iterator it = this.b.iterator(); + while ( it.hasNext() ) + { + Long coord = it.next(); + int x = LongHash.msw( coord ); + int z = LongHash.lsw( coord ); + if ( !((ChunkProviderServer)server.chunkProvider).unloadQueue.contains( coord ) && server.isChunkLoaded( x, z, true ) ) + { + i += server.getChunkAt( x, z ).entityCount.get( oClass ); + } + } + return i; + } + // Spigot end + public int a(WorldServer worldserver, boolean flag, boolean flag1, boolean flag2) { if (!flag && !flag1) { return 0; @@ -36,6 +55,11 @@ public final class SpawnerCreature { j = MathHelper.floor(entityhuman.locZ / 16.0D); byte b0 = 8; + // Spigot Start + b0 = worldserver.spigotConfig.mobSpawnRange; + b0 = ( b0 > worldserver.spigotConfig.viewDistance ) ? (byte) worldserver.spigotConfig.viewDistance : b0; + b0 = ( b0 > 8 ) ? 8 : b0; + // Spigot End for (int i1 = -b0; i1 <= b0; ++i1) { for (k = -b0; k <= b0; ++k) { @@ -89,18 +113,20 @@ public final class SpawnerCreature { if (limit == 0) { continue; } + int mobcnt = 0; // Spigot // CraftBukkit end if ((!enumcreaturetype.d() || flag1) && (enumcreaturetype.d() || flag) && (!enumcreaturetype.e() || flag2)) { k = worldserver.a(enumcreaturetype.a()); int l1 = limit * i / a; // CraftBukkit - use per-world limits - if (k <= l1) { + if ((mobcnt = getEntityCount(worldserver, enumcreaturetype.a())) <= limit * i / 256) { BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition(); Iterator iterator1 = this.b.iterator(); + int moblimit = (limit * i / 256) - mobcnt + 1; // Spigot - up to 1 more than limit label120: - while (iterator1.hasNext()) { + while (iterator1.hasNext() && (moblimit > 0)) { // Spigot - while more allowed // CraftBukkit start = use LongHash and LongObjectHashMap long key = ((Long) iterator1.next()).longValue(); BlockPosition blockposition1 = getRandomPosition(worldserver, LongHash.msw(key), LongHash.lsw(key)); @@ -162,7 +188,10 @@ public final class SpawnerCreature { entityinsentient.die(); } - if (l2 >= entityinsentient.cJ()) { + // Spigot start + if ( --moblimit <= 0 ) { + // If we're past limit, stop spawn + // Spigot end continue label120; } } diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java index 86300d6..cacb8fc 100644 --- a/src/main/java/org/spigotmc/SpigotWorldConfig.java +++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java @@ -122,4 +122,11 @@ public class SpigotWorldConfig viewDistance = getInt( "view-distance", Bukkit.getViewDistance() ); log( "View Distance: " + viewDistance ); } + + public byte mobSpawnRange; + private void mobSpawnRange() + { + mobSpawnRange = (byte) getInt( "mob-spawn-range", 4 ); + log( "Mob Spawn Range: " + mobSpawnRange ); + } } -- 2.5.0