Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mob spawner area limiter #83

Merged
merged 2 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/main/java/com/legacyminecraft/poseidon/Poseidon.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.legacyminecraft.poseidon;

import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftServer;

import java.util.LinkedList;

public class Poseidon {

/**
* Returns a list of the server's TPS (Ticks Per Second) records for performance monitoring.
* The list contains Double values indicating the TPS at each second, ordered from most recent to oldest.
*
* @return LinkedList<Double> of TPS records.
*/
public static LinkedList<Double> getTpsRecords() {
return ((CraftServer) Bukkit.getServer()).getServer().getTpsRecords();
}


}
13 changes: 13 additions & 0 deletions src/main/java/com/legacyminecraft/poseidon/PoseidonConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,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 Expand Up @@ -139,6 +147,11 @@ private void write() {
generateConfigOption("message.player.join", "\u00A7e%player% joined the game.");
generateConfigOption("message.player.leave", "\u00A7e%player% left the game.");

//Optional Poseidon Commands
generateConfigOption("command.info", "This section allows you to enable or disable optional Poseidon commands. This is useful if you have a plugin that conflicts with a Poseidon command.");
generateConfigOption("command.tps.info", "Enables the /tps command to show the server's TPS for various intervals.");
generateConfigOption("command.tps.enabled", true);

//Tree Leave Destroy Blacklist
if (Boolean.valueOf(String.valueOf(getConfigOption("world.settings.block-tree-growth.enabled", true)))) {
if (String.valueOf(this.getConfigOption("world.settings.block-tree-growth.list", "")).trim().isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.legacyminecraft.poseidon.commands;

import com.legacyminecraft.poseidon.Poseidon;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.defaults.VanillaCommand;

import java.util.LinkedList;
import java.util.LinkedHashMap;
import java.util.Map;

public class TPSCommand extends Command {

private final LinkedHashMap<String, Integer> intervals = new LinkedHashMap<>();

public TPSCommand(String name) {
super(name);
this.description = "Shows the server's TPS for various intervals";
this.usageMessage = "/tps";
this.setPermission("poseidon.command.tps");

// Define the intervals for TPS calculation
intervals.put("5s", 5);
intervals.put("30s", 30);
intervals.put("1m", 60);
intervals.put("5m", 300);
intervals.put("10m", 600);
intervals.put("15m", 900);
}

@Override
public boolean execute(CommandSender sender, String currentAlias, String[] args) {
if (!testPermission(sender)) return true;

LinkedList<Double> tpsRecords = Poseidon.getTpsRecords();
StringBuilder message = new StringBuilder("§bServer TPS: ");

// Calculate and format TPS for each interval dynamically
for (Map.Entry<String, Integer> entry : intervals.entrySet()) {
double averageTps = calculateAverage(tpsRecords, entry.getValue());
message.append(formatTps(averageTps)).append(" (").append(entry.getKey()).append("), ");
}

// Remove the trailing comma and space
if (message.length() > 0) {
message.setLength(message.length() - 2);
}

sender.sendMessage(message.toString());
return true;
}

private double calculateAverage(LinkedList<Double> records, int seconds) {
int size = Math.min(records.size(), seconds);
if (size == 0) return 20.0;

double total = 0;
for (int i = 0; i < size; i++) {
total += records.get(i);
}
return total / size;
}

private String formatTps(double tps) {
String colorCode;
if (tps >= 19) {
colorCode = "§a";
} else if (tps >= 15) {
colorCode = "§e";
} else {
colorCode = "§c";
}
return colorCode + String.format("%.2f", tps);
}
}
30 changes: 30 additions & 0 deletions src/main/java/net/minecraft/server/MinecraftServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,16 @@ public void run() {
}
}

//Project Poseidon Start - Tick Update
private final LinkedList<Double> tpsRecords = new LinkedList<>();
private long lastTick = System.currentTimeMillis();
private int tickCount = 0;

public LinkedList<Double> getTpsRecords() {
return tpsRecords;
}
//Project Poseidon End - Tick Update

private void h() {
ArrayList arraylist = new ArrayList();
Iterator iterator = trackerList.keySet().iterator();
Expand Down Expand Up @@ -494,6 +504,26 @@ private void h() {

((CraftScheduler) this.server.getScheduler()).mainThreadHeartbeat(this.ticks); // CraftBukkit

//Project Poseidon Start - Tick Update
long currentTime = System.currentTimeMillis();
tickCount++;

//Check if a second has passed
if (currentTime - lastTick >= 1000) {
double tps = tickCount / ((currentTime - lastTick) / 1000.0);
tpsRecords.addFirst(tps);
if(tpsRecords.size() > 900) { //Don't keep more than 15 minutes of data
tpsRecords.removeLast();
}

tickCount = 0;
lastTick = currentTime;
}

//Project Poseidon End - Tick Update



for (j = 0; j < this.worlds.size(); ++j) { // CraftBukkit
// if (j == 0 || this.propertyManager.getBoolean("allow-nether", true)) { // CraftBukkit
WorldServer worldserver = this.worlds.get(j); // CraftBukkit
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
8 changes: 7 additions & 1 deletion src/main/java/org/bukkit/command/SimpleCommandMap.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.bukkit.command;

import com.legacyminecraft.poseidon.PoseidonConfig;
import com.legacyminecraft.poseidon.commands.TPSCommand;
import org.bukkit.Server;
import org.bukkit.command.defaults.*;

Expand Down Expand Up @@ -43,10 +45,14 @@ public SimpleCommandMap(final Server server) {
}

private void setDefaultCommands(final Server server) {
register("poseidon", new PoseidonCommand("poseidon"));
register("bukkit", new VersionCommand("version"));
register("bukkit", new ReloadCommand("reload"));
register("bukkit", new PluginsCommand("plugins"));

//Poseidon Command
register("poseidon", new PoseidonCommand("poseidon"));
if (PoseidonConfig.getInstance().getConfigBoolean("command.tps.enabled"))
register("poseidon", new TPSCommand("tps"));
}

/**
Expand Down
Loading