Skip to content

Commit

Permalink
Mob Spawner Entity limiter (#83)
Browse files Browse the repository at this point in the history
Extreme server lag (TPS lag) can be caused due to extremely high entity counts into the thousands. Usually this isn’t a problem as the spawning methods within Bukkit check the amount of mobs already within the world.

Mob spawners currently bypass this (with some exceptions) which effectively means under mob spawner conditions spawners will never stop spawning mobs. On RetroMC, this has caused large amounts of lag with people AFKing at mob grinders for prolonged periods causing thousands of mobs to be in a single area drastically impacting TPS.

This commit adds a feature to Poseidon which will check 8 chunks surrounding the mob spawner to ensure that the mob cap is under a predefined limit (default 150) of that entity time.
  • Loading branch information
RhysB committed Mar 3, 2024
1 parent 9435b4d commit 9f0466f
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ private void write() {
generateConfigOption("world.settings.speed-hack-check.teleport", true);
generateConfigOption("world.settings.speed-hack-check.distance", 100.0D);
generateConfigOption("world.settings.speed-hack-check.info", "This setting allows you to configure the automatic speedhack detection.");
//Mob Spawner Area Limit (8 chunks)
generateConfigOption("world.settings.mob-spawner-area-limit.enable", true);
generateConfigOption("world.settings.mob-spawner-area-limit.limit", 150);
generateConfigOption("world.settings.mob-spawner-area-limit.chunk-radius", 8);
generateConfigOption("world.settings.mob-spawner-area-limit.info",
"This setting controls the maximum number of entities of a mob spawner type that can exist within the defined chunk radius around a mob spawner. If the number of entities exceeds this limit, the spawner will stop spawning additional entities of that type. This is useful to stop the extreme lag that can be caused by mob spawners.");


//generateConfigOption("world-settings.eject-from-vehicle-on-teleport.enabled", true);
//generateConfigOption("world-settings.eject-from-vehicle-on-teleport.info", "Eject the player from a boat or minecart before teleporting them preventing cross world coordinate exploits.");

Expand Down
21 changes: 21 additions & 0 deletions src/main/java/net/minecraft/server/TileEntityMobSpawner.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package net.minecraft.server;

import com.legacyminecraft.poseidon.PoseidonConfig;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;

import java.util.List;

public class TileEntityMobSpawner extends TileEntity {

public int spawnDelay = -1;
public String mobName = "Pig"; // CraftBukkit - private -> public
public double b;
public double c = 0.0D;

private static boolean poseidonAreaLimit = PoseidonConfig.getInstance().getConfigBoolean("world.settings.mob-spawner-area-limit.enable");
private static int poseidonAreaLimitRadius = PoseidonConfig.getInstance().getConfigInteger("world.settings.mob-spawner-area-limit.limit");
private static int poseidonChunkRadius = PoseidonConfig.getInstance().getConfigInteger("world.settings.mob-spawner-area-limit.chunk-radius");

public TileEntityMobSpawner() {
this.spawnDelay = 20;
}
Expand Down Expand Up @@ -61,13 +68,27 @@ public void g_() {
}
// CraftBukkit end


// Check mob cap within the spawning radius
int j = this.world.a(entityliving.getClass(), AxisAlignedBB.b((double) this.x, (double) this.y, (double) this.z, (double) (this.x + 1), (double) (this.y + 1), (double) (this.z + 1)).b(8.0D, 4.0D, 8.0D)).size();

if (j >= 6) {
this.c();
return;
}

//Poseidon Start - Ensure the mob cound of the specific type of mob is under the defined limit within the area
if(poseidonAreaLimit) {
double chunkSize = 16.0D;
AxisAlignedBB searchArea = AxisAlignedBB.b(this.x - poseidonChunkRadius * chunkSize, 0.0D, this.z - poseidonChunkRadius * chunkSize, this.x + poseidonChunkRadius * chunkSize, 128, this.z + poseidonChunkRadius * chunkSize);
List<Entity> existingEntities = this.world.a(entityliving.getClass(), searchArea);
if (existingEntities.size() >= poseidonAreaLimitRadius) {
this.c();
return;
}
}
//Poseidon End

if (entityliving != null) {
double d3 = (double) this.x + (this.world.random.nextDouble() - this.world.random.nextDouble()) * 4.0D;
double d4 = (double) (this.y + this.world.random.nextInt(3) - 1);
Expand Down

0 comments on commit 9f0466f

Please sign in to comment.