From bea5931eae57b9f71b5227e89055cd723723efc9 Mon Sep 17 00:00:00 2001 From: Smyler Date: Wed, 15 Oct 2025 22:49:34 +0200 Subject: [PATCH 1/8] Switch logging to the plugin component SL4J logger --- .../terraplusminus/Terraplusminus.java | 30 +++++++++---------- .../events/PlayerMoveEvent.java | 3 +- .../gen/tree/TreePopulator.java | 5 ++-- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java b/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java index b938d77..dcec6dd 100644 --- a/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java +++ b/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java @@ -36,10 +36,8 @@ import java.io.*; import java.util.List; import java.util.Locale; -import java.util.logging.Level; import static java.lang.String.format; -import static java.util.logging.Level.WARNING; import static net.daporkchop.lib.common.util.PValidation.checkState; public final class Terraplusminus extends JavaPlugin implements Listener { @@ -52,13 +50,13 @@ public void onEnable() { PluginDescriptionFile pdf = this.getDescription(); String pluginVersion = pdf.getVersion(); - getLogger().log(Level.INFO, "\n╭━━━━╮\n" + + this.getComponentLogger().info("\n╭━━━━╮\n" + "┃╭╮╭╮┃\n" + "╰╯┃┃┣┻━┳━┳━┳━━╮╭╮\n" + "╱╱┃┃┃┃━┫╭┫╭┫╭╮┣╯╰┳━━╮\n" + "╱╱┃┃┃┃━┫┃┃┃┃╭╮┣╮╭┻━━╯\n" + "╱╱╰╯╰━━┻╯╰╯╰╯╰╯╰╯\n" + - "Version: " + pluginVersion); + "Version: {}", pluginVersion); // Config ------------------] ConfigurationSerialization.registerClass(ConfigurationSerializable.class); @@ -93,7 +91,7 @@ public void onEnable() { registerCommands(); - Bukkit.getLogger().log(Level.INFO, "[T+-] Terraplusminus successfully enabled"); + this.getComponentLogger().info("Terraplusminus successfully enabled"); } @Override @@ -103,7 +101,7 @@ public void onDisable() { this.getServer().getMessenger().unregisterIncomingPluginChannel(this); // -------------------------- - Bukkit.getLogger().log(Level.INFO, "[T+-] Plugin deactivated"); + this.getComponentLogger().info("Plugin deactivated"); } @EventHandler @@ -143,7 +141,7 @@ public void copyFileFromResource(String resourcePath, File destination) { try { out = new FileOutputStream(destination); } catch (FileNotFoundException e) { - Bukkit.getLogger().log(Level.SEVERE, "[T+-] " + destination.getName() + " not found"); + this.getComponentLogger().error("{} not found", destination.getName()); throw new RuntimeException(e); } byte[] buf = new byte[1024]; @@ -153,13 +151,13 @@ public void copyFileFromResource(String resourcePath, File destination) { out.write(buf, 0, len); } } catch (IOException io) { - Bukkit.getLogger().log(Level.SEVERE, "[T+-] Could not copy " + destination); + this.getComponentLogger().error("Could not copy {}", destination); } finally { try { out.close(); if (resourcePath.equals("world-height-datapack.zip")) { - Bukkit.getLogger().log(Level.CONFIG, "[T+-] Copied datapack to world folder"); - Bukkit.getLogger().log(Level.SEVERE, "[T+-] Stopping server to start again with datapack"); + this.getComponentLogger().info("Copied datapack to world folder"); + this.getComponentLogger().error("Stopping server to start again with datapack"); Bukkit.getServer().shutdown(); } } catch (IOException e) { @@ -176,7 +174,7 @@ private void updateConfig() { configVersion = this.config.getDouble("config_version"); } catch (Exception e) { e.printStackTrace(); - Bukkit.getLogger().log(Level.SEVERE, "[T+-] Old config detected. Please delete and restart/reload."); + this.getComponentLogger().error("Old config detected. Please delete and restart/reload."); } if (configVersion == 1.0) { String passthroughTpll = Terraplusminus.config.getString("passthrough_tpll"); @@ -281,7 +279,7 @@ private void setupTerraMinusMinus() { Disk.setCacheRoot(this.getDataPath().resolve("cache").toFile()); String userAgent = this.createHttpUserAgent(); - this.getLogger().fine("Terraplusminus HTTP user agent: " + userAgent); + this.getComponentLogger().debug("Terraplusminus HTTP user agent: {}", userAgent); Http.userAgent(userAgent); } @@ -300,19 +298,19 @@ private String createHttpUserAgent() { private void extractTerraConfigFileToPluginDir(@NotNull String resourcePath, @NotNull String dropPath) { File droppedFile = this.getDataPath().resolve(dropPath).toFile(); if (droppedFile.exists()) { - this.getLogger().fine("Terra-- config file " + droppedFile.getAbsolutePath() + " is already present in plugin directory"); + this.getComponentLogger().debug("Terra-- config file {} is already present in plugin directory", droppedFile.getAbsolutePath()); return; } if(droppedFile.getParentFile().mkdirs()) { - this.getLogger().fine("Created parent directory before extracting Terra-- configuration to: " + droppedFile.getAbsolutePath()); + this.getComponentLogger().trace("Created parent directory before extracting Terra-- configuration to: {}", droppedFile.getAbsolutePath()); } try (InputStream resourceStream = this.getClass().getResourceAsStream(resourcePath); OutputStream fileStream = new FileOutputStream(droppedFile)) { checkState(resourceStream != null, "Missing internal resource: %s", resourcePath); resourceStream.transferTo(fileStream); } catch (IOException e) { - this.getLogger().log(WARNING, "Failed to drop a Terra configuration file in plugin directory", e); + this.getComponentLogger().warn("Failed to drop a Terra configuration file in plugin directory", e); } - this.getLogger().info("Created default Terra-- configuration at " + droppedFile.getAbsolutePath()); + this.getComponentLogger().info("Created default Terra-- configuration at {}", droppedFile.getAbsolutePath()); } } \ No newline at end of file diff --git a/src/main/java/de/btegermany/terraplusminus/events/PlayerMoveEvent.java b/src/main/java/de/btegermany/terraplusminus/events/PlayerMoveEvent.java index 787f440..b3dbdd7 100644 --- a/src/main/java/de/btegermany/terraplusminus/events/PlayerMoveEvent.java +++ b/src/main/java/de/btegermany/terraplusminus/events/PlayerMoveEvent.java @@ -19,7 +19,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.logging.Level; import static java.lang.String.valueOf; import static org.bukkit.ChatColor.BOLD; @@ -54,7 +53,7 @@ public PlayerMoveEvent(Plugin plugin) { for (LinkedWorld world : worlds) { this.worldHashMap.put(world.getWorldName(), world.getOffset()); } - Bukkit.getLogger().log(Level.INFO, "[T+-] Linked worlds enabled, using Multiverse method."); + Terraplusminus.instance.getComponentLogger().info("Linked worlds enabled, using Multiverse method."); } /* else { for (World world : Bukkit.getServer().getWorlds()) { // plugin loaded before worlds initialized, so that does not work diff --git a/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java b/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java index 4aa61cd..8ba7f37 100644 --- a/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java +++ b/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java @@ -35,7 +35,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import java.util.logging.Level; public class TreePopulator extends BlockPopulator { @@ -74,7 +73,7 @@ public TreePopulator(CustomBiomeProvider customBiomeProvider, int yOffset) { trees.put(treeSizes.getKey(), new ArrayList<>()); - Bukkit.getLogger().log(Level.INFO, "[T+-] Loading Tree Type " + treeSizes.getKey()); + Terraplusminus.instance.getComponentLogger().info("Loading Tree Type {}", treeSizes.getKey()); treeSizes.getValue().getAsJsonObject().entrySet().forEach(treeNames -> { @@ -97,7 +96,7 @@ public TreePopulator(CustomBiomeProvider customBiomeProvider, int yOffset) { }); }); - Bukkit.getLogger().log(Level.INFO, "[T+-] Finished loading " + treeCount[0] + " custom trees"); + Terraplusminus.instance.getComponentLogger().info("Finished loading {} custom trees", treeCount[0]); } From a77906f0adf9359c63254a8e9a08c2bd3b816efb Mon Sep 17 00:00:00 2001 From: Smyler Date: Sun, 19 Oct 2025 08:59:06 +0200 Subject: [PATCH 2/8] Refactored datapack installation --- .../terraplusminus/Terraplusminus.java | 66 +++++++++---------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java b/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java index dcec6dd..600a751 100644 --- a/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java +++ b/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java @@ -21,6 +21,7 @@ import net.buildtheearth.terraminusminus.util.http.Disk; import net.buildtheearth.terraminusminus.util.http.Http; import org.bukkit.Bukkit; +import org.bukkit.World; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.configuration.serialization.ConfigurationSerialization; @@ -34,6 +35,7 @@ import org.jetbrains.annotations.NotNull; import java.io.*; +import java.nio.file.Path; import java.util.List; import java.util.Locale; @@ -106,14 +108,13 @@ public void onDisable() { @EventHandler public void onWorldInit(WorldInitEvent event) { - String datapackName = "world-height-datapack.zip"; - File datapackPath = new File(event.getWorld().getWorldFolder() + File.separator + "datapacks" + File.separator + datapackName); - if (Terraplusminus.config.getBoolean("height_datapack")) { - if (!event.getWorld().getName().contains("_nether") && !event.getWorld().getName().contains("_the_end")) { //event.getWorld().getGenerator() is null here - if (!datapackPath.exists()) { - copyFileFromResource(datapackName, datapackPath); - } - } + World world = event.getWorld(); + boolean shouldInstallHeightDatapack = Terraplusminus.config.getBoolean("height_datapack"); + boolean isDefaultWorld = Bukkit.getWorlds().getFirst().getUID().equals(world.getUID()); + if (shouldInstallHeightDatapack && isDefaultWorld) { + // Datapacks should be installed in the default world and will apply to all of them. + // Getting the default world this way is reliable according to https://www.spigotmc.org/threads/ask-getting-the-servers-main-world.349626/#post-3238378 + this.enforceDatapackInstallation("world-height-datapack.zip", world); } } @@ -135,35 +136,32 @@ public ChunkGenerator getDefaultWorldGenerator(@NotNull String worldName, String } - public void copyFileFromResource(String resourcePath, File destination) { - InputStream in = getResource(resourcePath); - OutputStream out; - try { - out = new FileOutputStream(destination); - } catch (FileNotFoundException e) { - this.getComponentLogger().error("{} not found", destination.getName()); - throw new RuntimeException(e); + public void enforceDatapackInstallation(String datapackResourcePath, World world) { + String datapackName = Path.of(datapackResourcePath).getFileName().toString(); + File droppedFile = world + .getWorldFolder().toPath() + .resolve("datapacks") + .resolve(datapackName) + .toFile(); + if (droppedFile.exists()) { + this.getComponentLogger().debug("Datapack {} was already installed in world {}", datapackName, world.getName()); + return; } - byte[] buf = new byte[1024]; - int len; - try { - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } + try(InputStream in = this.getResource(datapackResourcePath); OutputStream out = new FileOutputStream(droppedFile)) { + checkState(in != null, "Missing internal resource: %s", datapackResourcePath); + in.transferTo(out); } catch (IOException io) { - this.getComponentLogger().error("Could not copy {}", destination); - } finally { - try { - out.close(); - if (resourcePath.equals("world-height-datapack.zip")) { - this.getComponentLogger().info("Copied datapack to world folder"); - this.getComponentLogger().error("Stopping server to start again with datapack"); - Bukkit.getServer().shutdown(); - } - } catch (IOException e) { - e.printStackTrace(); - } + this.getComponentLogger().error( + "Failed to extract datapack from resource '{}' to '{}'", + datapackResourcePath, droppedFile.getAbsolutePath() + ); + throw new RuntimeException(io); } + this.getComponentLogger().error( + "Datapack {} was missing from world {} and has been automatically installed by Terraplusminus. The server needs to be manually restarted for the change to take effect. Terraplusminus will now shutdown the server so it can be restarted.", + datapackName, world.getName() + ); + Bukkit.getServer().shutdown(); } private void updateConfig() { From 6f8163376467d655dc85bf8f7e038cc601737ba7 Mon Sep 17 00:00:00 2001 From: Smyler Date: Sun, 19 Oct 2025 10:36:07 +0200 Subject: [PATCH 3/8] Get rid of trivial calls to Exception#printStackTrace() --- .../btegermany/terraplusminus/Terraplusminus.java | 10 ++++------ .../terraplusminus/events/PluginMessageEvent.java | 4 +++- .../terraplusminus/gen/CustomBiomeProvider.java | 14 +++++++++++--- .../terraplusminus/gen/tree/TreePopulator.java | 13 +++++++++++-- .../terraplusminus/utils/FileBuilder.java | 9 ++++++--- 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java b/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java index 600a751..6d083ce 100644 --- a/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java +++ b/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java @@ -165,13 +165,11 @@ public void enforceDatapackInstallation(String datapackResourcePath, World world } private void updateConfig() { - FileBuilder fileBuilder = new FileBuilder(this); + new FileBuilder(this); // Sets FileBuilder#plugin (static field) - Double configVersion = null; - try { - configVersion = this.config.getDouble("config_version"); - } catch (Exception e) { - e.printStackTrace(); + double configVersion = this.config.getDouble("config_version"); + + if (configVersion == 0.0) { // That's the default value if the field was not set at all in the YAML this.getComponentLogger().error("Old config detected. Please delete and restart/reload."); } if (configVersion == 1.0) { diff --git a/src/main/java/de/btegermany/terraplusminus/events/PluginMessageEvent.java b/src/main/java/de/btegermany/terraplusminus/events/PluginMessageEvent.java index 5597f9e..e912c13 100644 --- a/src/main/java/de/btegermany/terraplusminus/events/PluginMessageEvent.java +++ b/src/main/java/de/btegermany/terraplusminus/events/PluginMessageEvent.java @@ -1,5 +1,6 @@ package de.btegermany.terraplusminus.events; +import de.btegermany.terraplusminus.Terraplusminus; import de.btegermany.terraplusminus.utils.PlayerHashMapManagement; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -11,6 +12,7 @@ import java.io.IOException; import java.util.UUID; + public class PluginMessageEvent implements PluginMessageListener { PlayerHashMapManagement playerHashMapManagement; @@ -35,7 +37,7 @@ public void onPluginMessageReceived(@NotNull String channel, @NotNull Player pla targetPlayer.chat("/tpll " + coordinates); } } catch (IOException e) { - e.printStackTrace(); + Terraplusminus.instance.getComponentLogger().warn("Failed to read plugin message", e); } } } diff --git a/src/main/java/de/btegermany/terraplusminus/gen/CustomBiomeProvider.java b/src/main/java/de/btegermany/terraplusminus/gen/CustomBiomeProvider.java index 1fe943c..b1902a8 100644 --- a/src/main/java/de/btegermany/terraplusminus/gen/CustomBiomeProvider.java +++ b/src/main/java/de/btegermany/terraplusminus/gen/CustomBiomeProvider.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.concurrent.ExecutionException; + public class CustomBiomeProvider extends BiomeProvider { private final KoppenClimateData climateData = new KoppenClimateData(); @@ -45,9 +46,16 @@ public Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { try { biomeData = this.climateData.getAsync(coords[0], coords[1]).get(); return koppenDataToBukkitBiome(biomeData); - } catch (InterruptedException | ExecutionException | OutOfProjectionBoundsException e) { - e.printStackTrace(); - + } catch (OutOfProjectionBoundsException silenced) { + // This is not an issue, + // we can't be expected to supply a realistic biome for a place that does not exist on Earth + } catch (InterruptedException | ExecutionException e) { + Terraplusminus.instance.getComponentLogger().warn( + "Exception when generating biome at position {}/{}/{} in world {}", + x, y, z, + worldInfo.getName(), + e + ); } } else biomeData = 8; // Default is plains for tree generation return parseDefaultBiome(); diff --git a/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java b/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java index 8ba7f37..cf4c151 100644 --- a/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java +++ b/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java @@ -36,6 +36,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; + public class TreePopulator extends BlockPopulator { public static final Cached RNG_CACHE = Cached.threadLocal(() -> new byte[16 * 16], ReferenceStrength.SOFT); @@ -125,7 +126,10 @@ public void populate(@NotNull WorldInfo worldInfo, @NotNull Random random, int x waterY = data.waterHeight(valueX, valueZ); state = data.surfaceBlock(valueX, valueZ); } catch (IndexOutOfBoundsException e) { - e.printStackTrace(); + Terraplusminus.instance.getComponentLogger().warn( + "Chunk boundary overflow when attempting to generate a tree at chunk {}/{}", + x, z + ); } if (groundY < waterY) { @@ -158,7 +162,12 @@ public void populate(@NotNull WorldInfo worldInfo, @NotNull Random random, int x } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); + Terraplusminus.instance.getComponentLogger().warn( + "Exception when generating trees in chunk {}/{} in world {}", + x, z, + worldInfo.getName(), + e + ); } } } diff --git a/src/main/java/de/btegermany/terraplusminus/utils/FileBuilder.java b/src/main/java/de/btegermany/terraplusminus/utils/FileBuilder.java index a649d0d..528b8e0 100644 --- a/src/main/java/de/btegermany/terraplusminus/utils/FileBuilder.java +++ b/src/main/java/de/btegermany/terraplusminus/utils/FileBuilder.java @@ -1,5 +1,6 @@ package de.btegermany.terraplusminus.utils; +import de.btegermany.terraplusminus.Terraplusminus; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; @@ -10,6 +11,8 @@ import java.util.List; import java.util.Set; +import static java.util.logging.Level.SEVERE; + public class FileBuilder { private File file = null; private FileConfiguration cfg = null; @@ -139,7 +142,7 @@ public static void deleteLine(String path) { inputFile.delete(); tempFile.renameTo(inputFile); } catch (IOException e) { - e.printStackTrace(); + Terraplusminus.instance.getComponentLogger().error("Failed to delete line from config with needle '{}'", path, e); } } @@ -165,7 +168,7 @@ public static void addLineAbove(String path, String comment) { inputFile.delete(); tempFile.renameTo(inputFile); } catch (IOException e) { - e.printStackTrace(); + Terraplusminus.instance.getComponentLogger().error("Failed to insert line above from config with needle '{}'", path, e); } } @@ -191,7 +194,7 @@ public static void addLineAfter(String path, String line) { inputFile.delete(); tempFile.renameTo(inputFile); } catch (IOException e) { - e.printStackTrace(); + Terraplusminus.instance.getComponentLogger().error("Failed to insert line below from config with needle '{}'", path, e); } } From 2441ffb4a3a33b05d247a6c17fb42d247d1ad1c5 Mon Sep 17 00:00:00 2001 From: Smyler Date: Sun, 19 Oct 2025 19:09:35 +0200 Subject: [PATCH 4/8] Cleanup configuration handling - Do not use this.config to access the configuration static field (ideally the configuration should not be in a static field, a complete rewrite of the config system is needed on that side). - Rename FileBuilder to PluginConfigManipulator and make it use instance fields and methods; remove all unused methods and rewrite the remaining ones to eliminate duplicated code and warnings, and use Java best practices like try-with blocks. - Use multiple strings I do believe this will have to be replaced at some point in the future and is still suboptimal, but at least it should be a lot less confusing and more manageable now. --- .../terraplusminus/Terraplusminus.java | 169 +++++++------ .../terraplusminus/utils/FileBuilder.java | 230 ------------------ .../utils/PluginConfigManipulator.java | 74 ++++++ 3 files changed, 174 insertions(+), 299 deletions(-) delete mode 100644 src/main/java/de/btegermany/terraplusminus/utils/FileBuilder.java create mode 100644 src/main/java/de/btegermany/terraplusminus/utils/PluginConfigManipulator.java diff --git a/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java b/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java index 6d083ce..8f7c042 100644 --- a/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java +++ b/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java @@ -9,7 +9,7 @@ import de.btegermany.terraplusminus.events.PluginMessageEvent; import de.btegermany.terraplusminus.gen.RealWorldGenerator; import de.btegermany.terraplusminus.utils.ConfigurationHelper; -import de.btegermany.terraplusminus.utils.FileBuilder; +import de.btegermany.terraplusminus.utils.PluginConfigManipulator; import de.btegermany.terraplusminus.utils.LinkedWorld; import de.btegermany.terraplusminus.utils.PlayerHashMapManagement; import io.papermc.paper.command.brigadier.Commands; @@ -165,9 +165,9 @@ public void enforceDatapackInstallation(String datapackResourcePath, World world } private void updateConfig() { - new FileBuilder(this); // Sets FileBuilder#plugin (static field) + PluginConfigManipulator manipulator = new PluginConfigManipulator(this); - double configVersion = this.config.getDouble("config_version"); + double configVersion = Terraplusminus.config.getDouble("config_version"); if (configVersion == 0.0) { // That's the default value if the field was not set at all in the YAML this.getComponentLogger().error("Old config detected. Please delete and restart/reload."); @@ -177,86 +177,117 @@ private void updateConfig() { if (passthroughTpll == null) { passthroughTpll = ""; } - int y = (int) this.config.getDouble("terrain_offset"); - this.config.set("terrain_offset.x", 0); - this.config.set("terrain_offset.y", y); - this.config.set("terrain_offset.z", 0); - this.config.set("config_version", 1.1); + int y = (int) Terraplusminus.config.getDouble("terrain_offset"); + Terraplusminus.config.set("terrain_offset.x", 0); + Terraplusminus.config.set("terrain_offset.y", y); + Terraplusminus.config.set("terrain_offset.z", 0); + Terraplusminus.config.set("config_version", 1.1); this.saveConfig(); - FileBuilder.addLineAbove("terrain_offset", "\n" + - "# Generation -------------------------------------------\n" + - "# Offset your section which fits into the world."); - FileBuilder.deleteLine("# Passthrough tpll"); - FileBuilder.deleteLine("passthrough_tpll"); - FileBuilder.addLineAbove("# Generation", "# Passthrough tpll to other bukkit plugins. It will not passthrough when it's empty. Type in the name of your plugin. E.g. Your plugin name is vanillatpll you set passthrough_tpll: 'vanillatpll'\n" + - "passthrough_tpll: '" + passthroughTpll + "'\n\n\n"); //Fixes empty config entry from passthrough_tpll + manipulator.addLineAbove( + "terrain_offset", + """ + + # Generation ------------------------------------------- + # Offset your section which fits into the world.""" + ); + manipulator.deleteLine("# Passthrough tpll"); + manipulator.deleteLine("passthrough_tpll"); + manipulator.addLineAbove( + "# Generation", + """ + # Passthrough tpll to other bukkit plugins. It will not passthrough when it's empty. Type in the name of your plugin. E.g. Your plugin name is vanillatpll you set passthrough_tpll: 'vanillatpll' + passthrough_tpll: 'PASSTHROUGH_TPLL' + + + """.replace("PASSTHROUGH_TPLL", passthroughTpll)); //Fixes empty config entry from passthrough_tpll } if (configVersion == 1.1) { - this.config.set("config_version", 1.2); + Terraplusminus.config.set("config_version", 1.2); this.saveConfig(); - FileBuilder.addLineAbove("# If disabled, tree generation is turned off.", "" + - "# Linked servers ---------------------------------------\n" + - "# If the height limit on this server is not enough, other servers can be linked to generate higher or lower sections.\n" + - "linked_servers:\n" + - " enabled: false\n" + - " servers:\n" + - " - another_server # e.g. this server has a datapack to extend height to 2032. it covers the height section (-2032) - (-1) m a.s.l. it has a y-offset of -2032.\n" + - " - current_server # e.g. this server has a datapack to extend height to 2032. it covers the height section 0 - 2032 m a.s.l.\n" + - " - another_server # e.g. this server has a datapack to extend height to 2032. it covers the height section 2033 - 4064 m a.s.l. it has a y-offset of 2032\n"); + manipulator.addLineAbove( + "# If disabled, tree generation is turned off.", + """ + # Linked servers --------------------------------------- + # If the height limit on this server is not enough, other servers can be linked to generate higher or lower sections. + linked_servers: + enabled: false + servers: + - another_server # e.g. this server has a datapack to extend height to 2032. it covers the height section (-2032) - (-1) m a.s.l. it has a y-offset of -2032. + - current_server # e.g. this server has a datapack to extend height to 2032. it covers the height section 0 - 2032 m a.s.l. + - another_server # e.g. this server has a datapack to extend height to 2032. it covers the height section 2033 - 4064 m a.s.l. it has a y-offset of 2032 + """ + ); } if (configVersion == 1.2) { - this.config.set("config_version", 1.3); + Terraplusminus.config.set("config_version", 1.3); this.saveConfig(); - FileBuilder.deleteLine("# Linked servers -------------------------------------"); - FileBuilder.deleteLine("# If the height limit on this server is not enough, other servers can be linked to generate higher or lower sections"); - FileBuilder.deleteLine("linked_servers:"); - FileBuilder.deleteLine(" enabled: false"); - FileBuilder.deleteLine(" servers:"); - FileBuilder.deleteLine("- another_server"); - FileBuilder.deleteLine("- current_server"); - FileBuilder.addLineAbove("# If disabled, tree generation is turned off.", "" + - "# Linked worlds ---------------------------------------\n" + - "# If the height limit in this world/server is not enough, other worlds/servers can be linked to generate higher or lower sections\n" + - "linked_worlds:\n" + - " enabled: false\n" + - " method: 'SERVER' # 'SERVER' or 'MULTIVERSE'\n" + - " # if method = MULTIVERSE -> world_name, y-offset\n" + - " worlds:\n" + - " - another_world/server # e.g. this world/server has a datapack to extend height to 2032. it covers the height section (-2032) - (-1) m a.s.l. it has a y-offset of -2032.\n" + - " - current_world/server # do not change! e.g. this world/server has a datapack to extend height to 2032. it covers the height section 0 - 2032 m a.s.l.\n" + - " - another_world/server # e.g. this world/server has a datapack to extend height to 2032. it covers the height section 2033 - 4064 m a.s.l. it has a y-offset of 2032\n\n"); + manipulator.deleteLine("# Linked servers -------------------------------------"); + manipulator.deleteLine("# If the height limit on this server is not enough, other servers can be linked to generate higher or lower sections"); + manipulator.deleteLine("linked_servers:"); + manipulator.deleteLine(" enabled: false"); + manipulator.deleteLine(" servers:"); + manipulator.deleteLine("- another_server"); + manipulator.deleteLine("- current_server"); + manipulator.addLineAbove( + "# If disabled, tree generation is turned off.", + """ + # Linked worlds --------------------------------------- + # If the height limit in this world/server is not enough, other worlds/servers can be linked to generate higher or lower sections + linked_worlds: + enabled: false + method: 'SERVER' # 'SERVER' or 'MULTIVERSE' + # if method = MULTIVERSE -> world_name, y-offset + worlds: + - another_world/server # e.g. this world/server has a datapack to extend height to 2032. it covers the height section (-2032) - (-1) m a.s.l. it has a y-offset of -2032. + - current_world/server # do not change! e.g. this world/server has a datapack to extend height to 2032. it covers the height section 0 - 2032 m a.s.l. + - another_world/server # e.g. this world/server has a datapack to extend height to 2032. it covers the height section 2033 - 4064 m a.s.l. it has a y-offset of 2032 + """ + ); } if (configVersion == 1.3) { - this.config.set("config_version", 1.4); + Terraplusminus.config.set("config_version", 1.4); this.saveConfig(); - FileBuilder.addLineAfter("prefix:", - "\n# If disabled, the plugin will log every fetched data to the console\n" + - "reduced_console_messages: true"); - FileBuilder.deleteLine("- another_world/server"); - FileBuilder.deleteLine("- current_world/server"); - FileBuilder.addLineAbove("# If disabled, tree generation is turned off.", - " - name: another_world/server # e.g. this world/server has a datapack to extend height to 2032. it covers the height section (-2032) - (-1) m a.s.l. it has a y-offset of -2032.\n" + - " offset: 2032\n" + - " - name: current_world/server # e.g. this world/server has a datapack to extend height to 2032. it covers the height section 0 - 2032 m a.s.l.\n" + - " offset: 0\n" + - " - name: another_world/server # e.g. this world/server has a datapack to extend height to 2032. it covers the height section 2033 - 4064 m a.s.l. it has a y-offset of 2032\n" + - " offset: -2032\n\n"); + manipulator.addLineBelow( + "prefix:", + """ + + # If disabled, the plugin will log every fetched data to the console + reduced_console_messages: true""" + ); + manipulator.deleteLine("- another_world/server"); + manipulator.deleteLine("- current_world/server"); + manipulator.addLineAbove( + "# If disabled, tree generation is turned off.", + """ + - name: another_world/server # e.g. this world/server has a datapack to extend height to 2032. it covers the height section (-2032) - (-1) m a.s.l. it has a y-offset of -2032. + offset: 2032 + - name: current_world/server # e.g. this world/server has a datapack to extend height to 2032. it covers the height section 0 - 2032 m a.s.l. + offset: 0 + - name: another_world/server # e.g. this world/server has a datapack to extend height to 2032. it covers the height section 2033 - 4064 m a.s.l. it has a y-offset of 2032 + offset: -2032 + + """); } if (configVersion == 1.4) { - this.config.set("config_version", 1.5); + Terraplusminus.config.set("config_version", 1.5); this.saveConfig(); boolean differentBiomes = Terraplusminus.config.getBoolean("different_biomes"); - FileBuilder.deleteLine("# The biomes will be generated with https://en.wikipedia.org/wiki/K%C3%B6ppen_climate_classification."); - FileBuilder.deleteLine("# If turned off, everything will be plains biome."); - FileBuilder.deleteLine("different_biomes:"); - FileBuilder.addLineAbove("# Customize the material, the blocks will be generated with.", - "biomes:\n" + - " # If 'use_dataset' is enabled, biomes will be generated based on: https://en.wikipedia.org/wiki/K%C3%B6ppen_climate_classification.\n" + - " use_dataset: " + differentBiomes + "\n" + - " # If 'use_dataset' is disabled, this biome will be used everywhere instead (if 'generate_trees' is also enabled -> oak and birch).\n" + - " # Possible values found in \"Resource location\" on: https://minecraft.wiki/w/Biome#Biome_IDs (use with namespace e.g. minecraft:plains)\n" + - " biome: minecraft:plains\n\n"); + manipulator.deleteLine("# The biomes will be generated with https://en.wikipedia.org/wiki/K%C3%B6ppen_climate_classification."); + manipulator.deleteLine("# If turned off, everything will be plains biome."); + manipulator.deleteLine("different_biomes:"); + manipulator.addLineAbove( + "# Customize the material, the blocks will be generated with.", + """ + biomes: + # If 'use_dataset' is enabled, biomes will be generated based on: https://en.wikipedia.org/wiki/K%C3%B6ppen_climate_classification. + use_dataset: USE_DATASET + # If 'use_dataset' is disabled, this biome will be used everywhere instead (if 'generate_trees' is also enabled -> oak and birch). + # Possible values found in "Resource location" on: https://minecraft.wiki/w/Biome#Biome_IDs (use with namespace e.g. minecraft:plains) + biome: minecraft:plains + + """.replace("USE_DATASET", "" + differentBiomes) + ); } } @@ -309,4 +340,4 @@ private void extractTerraConfigFileToPluginDir(@NotNull String resourcePath, @No this.getComponentLogger().info("Created default Terra-- configuration at {}", droppedFile.getAbsolutePath()); } -} \ No newline at end of file +} diff --git a/src/main/java/de/btegermany/terraplusminus/utils/FileBuilder.java b/src/main/java/de/btegermany/terraplusminus/utils/FileBuilder.java deleted file mode 100644 index 528b8e0..0000000 --- a/src/main/java/de/btegermany/terraplusminus/utils/FileBuilder.java +++ /dev/null @@ -1,230 +0,0 @@ -package de.btegermany.terraplusminus.utils; - -import de.btegermany.terraplusminus.Terraplusminus; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; - -import java.io.*; -import java.util.List; -import java.util.Set; - -import static java.util.logging.Level.SEVERE; - -public class FileBuilder { - private File file = null; - private FileConfiguration cfg = null; - private static Plugin plugin; - - public FileBuilder(String path, String file) { - this.file = new File(path, file); - this.cfg = YamlConfiguration.loadConfiguration(this.file); - } - - public FileBuilder(Plugin plugin) { - this.plugin = plugin; - } - - public FileBuilder addDefault(String path, Object value) { - this.cfg.addDefault(path, value); - return this; - } - - public FileBuilder copyDefaults(boolean copyDefaults) { - this.cfg.options().copyDefaults(copyDefaults); - return this; - } - - public FileBuilder set(String path, Object value) { - this.cfg.set(path, value); - return this; - } - - public FileBuilder save() { - try { - this.cfg.save(this.file); - } catch (IOException e) { - e.printStackTrace(); - } - return this; - } - - public File getFile() { - return this.file; - } - - public void reload() { - try { - this.cfg.load(this.file); - } catch (IOException | InvalidConfigurationException e) { - e.printStackTrace(); - } - } - - public boolean exists() { - return this.file.exists(); - } - - public boolean contains(String value) { - return this.cfg.contains(value); - } - - public Object getObject(String path) { - return this.cfg.get(path); - } - - public String getString(String path) { - return this.cfg.getString(path); - } - - public int getInt(String path) { - return this.cfg.getInt(path); - } - - public double getDouble(String path) { - return this.cfg.getDouble(path); - } - - public long getLong(String path) { - return this.cfg.getLong(path); - } - - public boolean getBoolean(String path) { - return this.cfg.getBoolean(path); - } - - public List getStringList(String path) { - return this.cfg.getStringList(path); - } - - public List getBooleanList(String path) { - return this.cfg.getBooleanList(path); - } - - public List getDoubleList(String path) { - return this.cfg.getDoubleList(path); - } - - public List getIntegerList(String path) { - return this.cfg.getIntegerList(path); - } - - public Set getKeys(boolean keys) { - return this.cfg.getKeys(keys); - } - - public ConfigurationSection getConfigurationSection(String section) { - return this.cfg.getConfigurationSection(section); - } - - public static void deleteLine(String path) { - try { - File inputFile = new File(plugin.getDataFolder() + File.separator + "config.yml"); - File tempFile = new File(plugin.getDataFolder() + File.separator + "temp.yml"); - - BufferedReader reader = new BufferedReader(new FileReader(inputFile)); - BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile)); - - String currentLine; - - while ((currentLine = reader.readLine()) != null) { - if (currentLine.contains(path)) { - writer.write(""); - } else { - writer.write(currentLine + "\n"); - } - } - - writer.close(); - reader.close(); - inputFile.delete(); - tempFile.renameTo(inputFile); - } catch (IOException e) { - Terraplusminus.instance.getComponentLogger().error("Failed to delete line from config with needle '{}'", path, e); - } - } - - public static void addLineAbove(String path, String comment) { - try { - File inputFile = new File(plugin.getDataFolder() + File.separator + "config.yml"); - File tempFile = new File(plugin.getDataFolder() + File.separator + "temp.yml"); - - BufferedReader reader = new BufferedReader(new FileReader(inputFile)); - BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile)); - - String currentLine; - - while ((currentLine = reader.readLine()) != null) { - if (currentLine.contains(path)) { - writer.write(comment + "\n"); - } - writer.write(currentLine + "\n"); - } - - writer.close(); - reader.close(); - inputFile.delete(); - tempFile.renameTo(inputFile); - } catch (IOException e) { - Terraplusminus.instance.getComponentLogger().error("Failed to insert line above from config with needle '{}'", path, e); - } - } - - public static void addLineAfter(String path, String line) { - try { - File inputFile = new File(plugin.getDataFolder() + File.separator + "config.yml"); - File tempFile = new File(plugin.getDataFolder() + File.separator + "temp.yml"); - - BufferedReader reader = new BufferedReader(new FileReader(inputFile)); - BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile)); - - String currentLine; - - while ((currentLine = reader.readLine()) != null) { - writer.write(currentLine + "\n"); - if (currentLine.contains(path)) { - writer.write(line + "\n"); - } - } - - writer.close(); - reader.close(); - inputFile.delete(); - tempFile.renameTo(inputFile); - } catch (IOException e) { - Terraplusminus.instance.getComponentLogger().error("Failed to insert line below from config with needle '{}'", path, e); - } - } - - public static void editPathValue(String path, String value) { - try { - File inputFile = new File(plugin.getDataFolder() + File.separator + "config.yml"); - File tempFile = new File(plugin.getDataFolder() + File.separator + "temp.yml"); - - BufferedReader reader = new BufferedReader(new FileReader(inputFile)); - BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile)); - - String currentLine; - - while ((currentLine = reader.readLine()) != null) { - if (currentLine.contains(path)) { - writer.write(path + ": " + value + "\n"); - } else { - writer.write(currentLine + "\n"); - } - } - writer.close(); - reader.close(); - inputFile.delete(); - tempFile.renameTo(inputFile); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public void delete() { - this.file.delete(); - } -} diff --git a/src/main/java/de/btegermany/terraplusminus/utils/PluginConfigManipulator.java b/src/main/java/de/btegermany/terraplusminus/utils/PluginConfigManipulator.java new file mode 100644 index 0000000..9859ff5 --- /dev/null +++ b/src/main/java/de/btegermany/terraplusminus/utils/PluginConfigManipulator.java @@ -0,0 +1,74 @@ +package de.btegermany.terraplusminus.utils; + +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.io.*; +import java.util.function.Function; + + +public class PluginConfigManipulator { + private final Plugin plugin; + + public PluginConfigManipulator(Plugin plugin) { + this.plugin = plugin; + } + + /** + * Remove all lines in plugin's config file that contain the given needle. + * + * @param needle the needle to search for in lines + */ + public void deleteLine(String needle) { + this.transformLinesContaining(needle, l -> new String[0]); + } + + /** + * Add given content above all lines in plugin's config file that contain the given needle. + * + * @param needle the needle to search for in lines + */ + public void addLineAbove(String needle, String content) { + this.transformLinesContaining(needle, l -> new String[] {content, l}); + } + + /** + * Add given content below all lines in plugin's config file that contain the given needle. + * + * @param needle the needle to search for in lines + */ + public void addLineBelow(String needle, String content) { + this.transformLinesContaining(needle, l -> new String[] {l, content}); + } + + private void transformLinesContaining(String needle, Function<@NotNull String, @NotNull String[]> transformer) { + File inputFile = new File(this.plugin.getDataFolder() + File.separator + "config.yml"); + File tempFile = new File(this.plugin.getDataFolder() + File.separator + "temp.yml"); + try ( + BufferedReader reader = new BufferedReader(new FileReader(inputFile)); + BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile)) + ) { + + String currentLine; + while ((currentLine = reader.readLine()) != null) { + if (!currentLine.contains(needle)) { + writer.write(currentLine + "\n"); + } else { + String[] transformed = transformer.apply(currentLine); + for (String line: transformed) { + writer.write(line + "\n"); + } + } + } + + boolean deleted = inputFile.delete(); + boolean renamed = tempFile.renameTo(inputFile); + if (!deleted || !renamed) { + this.plugin.getComponentLogger().warn("Failed to swap temporary file with config"); + } + } catch (IOException e) { + this.plugin.getComponentLogger().error("Failed to transform config file {} with needle '{}'", inputFile, needle, e); + } + } + +} From b2a9681a7521c7058c9618dfae82f9d7baf23a87 Mon Sep 17 00:00:00 2001 From: Smyler Date: Sun, 19 Oct 2025 19:21:59 +0200 Subject: [PATCH 5/8] Send a message to players using /where from outside the projection instead of silently failing and printing a useless stack trace --- .../terraplusminus/commands/WhereCommand.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/btegermany/terraplusminus/commands/WhereCommand.java b/src/main/java/de/btegermany/terraplusminus/commands/WhereCommand.java index 13089c2..818b8f8 100644 --- a/src/main/java/de/btegermany/terraplusminus/commands/WhereCommand.java +++ b/src/main/java/de/btegermany/terraplusminus/commands/WhereCommand.java @@ -9,6 +9,7 @@ import net.md_5.bungee.api.chat.ComponentBuilder; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -30,20 +31,19 @@ public void execute(@NotNull CommandSourceStack stack, @NotNull String[] args) { int xOffset = Terraplusminus.config.getInt("terrain_offset.x"); int zOffset = Terraplusminus.config.getInt("terrain_offset.z"); - double[] mcCoordinates = new double[2]; - mcCoordinates[0] = player.getLocation().getX() - xOffset; - mcCoordinates[1] = player.getLocation().getZ() - zOffset; - System.out.println(mcCoordinates[0] + ", " + mcCoordinates[1]); - double[] coordinates = new double[0]; + TextComponent message = new TextComponent(Terraplusminus.config.getString("prefix")); + + double playerX = player.getLocation().getX() - xOffset; + double playerZ = player.getLocation().getZ() - zOffset; try { - coordinates = bteGeneratorSettings.projection().toGeo(mcCoordinates[0], mcCoordinates[1]); + double[] coordinates = this.bteGeneratorSettings.projection().toGeo(playerX, playerZ); + message.addExtra("§7Your coordinates are:"); + message.addExtra("\n§8" + coordinates[1] + ", " + coordinates[0] + "§7."); + message.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://maps.google.com/maps?t=k&q=loc:" + coordinates[1] + "+" + coordinates[0])); + message.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("§7Click here to view in Google Maps.").create())); } catch (OutOfProjectionBoundsException e) { - e.printStackTrace(); + message.addExtra(ChatColor.RED + "You are currently outside of the world's projection and your location in the Minecraft world has no equivalent on Earth."); } - TextComponent message = new TextComponent(Terraplusminus.config.getString("prefix") + "§7Your coordinates are:"); - message.addExtra("\n§8" + coordinates[1] + ", " + coordinates[0] + "§7."); - message.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://maps.google.com/maps?t=k&q=loc:" + coordinates[1] + "+" + coordinates[0])); - message.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("§7Click here to view in Google Maps.").create())); player.spigot().sendMessage(message); } } From 4f6468e6f2923df78dc50c602145fcae56478466 Mon Sep 17 00:00:00 2001 From: Smyler Date: Sun, 19 Oct 2025 19:30:17 +0200 Subject: [PATCH 6/8] Remove log ascii art when the plugin gets loaded These kind of multiline logs add nothing of value besides "looking cool" and make logs harder to read, search and process for server admins. --- .../terraplusminus/Terraplusminus.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java b/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java index 8f7c042..2d704f3 100644 --- a/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java +++ b/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java @@ -30,7 +30,6 @@ import org.bukkit.event.world.WorldInitEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; @@ -49,16 +48,6 @@ public final class Terraplusminus extends JavaPlugin implements Listener { @Override public void onEnable() { instance = this; - PluginDescriptionFile pdf = this.getDescription(); - String pluginVersion = pdf.getVersion(); - - this.getComponentLogger().info("\n╭━━━━╮\n" + - "┃╭╮╭╮┃\n" + - "╰╯┃┃┣┻━┳━┳━┳━━╮╭╮\n" + - "╱╱┃┃┃┃━┫╭┫╭┫╭╮┣╯╰┳━━╮\n" + - "╱╱┃┃┃┃━┫┃┃┃┃╭╮┣╮╭┻━━╯\n" + - "╱╱╰╯╰━━┻╯╰╯╰╯╰╯╰╯\n" + - "Version: {}", pluginVersion); // Config ------------------] ConfigurationSerialization.registerClass(ConfigurationSerializable.class); @@ -93,7 +82,10 @@ public void onEnable() { registerCommands(); - this.getComponentLogger().info("Terraplusminus successfully enabled"); + this.getComponentLogger().info( + "Terraplusminus successfully enabled ({} v{}, {} v{})", + this.getName(), this.getVersion(), TerraConstants.LIB_NAME, TerraConstants.LIB_VERSION + ); } @Override @@ -310,6 +302,12 @@ private void setupTerraMinusMinus() { Http.userAgent(userAgent); } + // The old way is deprecated and the new one is experimental, let's go with the new one + private String getVersion() { + PluginMeta meta = this.getPluginMeta(); + return meta.getVersion(); + } + // This method has to rely on the unstable paper API as we use paper-plugin.yml, which itself is experimental private String createHttpUserAgent() { PluginMeta metadata = this.getPluginMeta(); From 8b12dea3bd61a92956ac2fa31249463a30fb73aa Mon Sep 17 00:00:00 2001 From: Smyler Date: Sun, 2 Nov 2025 10:34:27 +0100 Subject: [PATCH 7/8] Tweak tree-loading logging --- .../gen/tree/TreePopulator.java | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java b/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java index cf4c151..724ee4e 100644 --- a/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java +++ b/src/main/java/de/btegermany/terraplusminus/gen/tree/TreePopulator.java @@ -69,35 +69,43 @@ public TreePopulator(CustomBiomeProvider customBiomeProvider, int yOffset) { // Load Trees from customTrees.json JsonObject treeTypes = getJSONObject(); - final int[] treeCount = {0}; - treeTypes.entrySet().forEach(treeSizes -> { - - trees.put(treeSizes.getKey(), new ArrayList<>()); - - Terraplusminus.instance.getComponentLogger().info("Loading Tree Type {}", treeSizes.getKey()); - - treeSizes.getValue().getAsJsonObject().entrySet().forEach(treeNames -> { - - treeNames.getValue().getAsJsonObject().entrySet().forEach(tree -> { - - treeCount[0]++; + final TreeLoadingStatistics stats = new TreeLoadingStatistics(); + treeTypes.entrySet().forEach(treeTypeEntry -> { + final String treeType = treeTypeEntry.getKey(); + final JsonObject treeSizeVariants = treeTypeEntry.getValue().getAsJsonObject(); + stats.familyCount++; + Terraplusminus.instance.getComponentLogger().debug("Loading tree family {} with {} size variants", treeType, treeSizeVariants.size()); + + this.trees.put(treeType, new ArrayList<>()); + + treeSizeVariants.entrySet().forEach(variantEntry -> { + final String sizeName = variantEntry.getKey(); // s, m, l, ... + final JsonObject treeVariants = variantEntry.getValue().getAsJsonObject(); + Terraplusminus.instance.getComponentLogger().trace("Loading trees of family {} and size {} with {} variants", treeType, sizeName, treeVariants.size()); + + treeVariants.entrySet().forEach(treeEntry -> { + final String treeName = treeEntry.getKey(); + final JsonObject treeConfig = treeEntry.getValue().getAsJsonObject(); + Terraplusminus.instance.getComponentLogger().trace("Loading tree variant {} of size {} and family {}", treeName, sizeName, treeType); + + stats.totalVariantCount++; ArrayList treeBlocks = new ArrayList<>(); - tree.getValue().getAsJsonObject().get("blocks").getAsJsonArray().forEach(treeBlockElement -> { + treeConfig.get("blocks").getAsJsonArray().forEach(treeBlockElement -> { JsonObject treeBlock = treeBlockElement.getAsJsonObject(); treeBlocks.add(new TreeBlock(treeBlock.get("x").getAsInt(), treeBlock.get("y").getAsInt(), treeBlock.get("z").getAsInt(), Material.getMaterial(treeBlock.get("material").getAsString()))); }); - trees.get(treeSizes.getKey()).add(treeBlocks); + trees.get(treeTypeEntry.getKey()).add(treeBlocks); }); }); }); - Terraplusminus.instance.getComponentLogger().info("Finished loading {} custom trees", treeCount[0]); + Terraplusminus.instance.getComponentLogger().info("Loaded {} custom trees from {} families", stats.totalVariantCount, stats.familyCount); } @@ -229,4 +237,9 @@ public JsonObject getJSONObject() { return jsonObject.get("trees").getAsJsonObject(); } + private static class TreeLoadingStatistics { + int familyCount = 0; + int totalVariantCount = 0; + } + } \ No newline at end of file From 9bb4b882529f4b7e8f5849762b5067498d44f9d6 Mon Sep 17 00:00:00 2001 From: Smyler Date: Tue, 11 Nov 2025 08:46:20 +0100 Subject: [PATCH 8/8] Make config replacement atomic --- .../utils/PluginConfigManipulator.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/btegermany/terraplusminus/utils/PluginConfigManipulator.java b/src/main/java/de/btegermany/terraplusminus/utils/PluginConfigManipulator.java index 9859ff5..0effc6d 100644 --- a/src/main/java/de/btegermany/terraplusminus/utils/PluginConfigManipulator.java +++ b/src/main/java/de/btegermany/terraplusminus/utils/PluginConfigManipulator.java @@ -4,8 +4,12 @@ import org.jetbrains.annotations.NotNull; import java.io.*; +import java.nio.file.Path; import java.util.function.Function; +import static java.nio.file.Files.move; +import static java.nio.file.StandardCopyOption.ATOMIC_MOVE; + public class PluginConfigManipulator { private final Plugin plugin; @@ -42,11 +46,11 @@ public void addLineBelow(String needle, String content) { } private void transformLinesContaining(String needle, Function<@NotNull String, @NotNull String[]> transformer) { - File inputFile = new File(this.plugin.getDataFolder() + File.separator + "config.yml"); - File tempFile = new File(this.plugin.getDataFolder() + File.separator + "temp.yml"); + Path inputFile = this.plugin.getDataPath().resolve("config.yml"); + Path tempFile = this.plugin.getDataPath().resolve("temp.yml"); try ( - BufferedReader reader = new BufferedReader(new FileReader(inputFile)); - BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile)) + BufferedReader reader = new BufferedReader(new FileReader(inputFile.toFile())); + BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile.toFile())) ) { String currentLine; @@ -61,11 +65,7 @@ private void transformLinesContaining(String needle, Function<@NotNull String, @ } } - boolean deleted = inputFile.delete(); - boolean renamed = tempFile.renameTo(inputFile); - if (!deleted || !renamed) { - this.plugin.getComponentLogger().warn("Failed to swap temporary file with config"); - } + move(tempFile, inputFile, ATOMIC_MOVE); } catch (IOException e) { this.plugin.getComponentLogger().error("Failed to transform config file {} with needle '{}'", inputFile, needle, e); }