From c15eeeb38cbb3bdfdc46239cd0dbbd204a0a103a Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 01:46:56 +0100 Subject: [PATCH 01/17] Allow title times to be configured & allow title to be disabled completely --- .../extras/modules/player/PlayerConnection.java | 15 +++++++++++---- src/main/resources/config.yml | 4 ++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java index b2be1747..dc3d58db 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java @@ -45,9 +45,16 @@ public final class PlayerConnection implements Listener { "" ) ); - private static final Duration FADE_IN = Duration.ofMillis(50); - private static final Duration STAY = Duration.ofMillis(8000); - private static final Duration FADE_OUT = Duration.ofMillis(250); + private static final boolean SEND_TITLE = CONFIG.getBoolean("playerJoinSendTitle"); + private static final Duration FADE_IN = Duration.ofMillis( + CONFIG.getLong("playerJoinTitleFadeIn") + ); + private static final Duration STAY = Duration.ofMillis( + CONFIG.getLong("playerJoinTitleStay") + ); + private static final Duration FADE_OUT = Duration.ofMillis( + CONFIG.getLong("playerJoinTitleFadeOut") + ); private static final boolean ENABLE_KICK = CONFIG.getBoolean("enableKick"); private static final boolean ENABLE_JOIN_RESTRICTIONS = CONFIG.getBoolean( @@ -102,7 +109,7 @@ void onAsyncPlayerPreLogin(final AsyncPlayerPreLoginEvent event) { void onPlayerJoin(final PlayerJoinEvent event) { final Player player = event.getPlayer(); - player.showTitle(Title.title( + if (SEND_TITLE) player.showTitle(Title.title( TITLE, SUBTITLE, Title.Times.times(FADE_IN, STAY, FADE_OUT) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b26129a5..32575bf6 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -11,7 +11,11 @@ randomizeSpawn: false maxEntitiesPerChunk: 50 maxEntitiesPerWorld: 5120 maxTntsPerWorld: 1024 +playerJoinSendTitle: true playerJoinTitle: "§7Welcome to Kaboom!" playerJoinSubtitle: "Free OP • Anarchy • Creative" +playerJoinTitleFadeIn: 50 +playerJoinTitleStay: 8000 +playerJoinTitleFadeOut: 50 opTag: "§4§l[§c§lOP§4§l] §c" deOpTag: "§8§l[§7§lDeOP§8§l] §7" From 1c388f71a82deb7657f1d3f57f0f56518113579e Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 01:48:37 +0100 Subject: [PATCH 02/17] Allow minimum command delay to be configured --- .../pw/kaboom/extras/modules/player/PlayerCommand.java | 7 ++++++- src/main/resources/config.yml | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerCommand.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerCommand.java index cc3e5d0a..3d3c3b48 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerCommand.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerCommand.java @@ -10,10 +10,15 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.plugin.java.JavaPlugin; +import pw.kaboom.extras.Main; import pw.kaboom.extras.modules.server.ServerCommand; public final class PlayerCommand implements Listener { private static HashMap commandMillisList = new HashMap(); + private static final long MIN_COMMAND_DELAY_MILLIS = JavaPlugin.getPlugin(Main.class) + .getConfig() + .getLong("minCommandDelayMillis"); @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) { @@ -23,7 +28,7 @@ void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) { final long lastCommandTime = getCommandMillisList().get(playerUuid); final long millisDifference = System.currentTimeMillis() - lastCommandTime; - if (millisDifference < 75) { + if (millisDifference < MIN_COMMAND_DELAY_MILLIS) { event.setCancelled(true); return; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 32575bf6..a65387a5 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -19,3 +19,4 @@ playerJoinTitleStay: 8000 playerJoinTitleFadeOut: 50 opTag: "§4§l[§c§lOP§4§l] §c" deOpTag: "§8§l[§7§lDeOP§8§l] §7" +minCommandDelayMillis: 75 From 1e0f579327aff0533dbbcf07b83bf054ca3a5d14 Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 01:50:34 +0100 Subject: [PATCH 03/17] Make the last command execution map more consistent with other code --- .../pw/kaboom/extras/modules/player/PlayerChat.java | 6 +++--- .../kaboom/extras/modules/player/PlayerCommand.java | 13 +++++++------ .../extras/modules/player/PlayerConnection.java | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java index 5bcf2704..7439867e 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java @@ -25,8 +25,8 @@ public final class PlayerChat implements Listener { void onAsyncChatEventProcess(final AsyncChatEvent event) { final UUID playerUuid = event.getPlayer().getUniqueId(); - if (PlayerCommand.getCommandMillisList().get(playerUuid) != null) { - final long lastCommandTime = PlayerCommand.getCommandMillisList().get(playerUuid); + if (PlayerCommand.getLastCommandExec().get(playerUuid) != null) { + final long lastCommandTime = PlayerCommand.getLastCommandExec().get(playerUuid); final long millisDifference = System.currentTimeMillis() - lastCommandTime; if (millisDifference < 50) { @@ -35,7 +35,7 @@ void onAsyncChatEventProcess(final AsyncChatEvent event) { } } - PlayerCommand.getCommandMillisList().put(playerUuid, System.currentTimeMillis()); + PlayerCommand.getLastCommandExec().put(playerUuid, System.currentTimeMillis()); } @EventHandler(priority = EventPriority.MONITOR) diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerCommand.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerCommand.java index 3d3c3b48..4d3ed140 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerCommand.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerCommand.java @@ -1,6 +1,7 @@ package pw.kaboom.extras.modules.player; import java.util.HashMap; +import java.util.Map; import java.util.UUID; import io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent; @@ -15,7 +16,7 @@ import pw.kaboom.extras.modules.server.ServerCommand; public final class PlayerCommand implements Listener { - private static HashMap commandMillisList = new HashMap(); + private static final Map LAST_COMMAND_EXEC = new HashMap<>(); private static final long MIN_COMMAND_DELAY_MILLIS = JavaPlugin.getPlugin(Main.class) .getConfig() .getLong("minCommandDelayMillis"); @@ -24,8 +25,8 @@ public final class PlayerCommand implements Listener { void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) { final UUID playerUuid = event.getPlayer().getUniqueId(); - if (getCommandMillisList().get(playerUuid) != null) { - final long lastCommandTime = getCommandMillisList().get(playerUuid); + if (getLastCommandExec().get(playerUuid) != null) { + final long lastCommandTime = getLastCommandExec().get(playerUuid); final long millisDifference = System.currentTimeMillis() - lastCommandTime; if (millisDifference < MIN_COMMAND_DELAY_MILLIS) { @@ -34,7 +35,7 @@ void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) { } } - getCommandMillisList().put(playerUuid, System.currentTimeMillis()); + getLastCommandExec().put(playerUuid, System.currentTimeMillis()); final CommandSender sender = event.getPlayer(); final String command = event.getMessage(); @@ -55,7 +56,7 @@ void onPlayerSignCommandPreprocess(final PlayerSignCommandPreprocessEvent event) this.onPlayerCommandPreprocess(event); } - public static HashMap getCommandMillisList() { - return commandMillisList; + public static Map getLastCommandExec() { + return LAST_COMMAND_EXEC; } } diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java index dc3d58db..c9fc4377 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java @@ -180,7 +180,7 @@ void onPlayerSpawn(final AsyncPlayerSpawnLocationEvent event) { @EventHandler void onPlayerQuit(final PlayerQuitEvent event) { - PlayerCommand.getCommandMillisList().remove(event.getPlayer().getUniqueId()); + PlayerCommand.getLastCommandExec().remove(event.getPlayer().getUniqueId()); //PlayerInteract.interactMillisList.remove(event.getPlayer().getUniqueId()); ServerTabComplete.getLoginNameList().remove(event.getPlayer().getUniqueId()); } From 0d23515e6f174dc62fdcd076b9ed2e00bc65427c Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 01:51:34 +0100 Subject: [PATCH 04/17] Make minimum chat delay configurable Closes #352 --- .../java/pw/kaboom/extras/modules/player/PlayerChat.java | 7 ++++++- src/main/resources/config.yml | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java index 7439867e..bee128e0 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java @@ -12,6 +12,8 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.plugin.java.JavaPlugin; +import pw.kaboom.extras.Main; import javax.annotation.Nonnull; import java.io.IOException; @@ -20,6 +22,9 @@ public final class PlayerChat implements Listener { private static final PlayerChatRenderer CHAT_RENDERER = new PlayerChatRenderer(); + private static final long MIN_CHAT_DELAY_MILLIS = JavaPlugin.getPlugin(Main.class) + .getConfig() + .getLong("minChatDelayMillis"); @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) void onAsyncChatEventProcess(final AsyncChatEvent event) { @@ -29,7 +34,7 @@ void onAsyncChatEventProcess(final AsyncChatEvent event) { final long lastCommandTime = PlayerCommand.getLastCommandExec().get(playerUuid); final long millisDifference = System.currentTimeMillis() - lastCommandTime; - if (millisDifference < 50) { + if (millisDifference < MIN_CHAT_DELAY_MILLIS) { event.setCancelled(true); return; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index a65387a5..1d92a71b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -20,3 +20,4 @@ playerJoinTitleFadeOut: 50 opTag: "§4§l[§c§lOP§4§l] §c" deOpTag: "§8§l[§7§lDeOP§8§l] §7" minCommandDelayMillis: 75 +minChatDelayMillis: 50 \ No newline at end of file From 14cc9138a7023164eb758cd09956aca7bdffa734 Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 01:52:47 +0100 Subject: [PATCH 05/17] Make flatland world generation configurable Closes #360 --- src/main/java/pw/kaboom/extras/Main.java | 7 ++++--- src/main/resources/config.yml | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/Main.java b/src/main/java/pw/kaboom/extras/Main.java index 3e23caa9..a4258f35 100644 --- a/src/main/java/pw/kaboom/extras/Main.java +++ b/src/main/java/pw/kaboom/extras/Main.java @@ -87,9 +87,10 @@ public void onEnable() { this.getServer().getPluginManager().registerEvents(new ServerTabComplete(), this); /* Custom worlds */ - this.getServer().createWorld( - new WorldCreator("world_flatlands").generateStructures(false).type(WorldType.FLAT) - ); + if (this.getConfig().getBoolean("generateFlatlands")) + this.getServer().createWorld( + new WorldCreator("world_flatlands").generateStructures(false).type(WorldType.FLAT) + ); final Messenger messenger = this.getServer().getMessenger(); final PlayerMessaging playerMessaging = new PlayerMessaging(this); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 1d92a71b..d728fbb4 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -11,6 +11,7 @@ randomizeSpawn: false maxEntitiesPerChunk: 50 maxEntitiesPerWorld: 5120 maxTntsPerWorld: 1024 +generateFlatlands: true playerJoinSendTitle: true playerJoinTitle: "§7Welcome to Kaboom!" playerJoinSubtitle: "Free OP • Anarchy • Creative" From 438be340a6163bc79e34d07ab39d15d922d5f92d Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:09:46 +0100 Subject: [PATCH 06/17] Allow commands blocked in execute to be configured Lots of people ask for summon to be unblocked in execute, so this commit allows them to unblock it on their own clones without needing to modify Extras. Unfortunately, if we want to continue to use Bukkit's built in configuration system, we must keep the blockedInExecute lists synced between config.yml and ServerCommand.java. The config in the kaboomserver/server repo SHOULD NOT have the list synced though, and instead it should be absent entirely to prevent unwanted overriding of what should actually be blocked in execute. --- .../extras/modules/server/ServerCommand.java | 31 ++++++++++++------- src/main/resources/config.yml | 24 +++++++++++++- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/server/ServerCommand.java b/src/main/java/pw/kaboom/extras/modules/server/ServerCommand.java index a2dac790..de807199 100644 --- a/src/main/java/pw/kaboom/extras/modules/server/ServerCommand.java +++ b/src/main/java/pw/kaboom/extras/modules/server/ServerCommand.java @@ -1,6 +1,5 @@ package pw.kaboom.extras.modules.server; -import com.google.common.collect.ImmutableSet; import org.bukkit.block.CommandBlock; import org.bukkit.command.BlockCommandSender; import org.bukkit.command.CommandSender; @@ -11,9 +10,7 @@ import org.bukkit.plugin.java.JavaPlugin; import pw.kaboom.extras.Main; -import java.util.Arrays; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -21,13 +18,22 @@ public final class ServerCommand implements Listener { private static final Pattern SELECTOR_PATTERN = Pattern.compile("(?>\\s)*@[aenprs](?>\\s)*"); - private static final Logger LOGGER = JavaPlugin.getPlugin(Main.class).getLogger(); - - private static final Set BLOCKED_EXECUTE_COMMANDS = ImmutableSet.of( - "clone", "fill", "give", "kick", "locate", "me", "msg", "save-all", "say", - "spawnpoint", "spreadplayers", "summon", "teammsg", "teleport", "tell", "tellraw", - "tm", "tp", "w", "fillbiome", "ride"); - + private static final Main PLUGIN = JavaPlugin.getPlugin(Main.class); + private static final Logger LOGGER = PLUGIN.getLogger(); + + // Must be kept in sync with the blocked execute command list in config.yml + @SuppressWarnings("unchecked") + private static final Set BLOCKED_EXECUTE_COMMANDS = new HashSet<>( + (List) + PLUGIN.getConfig().getList( + "blockedInExecute", + Arrays.asList( + "clone", "fill", "give", "kick", "locate", "me", "msg", "save-all", + "say", "spawnpoint", "spreadplayers", "summon", "teammsg", "teleport", + "tell", "tellraw", "tm", "tp", "w", "fillbiome", "ride" + ) + ) + ); private static String checkSelectors(final String[] arr, final int offset) { final String[] args = Arrays.copyOfRange(arr, offset, arr.length); final String str = String.join(" ", args); @@ -76,7 +82,8 @@ public static String checkCommand(final CommandSender sender, final String comma } for (int i = 1; i < arr.length; i++) { - if ("summon".equalsIgnoreCase(arr[i])) { + if (BLOCKED_EXECUTE_COMMANDS.contains("summon") + && "summon".equalsIgnoreCase(arr[i])) { return "cancel"; } if (!"run".equalsIgnoreCase(arr[i])) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index d728fbb4..fd7000af 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -21,4 +21,26 @@ playerJoinTitleFadeOut: 50 opTag: "§4§l[§c§lOP§4§l] §c" deOpTag: "§8§l[§7§lDeOP§8§l] §7" minCommandDelayMillis: 75 -minChatDelayMillis: 50 \ No newline at end of file +minChatDelayMillis: 50 +blockedInExecute: + - clone + - fill + - give + - kick + - locate + - me + - msg + - save-all + - say + - spawnpoint + - spreadplayers + - summon + - teammsg + - teleport + - tell + - tellraw + - tm + - tp + - w + - fillbiome + - ride \ No newline at end of file From a1159bd544238e4ca6dcef0c818dd9bf73b9f18e Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:14:59 +0100 Subject: [PATCH 07/17] Allow maximum prefix length to be configured --- src/main/java/pw/kaboom/extras/commands/CommandPrefix.java | 6 +++++- src/main/resources/config.yml | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/pw/kaboom/extras/commands/CommandPrefix.java b/src/main/java/pw/kaboom/extras/commands/CommandPrefix.java index e2f92da3..5a4e1c11 100644 --- a/src/main/java/pw/kaboom/extras/commands/CommandPrefix.java +++ b/src/main/java/pw/kaboom/extras/commands/CommandPrefix.java @@ -6,12 +6,16 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import pw.kaboom.extras.Main; import pw.kaboom.extras.modules.player.PlayerPrefix; import javax.annotation.Nonnull; public final class CommandPrefix implements CommandExecutor { - private static final int MAX_PREFIX_LENGTH = 1024; + private static final int MAX_PREFIX_LENGTH = JavaPlugin.getPlugin(Main.class) + .getConfig() + .getInt("maxPrefixLength"); public boolean onCommand(final @Nonnull CommandSender sender, final @Nonnull Command cmd, diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index fd7000af..aefc34ea 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -22,6 +22,7 @@ opTag: "§4§l[§c§lOP§4§l] §c" deOpTag: "§8§l[§7§lDeOP§8§l] §7" minCommandDelayMillis: 75 minChatDelayMillis: 50 +maxPrefixLength: 1024 blockedInExecute: - clone - fill From 8f1ff74c5710765dd3acb7b4c5bd53d91c61ece9 Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:16:22 +0100 Subject: [PATCH 08/17] Allow per-world dragon limit to be configured --- .../java/pw/kaboom/extras/modules/entity/EntitySpawn.java | 4 ++-- src/main/resources/config.yml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java index 2b239c39..30bd2e45 100644 --- a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java +++ b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java @@ -42,6 +42,7 @@ public final class EntitySpawn implements Listener { private static final int MAX_ENTITIES_PER_CHUNK = CONFIG.getInt("maxEntitiesPerChunk"); public static final int MAX_ENTITIES_PER_WORLD = CONFIG.getInt("maxEntitiesPerWorld"); private static final int MAX_TNTS_PER_WORLD = CONFIG.getInt("maxTntsPerWorld"); + private static final int MAX_DRAGONS_PER_WORLD = CONFIG.getInt("maxDragonsPerWorld"); private void applyEntityChanges(final Entity entity) { switch (entity.getType()) { @@ -84,9 +85,8 @@ private boolean isEntityLimitReached(final EntityType entityType, final Chunk ch switch (entityType) { case ENDER_DRAGON: final int worldDragonCount = world.getEntitiesByClass(EnderDragon.class).size(); - final int worldDragonCountLimit = 24; - if (worldDragonCount >= worldDragonCountLimit) { + if (worldDragonCount >= MAX_DRAGONS_PER_WORLD) { return true; } break; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index aefc34ea..43bc6218 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -11,6 +11,7 @@ randomizeSpawn: false maxEntitiesPerChunk: 50 maxEntitiesPerWorld: 5120 maxTntsPerWorld: 1024 +maxDragonsPerWorld: 24 generateFlatlands: true playerJoinSendTitle: true playerJoinTitle: "§7Welcome to Kaboom!" From f1dd4ba99bef5bd0750822896c892bdc3e5c604c Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:18:43 +0100 Subject: [PATCH 09/17] Add a maximum amount of withers They are very destructive, and also very loud. Current limit is set to 128, but it might need to be increased/decreased accordingly. --- .../extras/modules/entity/EntitySpawn.java | 18 +++++++++--------- src/main/resources/config.yml | 1 + 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java index 30bd2e45..f977ce15 100644 --- a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java +++ b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java @@ -9,15 +9,7 @@ import org.bukkit.attribute.AttributeInstance; import org.bukkit.block.CreatureSpawner; import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.entity.AreaEffectCloud; -import org.bukkit.entity.EnderDragon; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.LightningStrike; -import org.bukkit.entity.Slime; -import org.bukkit.entity.TNTPrimed; -import org.bukkit.entity.Vehicle; +import org.bukkit.entity.*; import org.bukkit.entity.minecart.ExplosiveMinecart; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -43,6 +35,7 @@ public final class EntitySpawn implements Listener { public static final int MAX_ENTITIES_PER_WORLD = CONFIG.getInt("maxEntitiesPerWorld"); private static final int MAX_TNTS_PER_WORLD = CONFIG.getInt("maxTntsPerWorld"); private static final int MAX_DRAGONS_PER_WORLD = CONFIG.getInt("maxDragonsPerWorld"); + private static final int MAX_WITHERS_PER_WORLD = CONFIG.getInt("maxWithersPerWorld"); private void applyEntityChanges(final Entity entity) { switch (entity.getType()) { @@ -90,6 +83,13 @@ private boolean isEntityLimitReached(final EntityType entityType, final Chunk ch return true; } break; + case WITHER: + final int worldWitherCount = world.getEntitiesByClass(Wither.class).size(); + + if (worldWitherCount >= MAX_WITHERS_PER_WORLD) { + return true; + } + break; case TNT: final int worldTntCount = world.getEntitiesByClass(TNTPrimed.class).size(); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 43bc6218..10e1fc49 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -12,6 +12,7 @@ maxEntitiesPerChunk: 50 maxEntitiesPerWorld: 5120 maxTntsPerWorld: 1024 maxDragonsPerWorld: 24 +maxWithersPerWorld: 128 generateFlatlands: true playerJoinSendTitle: true playerJoinTitle: "§7Welcome to Kaboom!" From 03c477c1b189ab8fbfb6e8cbbbc561d7bffe8cc8 Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:20:43 +0100 Subject: [PATCH 10/17] Allow explosion radius & max fireball count to be configured --- .../extras/modules/entity/EntityExplosion.java | 17 +++++++++++------ src/main/resources/config.yml | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/entity/EntityExplosion.java b/src/main/java/pw/kaboom/extras/modules/entity/EntityExplosion.java index 69d7ba2e..56f1bcf6 100644 --- a/src/main/java/pw/kaboom/extras/modules/entity/EntityExplosion.java +++ b/src/main/java/pw/kaboom/extras/modules/entity/EntityExplosion.java @@ -1,24 +1,29 @@ package pw.kaboom.extras.modules.entity; import org.bukkit.World; +import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Fireball; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.ExplosionPrimeEvent; +import org.bukkit.plugin.java.JavaPlugin; +import pw.kaboom.extras.Main; public final class EntityExplosion implements Listener { + private static final FileConfiguration CONFIG = JavaPlugin.getPlugin(Main.class).getConfig(); + + private static final int MAX_EXPLOSION_RADIUS = CONFIG.getInt("maxExplosionRadius"); + private static final int MAX_FIREBALL_COUNT = CONFIG.getInt("maxFireballCount"); + @EventHandler void onExplosionPrime(final ExplosionPrimeEvent event) { - final int maxRadius = 20; - - if (event.getRadius() > maxRadius) { - event.setRadius(maxRadius); + if (event.getRadius() > MAX_EXPLOSION_RADIUS) { + event.setRadius(MAX_EXPLOSION_RADIUS); } final World world = event.getEntity().getWorld(); - final int maxFireballCount = 30; - if (world.getEntitiesByClass(Fireball.class).size() > maxFireballCount + if (world.getEntitiesByClass(Fireball.class).size() > MAX_FIREBALL_COUNT && event.getRadius() > 1) { event.setRadius(1); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 10e1fc49..b894b27d 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -13,6 +13,8 @@ maxEntitiesPerWorld: 5120 maxTntsPerWorld: 1024 maxDragonsPerWorld: 24 maxWithersPerWorld: 128 +maxFireballCount: 30 +maxExplosionRadius: 20 generateFlatlands: true playerJoinSendTitle: true playerJoinTitle: "§7Welcome to Kaboom!" From 7cbe56aade900c3f2b1a5010fd29ee3b3da0c983 Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:22:04 +0100 Subject: [PATCH 11/17] Allow per-world TNT minecart limit to be configured --- src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java | 3 ++- src/main/resources/config.yml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java index f977ce15..d51a47a7 100644 --- a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java +++ b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java @@ -36,6 +36,7 @@ public final class EntitySpawn implements Listener { private static final int MAX_TNTS_PER_WORLD = CONFIG.getInt("maxTntsPerWorld"); private static final int MAX_DRAGONS_PER_WORLD = CONFIG.getInt("maxDragonsPerWorld"); private static final int MAX_WITHERS_PER_WORLD = CONFIG.getInt("maxWithersPerWorld"); + private static final int MAX_TNT_MINECARTS_PER_WORLD = CONFIG.getInt("maxTntMinecartsPerWorld"); private void applyEntityChanges(final Entity entity) { switch (entity.getType()) { @@ -165,7 +166,7 @@ void onAreaEffectCloudApply(final AreaEffectCloudApplyEvent event) { void onExplosionPrime(final ExplosionPrimeEvent event) { if (EntityType.TNT_MINECART.equals(event.getEntityType()) && event.getEntity().getWorld() - .getEntitiesByClass(ExplosiveMinecart.class).size() > 80) { + .getEntitiesByClass(ExplosiveMinecart.class).size() > MAX_TNT_MINECARTS_PER_WORLD) { event.setCancelled(true); } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b894b27d..b73a9a3f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -13,6 +13,7 @@ maxEntitiesPerWorld: 5120 maxTntsPerWorld: 1024 maxDragonsPerWorld: 24 maxWithersPerWorld: 128 +maxTntMinecartsPerWorld: 80 maxFireballCount: 30 maxExplosionRadius: 20 generateFlatlands: true From 76a23637a2655c1439231aac0ed1339e0053f1f4 Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:27:57 +0100 Subject: [PATCH 12/17] Allow spawner limits to be configured --- .../extras/modules/entity/EntitySpawn.java | 24 +++++++------------ src/main/resources/config.yml | 3 +++ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java index d51a47a7..6fa0df1d 100644 --- a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java +++ b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java @@ -38,6 +38,11 @@ public final class EntitySpawn implements Listener { private static final int MAX_WITHERS_PER_WORLD = CONFIG.getInt("maxWithersPerWorld"); private static final int MAX_TNT_MINECARTS_PER_WORLD = CONFIG.getInt("maxTntMinecartsPerWorld"); + private static final int SPAWNER_MIN_SPAWN_DELAY = CONFIG.getInt("spawnerMinSpawnDelay"); + private static final int SPAWNER_MAX_SPAWN_COUNT = CONFIG.getInt("spawnerMaxSpawnCount"); + private static final int SPAWNER_MAX_SPAWN_RANGE = CONFIG.getInt("spawnerMaxSpawnRange"); + + private void applyEntityChanges(final Entity entity) { switch (entity.getType()) { case AREA_EFFECT_CLOUD: @@ -140,21 +145,10 @@ private void limitSpawner(final CreatureSpawner spawner) { spawner.setSpawnedType(EntityType.MINECART); } - if (spawner.getMinSpawnDelay() < 1000) { - spawner.setMinSpawnDelay(1000); - } - - if (spawner.getMaxSpawnDelay() < 1000) { - spawner.setMaxSpawnDelay(1000); - } - - if (spawner.getSpawnCount() > 200) { - spawner.setSpawnCount(200); - } - - if (spawner.getSpawnRange() > 50) { - spawner.setSpawnRange(50); - } + spawner.setMinSpawnDelay(Math.max(SPAWNER_MIN_SPAWN_DELAY, spawner.getMinSpawnDelay())); + spawner.setMaxSpawnDelay(Math.max(SPAWNER_MIN_SPAWN_DELAY, spawner.getMaxSpawnDelay())); + spawner.setSpawnCount(Math.min(SPAWNER_MAX_SPAWN_COUNT, spawner.getSpawnCount())); + spawner.setSpawnRange(Math.min(SPAWNER_MAX_SPAWN_RANGE, spawner.getSpawnRange())); } @EventHandler diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b73a9a3f..3c9da1a1 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -16,6 +16,9 @@ maxWithersPerWorld: 128 maxTntMinecartsPerWorld: 80 maxFireballCount: 30 maxExplosionRadius: 20 +spawnerMinSpawnDelay: 1000 +spawnerMaxSpawnCount: 200 +spawnerMaxSpawnRange: 50 generateFlatlands: true playerJoinSendTitle: true playerJoinTitle: "§7Welcome to Kaboom!" From fdc530ef5114de5a9d0407665613c170d2ba29ef Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:31:01 +0100 Subject: [PATCH 13/17] Allow area effect cloud limits to be configured --- .../extras/modules/entity/EntitySpawn.java | 23 ++++++++++--------- src/main/resources/config.yml | 3 +++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java index 6fa0df1d..5b568b25 100644 --- a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java +++ b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java @@ -42,6 +42,12 @@ public final class EntitySpawn implements Listener { private static final int SPAWNER_MAX_SPAWN_COUNT = CONFIG.getInt("spawnerMaxSpawnCount"); private static final int SPAWNER_MAX_SPAWN_RANGE = CONFIG.getInt("spawnerMaxSpawnRange"); + private static final int EFFECT_CLOUD_MAX_RADIUS = + CONFIG.getInt("effectCloudMaxRadius"); + private static final int EFFECT_CLOUD_MAX_RADIUS_ON_USE = + CONFIG.getInt("effectCloudMaxRadiusOnUse"); + private static final int EFFECT_CLOUD_MAX_RADIUS_PER_TICK = + CONFIG.getInt("effectCloudMaxRadiusPerTick"); private void applyEntityChanges(final Entity entity) { switch (entity.getType()) { @@ -117,17 +123,12 @@ private boolean isEntityLimitReached(final EntityType entityType, final Chunk ch } private void limitAreaEffectCloudRadius(final AreaEffectCloud cloud) { - if (cloud.getRadius() > 40) { - cloud.setRadius(40); - } - - if (cloud.getRadiusOnUse() > 0.01f) { - cloud.setRadiusOnUse(0.1f); - } - - if (cloud.getRadiusPerTick() > 0) { - cloud.setRadiusPerTick(0); - } + cloud.setRadius(Math.min(EFFECT_CLOUD_MAX_RADIUS, cloud.getRadius())); + cloud.setRadiusOnUse(Math.min(EFFECT_CLOUD_MAX_RADIUS_ON_USE, cloud.getRadiusPerTick())); + cloud.setRadiusPerTick(Math.min( + EFFECT_CLOUD_MAX_RADIUS_PER_TICK, + cloud.getRadiusPerTick()) + ); } private void limitSlimeSize(final Slime slime) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 3c9da1a1..8a8ed067 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -19,6 +19,9 @@ maxExplosionRadius: 20 spawnerMinSpawnDelay: 1000 spawnerMaxSpawnCount: 200 spawnerMaxSpawnRange: 50 +effectCloudMaxRadius: 40 +effectCloudMaxRadiusOnUse: 0.01 +effectCloudMaxRadiusPerTick: 0 generateFlatlands: true playerJoinSendTitle: true playerJoinTitle: "§7Welcome to Kaboom!" From 1558f51a91696d03099a0e39db8aa2996fe9a690 Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:31:46 +0100 Subject: [PATCH 14/17] Allow slime size limit to be configured --- .../java/pw/kaboom/extras/modules/entity/EntitySpawn.java | 7 +++++-- src/main/resources/config.yml | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java index 5b568b25..253a3000 100644 --- a/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java +++ b/src/main/java/pw/kaboom/extras/modules/entity/EntitySpawn.java @@ -49,6 +49,9 @@ public final class EntitySpawn implements Listener { private static final int EFFECT_CLOUD_MAX_RADIUS_PER_TICK = CONFIG.getInt("effectCloudMaxRadiusPerTick"); + private static final int MAX_SLIME_SIZE = + CONFIG.getInt("maxSlimeSize"); + private void applyEntityChanges(final Entity entity) { switch (entity.getType()) { case AREA_EFFECT_CLOUD: @@ -135,8 +138,8 @@ private void limitSlimeSize(final Slime slime) { final AttributeInstance scaleInstance = slime.getAttribute(Attribute.SCALE); final double scale = scaleInstance != null ? scaleInstance.getValue() : 1.0f; - if ((slime.getSize() * scale) > 20) { - slime.setSize(20); + if ((slime.getSize() * scale) > MAX_SLIME_SIZE) { + slime.setSize(MAX_SLIME_SIZE); Utility.resetAttribute(slime, Attribute.SCALE); } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 8a8ed067..c04e6e6e 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -22,6 +22,7 @@ spawnerMaxSpawnRange: 50 effectCloudMaxRadius: 40 effectCloudMaxRadiusOnUse: 0.01 effectCloudMaxRadiusPerTick: 0 +maxSlimeSize: 20 generateFlatlands: true playerJoinSendTitle: true playerJoinTitle: "§7Welcome to Kaboom!" From d74d8cfd3f267aadf5f7cb1585b7e70946ddc798 Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:33:01 +0100 Subject: [PATCH 15/17] Allow max knockback velocity to be configured --- .../pw/kaboom/extras/modules/entity/EntityKnockback.java | 7 ++++++- src/main/resources/config.yml | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/pw/kaboom/extras/modules/entity/EntityKnockback.java b/src/main/java/pw/kaboom/extras/modules/entity/EntityKnockback.java index b98fbf1b..a86cf5b6 100644 --- a/src/main/java/pw/kaboom/extras/modules/entity/EntityKnockback.java +++ b/src/main/java/pw/kaboom/extras/modules/entity/EntityKnockback.java @@ -4,10 +4,15 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.util.Vector; +import pw.kaboom.extras.Main; public final class EntityKnockback implements Listener { - private static final double KNOCKBACK_LIMIT = 20; // translates to enchantment level 40 + // default translates to enchantment level 40 + private static final double KNOCKBACK_LIMIT = JavaPlugin.getPlugin(Main.class) + .getConfig() + .getDouble("maxKnockbackVelocity"); private static final double KNOCKBACK_LIMIT_SQUARED = KNOCKBACK_LIMIT * KNOCKBACK_LIMIT; @EventHandler diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index c04e6e6e..4d7cb86c 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -23,6 +23,7 @@ effectCloudMaxRadius: 40 effectCloudMaxRadiusOnUse: 0.01 effectCloudMaxRadiusPerTick: 0 maxSlimeSize: 20 +maxKnockbackVelocity: 20 generateFlatlands: true playerJoinSendTitle: true playerJoinTitle: "§7Welcome to Kaboom!" From ee85058bb51bc8ce2d326f3fa9b9f30626183db0 Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:35:28 +0100 Subject: [PATCH 16/17] Allow spawn teleport radius to be configured Considering pregenerating 500,000 blocks with Chunky probably takes a while... --- .../kaboom/extras/modules/player/PlayerConnection.java | 10 ++++++---- src/main/resources/config.yml | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java b/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java index c9fc4377..5a46e6f5 100644 --- a/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java +++ b/src/main/java/pw/kaboom/extras/modules/player/PlayerConnection.java @@ -64,6 +64,9 @@ public final class PlayerConnection implements Listener { private static final boolean OP_ON_JOIN = CONFIG.getBoolean("opOnJoin"); private static final boolean RANDOMIZE_SPAWN = CONFIG.getBoolean("randomizeSpawn"); + private static final double RANDOMIZE_SPAWN_RADIUS = CONFIG.getDouble("randomizeSpawnRadius"); + private static final double RANDOMIZE_SPAWN_Y = CONFIG.getDouble("randomizeSpawnY"); + private static final EnumSet ALLOWED_KICK_CAUSES = EnumSet.of( PlayerKickEvent.Cause.TIMEOUT, PlayerKickEvent.Cause.INVALID_VEHICLE_MOVEMENT, PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT, @@ -167,12 +170,11 @@ void onPlayerSpawn(final AsyncPlayerSpawnLocationEvent event) { final World world = event.getSpawnLocation().getWorld(); final ThreadLocalRandom random = ThreadLocalRandom.current(); - final double teleportAmount = 500000D; final Location location = new Location( world, - random.nextDouble(-teleportAmount, teleportAmount), - 100, - random.nextDouble(-teleportAmount, teleportAmount) + random.nextDouble(-RANDOMIZE_SPAWN_RADIUS, RANDOMIZE_SPAWN_RADIUS), + RANDOMIZE_SPAWN_Y, + random.nextDouble(-RANDOMIZE_SPAWN_RADIUS, RANDOMIZE_SPAWN_RADIUS) ); event.setSpawnLocation(location); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 4d7cb86c..be346595 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -8,6 +8,8 @@ opOnJoin: true # versions. # You can use the pre-world generation plugin "Chunky" to achieve this. randomizeSpawn: false +randomizeSpawnRadius: 500000 +randomizeSpawnY: 100 maxEntitiesPerChunk: 50 maxEntitiesPerWorld: 5120 maxTntsPerWorld: 1024 From 5d6d6ae4574d5f13f86372fbade105cdd09e85a5 Mon Sep 17 00:00:00 2001 From: opt Date: Mon, 30 Mar 2026 02:44:39 +0100 Subject: [PATCH 17/17] Allow gamerule limits to be configured --- .../extras/modules/server/ServerGameRule.java | 18 +++++++++++++----- src/main/resources/config.yml | 5 +++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/pw/kaboom/extras/modules/server/ServerGameRule.java b/src/main/java/pw/kaboom/extras/modules/server/ServerGameRule.java index ac5b81c5..a31af643 100644 --- a/src/main/java/pw/kaboom/extras/modules/server/ServerGameRule.java +++ b/src/main/java/pw/kaboom/extras/modules/server/ServerGameRule.java @@ -4,8 +4,10 @@ import org.bukkit.Bukkit; import org.bukkit.GameRule; import org.bukkit.World; +import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitScheduler; import pw.kaboom.extras.Main; import pw.kaboom.extras.modules.entity.EntitySpawn; @@ -13,15 +15,21 @@ import java.util.Map; public final class ServerGameRule implements Listener { + private static final FileConfiguration CONFIG = JavaPlugin.getPlugin(Main.class).getConfig(); + private static final Map, ?> FORCED_GAMERULES = Map.of( - GameRule.COMMAND_BLOCKS_ENABLED, true, - GameRule.SPAWNER_BLOCKS_ENABLED, false + GameRule.COMMAND_BLOCKS_ENABLED, CONFIG.getBoolean("forceCommandBlocksTo"), + GameRule.SPAWNER_BLOCKS_ENABLED, CONFIG.getBoolean("forceSpawnerBlocksTo") ); + // TODO: Dynamic gamerule limits private static final Map, Integer> GAMERULE_LIMITS = Map.of( - GameRule.RANDOM_TICK_SPEED, 6, - GameRule.SPAWN_RADIUS, 100, - GameRule.COMMAND_MODIFICATION_BLOCK_LIMIT, 32768, + GameRule.RANDOM_TICK_SPEED, CONFIG.getInt("maxTickSpeed"), + GameRule.SPAWN_RADIUS, CONFIG.getInt("maxSpawnRadius"), + + GameRule.COMMAND_MODIFICATION_BLOCK_LIMIT, + CONFIG.getInt("maxCommandModificationBlockLimit"), + GameRule.MAX_COMMAND_FORK_COUNT, EntitySpawn.MAX_ENTITIES_PER_WORLD ); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index be346595..7056570f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -26,6 +26,11 @@ effectCloudMaxRadiusOnUse: 0.01 effectCloudMaxRadiusPerTick: 0 maxSlimeSize: 20 maxKnockbackVelocity: 20 +forceCommandBlocksTo: true +forceSpawnerBlocksTo: false +maxTickSpeed: 6 +maxSpawnRadius: 100 +maxCommandModificationBlockLimit: 32768 generateFlatlands: true playerJoinSendTitle: true playerJoinTitle: "§7Welcome to Kaboom!"