diff --git a/src/main/java/noppes/npcs/NPCSpawning.java b/src/main/java/noppes/npcs/NPCSpawning.java index 8b97c0307..ed633c8f7 100644 --- a/src/main/java/noppes/npcs/NPCSpawning.java +++ b/src/main/java/noppes/npcs/NPCSpawning.java @@ -38,6 +38,7 @@ public class NPCSpawning { private static Set eligibleChunksForSpawning = Sets.newHashSet(); private static final byte CHUNK_SPAWN_RADIUS = 7; private static final int SPAWN_ATTEMPTS_PER_CHUNK = 3; + private static final int NATURAL_CAP_PER_256_CHUNKS = 70; private static final long RUNTIME_SPAWN_TICK_INTERVAL = 20L; private static final int RUNTIME_SPAWN_CYCLE_TICKS = 400; private static final String NATURAL_SPAWN_ID_TAG = "CNPCNaturalSpawnId"; @@ -76,8 +77,8 @@ public class NPCSpawning { } } } - int cap = eligibleChunksForSpawning.size(); - int npcCount = countNPCs(world); + int cap = getScaledNaturalCap(eligibleChunksForSpawning.size()); + int npcCount = countNaturalSpawnedNPCs(world); if (npcCount >= cap) { return; } @@ -155,17 +156,24 @@ public class NPCSpawning { return result; } - public static int countNPCs(World world) { + private static int countNaturalSpawnedNPCs(World world) { int count = 0; List list = world.loadedEntityList; for (Entity entity : list) { - if (entity instanceof EntityNPCInterface) { + if (entity instanceof EntityNPCInterface && !entity.isDead && entity.getEntityData().hasKey(NATURAL_SPAWN_ID_TAG)) { count++; } } return count; } + private static int getScaledNaturalCap(int eligibleChunkCount) { + if (eligibleChunkCount <= 0) { + return 0; + } + return Math.max(1, NATURAL_CAP_PER_256_CHUNKS * eligibleChunkCount / 256); + } + protected static ChunkPosition getChunk(World world, int x, int z) { Chunk chunk = world.getChunkFromChunkCoords(x, z); int k = x * 16 + world.rand.nextInt(16); @@ -188,14 +196,14 @@ public class NPCSpawning { } } } - return chunkSet.size(); + return getScaledNaturalCap(chunkSet.size()); } private static HashMap getNaturalSpawnEntryCounts(World world) { HashMap counts = new HashMap(); List list = world.loadedEntityList; for (Entity entity : list) { - if (entity == null || entity.isDead) { + if (entity == null || entity.isDead || !(entity instanceof EntityNPCInterface)) { continue; } NBTTagCompound entityData = entity.getEntityData(); @@ -223,6 +231,10 @@ public class NPCSpawning { return false; } long tickDelta = world.getWorldInfo().getWorldTotalTime() - lastSpawnTick; + if (tickDelta < 0) { + SPAWN_COOLDOWNS.remove(key); + return false; + } return tickDelta < data.cooldownTicks; } @@ -288,7 +300,7 @@ public class NPCSpawning { public static void performWorldGenSpawning(World world, int x, int z, Random rand) { int cap = getCap(world); - int npcCount = countNPCs(world); + int npcCount = countNaturalSpawnedNPCs(world); if (npcCount >= cap) { return; } @@ -379,6 +391,7 @@ public class NPCSpawning { npc.stats.canDespawn = true; npc.stats.playerSetCanDespawn = true; } + npc.syncDespawnPersistence(); npc.ais.returnToStart = false; npc.ais.startPos = new int[]{x, y, z}; npc.updateAI = true; diff --git a/src/main/java/noppes/npcs/ServerEventsHandler.java b/src/main/java/noppes/npcs/ServerEventsHandler.java index 0f9fa1d3e..43d78e6eb 100644 --- a/src/main/java/noppes/npcs/ServerEventsHandler.java +++ b/src/main/java/noppes/npcs/ServerEventsHandler.java @@ -530,7 +530,7 @@ public class ServerEventsHandler { @SubscribeEvent public void populateChunk(PopulateChunkEvent.Post event) { - NPCSpawning.performWorldGenSpawning(event.world, event.chunkX, event.chunkZ, event.rand); + NPCSpawning.performWorldGenSpawning(event.world, event.chunkX << 4, event.chunkZ << 4, event.rand); } @SubscribeEvent diff --git a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java index 7a978eb89..a3dcfb84c 100644 --- a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java +++ b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java @@ -255,7 +255,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti setFaction(faction.id); setSize(1, 1); this.updateTasks(); - this.func_110163_bv(); + this.syncDespawnPersistence(); if (!this.isRemote() && this.wrappedNPC == null) { this.wrappedNPC = new ScriptNpc<>(this); @@ -1203,7 +1203,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti this.getEntityAttribute(SharedMonsterAttributes.followRange).setBaseValue(ConfigMain.NpcNavRange); this.updateTasks(); - this.func_110163_bv(); + this.syncDespawnPersistence(); } @Override @@ -1404,6 +1404,26 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti field_20062_v += d1 * 0.25D; } + @Override + protected void despawnEntity() { + syncDespawnPersistence(); + super.despawnEntity(); + } + + public void syncDespawnPersistence() { + if (stats == null) { + if (!this.persistenceRequired) { + this.func_110163_bv(); + } + return; + } + if (stats.canDespawn) { + this.persistenceRequired = false; + } else if (!this.persistenceRequired) { + this.func_110163_bv(); + } + } + @Override protected boolean canDespawn() { return stats.canDespawn; diff --git a/src/main/java/noppes/npcs/scripted/entity/ScriptNpc.java b/src/main/java/noppes/npcs/scripted/entity/ScriptNpc.java index 25734b7e4..c362d72c6 100644 --- a/src/main/java/noppes/npcs/scripted/entity/ScriptNpc.java +++ b/src/main/java/noppes/npcs/scripted/entity/ScriptNpc.java @@ -1109,6 +1109,7 @@ public class ScriptNpc extends ScriptLiving imp public void setNaturallyDespawns(boolean canDespawn) { npc.stats.canDespawn = canDespawn; npc.stats.playerSetCanDespawn = canDespawn; + npc.syncDespawnPersistence(); } public boolean spawnedFromSoulStone() { diff --git a/src/main/resources/META-INF/customnpcs_at.cfg b/src/main/resources/META-INF/customnpcs_at.cfg index dbcb46481..a41eb23c9 100644 --- a/src/main/resources/META-INF/customnpcs_at.cfg +++ b/src/main/resources/META-INF/customnpcs_at.cfg @@ -18,6 +18,8 @@ public net.minecraft.client.renderer.entity.RenderPlayer func_77043_a(Lnet/minec #EntityLivingBase public net.minecraft.entity.EntityLivingBase func_82166_i()I # getArmSwingAnimationEnd public net.minecraft.entity.EntityLivingBase field_70703_bu # isJumping +#EntityLiving +public net.minecraft.entity.EntityLiving field_82179_bU # persistenceRequired # Minecraft public net.minecraft.client.Minecraft field_147126_aw # mcMusicTicker # MusicTicker