diff --git a/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java b/src/main/java/de/btegermany/terraplusminus/Terraplusminus.java index b938d77..2d704f3 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; @@ -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; @@ -29,17 +30,15 @@ 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; import java.io.*; +import java.nio.file.Path; 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 { @@ -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(); - - getLogger().log(Level.INFO, "\n╭━━━━╮\n" + - "┃╭╮╭╮┃\n" + - "╰╯┃┃┣┻━┳━┳━┳━━╮╭╮\n" + - "╱╱┃┃┃┃━┫╭┫╭┫╭╮┣╯╰┳━━╮\n" + - "╱╱┃┃┃┃━┫┃┃┃┃╭╮┣╮╭┻━━╯\n" + - "╱╱╰╯╰━━┻╯╰╯╰╯╰╯╰╯\n" + - "Version: " + pluginVersion); // Config ------------------] ConfigurationSerialization.registerClass(ConfigurationSerializable.class); @@ -93,7 +82,10 @@ public void onEnable() { registerCommands(); - Bukkit.getLogger().log(Level.INFO, "[T+-] Terraplusminus successfully enabled"); + this.getComponentLogger().info( + "Terraplusminus successfully enabled ({} v{}, {} v{})", + this.getName(), this.getVersion(), TerraConstants.LIB_NAME, TerraConstants.LIB_VERSION + ); } @Override @@ -103,19 +95,18 @@ public void onDisable() { this.getServer().getMessenger().unregisterIncomingPluginChannel(this); // -------------------------- - Bukkit.getLogger().log(Level.INFO, "[T+-] Plugin deactivated"); + this.getComponentLogger().info("Plugin deactivated"); } @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); } } @@ -137,132 +128,158 @@ 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) { - Bukkit.getLogger().log(Level.SEVERE, "[T+-] " + destination.getName() + " not found"); - 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) { - Bukkit.getLogger().log(Level.SEVERE, "[T+-] 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"); - 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() { - FileBuilder fileBuilder = new FileBuilder(this); + PluginConfigManipulator manipulator = new PluginConfigManipulator(this); - Double configVersion = null; - try { - 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."); + 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."); } if (configVersion == 1.0) { String passthroughTpll = Terraplusminus.config.getString("passthrough_tpll"); 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) + ); } } @@ -281,10 +298,16 @@ 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); } + // 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(); @@ -300,19 +323,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/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); } } 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/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 4aa61cd..724ee4e 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,7 @@ 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 { @@ -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<>()); - - Bukkit.getLogger().log(Level.INFO, "[T+-] 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); }); }); }); - Bukkit.getLogger().log(Level.INFO, "[T+-] Finished loading " + treeCount[0] + " custom trees"); + Terraplusminus.instance.getComponentLogger().info("Loaded {} custom trees from {} families", stats.totalVariantCount, stats.familyCount); } @@ -126,7 +134,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) { @@ -159,7 +170,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 + ); } } } @@ -221,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 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 a649d0d..0000000 --- a/src/main/java/de/btegermany/terraplusminus/utils/FileBuilder.java +++ /dev/null @@ -1,227 +0,0 @@ -package de.btegermany.terraplusminus.utils; - -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; - -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) { - e.printStackTrace(); - } - } - - 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) { - e.printStackTrace(); - } - } - - 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) { - e.printStackTrace(); - } - } - - 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..0effc6d --- /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.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; + + 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) { + Path inputFile = this.plugin.getDataPath().resolve("config.yml"); + Path tempFile = this.plugin.getDataPath().resolve("temp.yml"); + try ( + BufferedReader reader = new BufferedReader(new FileReader(inputFile.toFile())); + BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile.toFile())) + ) { + + 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"); + } + } + } + + move(tempFile, inputFile, ATOMIC_MOVE); + } catch (IOException e) { + this.plugin.getComponentLogger().error("Failed to transform config file {} with needle '{}'", inputFile, needle, e); + } + } + +}