diff --git a/CHANGELOG.md b/CHANGELOG.md index 446b67a..30ecefd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,17 +4,6 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project kind of adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -### WIP [1.4.0] -#### Changed -- The loading logic of the storage file - -#### Added -- **a config file!** - - The config file starts at **version 0**! -- versioning to the storage file for better handling of migrations. - - We start at **version 1**, all previous version are version 0. - - ### [1.3.4] - Updated Italian translations (Thanks to [Jump-333](https://github.com/Jump-333)!) - Turned DeathLocation into a Hashmap diff --git a/README.md b/README.md index ef02038..c251d75 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A Minecraft server-side mod that adds various teleportation related commands, li Here is the [Changelog](https://github.com/MrSn0wy/TeleportCommands/blob/main/CHANGELOG.md) -## Currently available commands: +### Currently available commands: - `/worldspawn []` - Teleports you to the world spawn (in the overworld), if given true it will not do safety checks - `/back []` - Teleports you to the location where you last died, if given true it will not do safety checks @@ -32,14 +32,14 @@ Here is the [Changelog](https://github.com/MrSn0wy/TeleportCommands/blob/main/CH
-## TODO: -### Planned commands: +### TODO: +#### Planned commands: - [ ] `/wild` - Teleports you to a random location in the Overworld - [x] `/worldspawn` - Teleports you to the worldspawn -- [ ] `/spawn ` - Teleports you to your spawn point in a dimension, defaults to your current dimension +- [ ] `/spawn ` - Teleports you to your spawnpoint in a dimension, defaults to your current dimension - [ ] `/previous` - Go to the last teleported location -### Improvements: +#### Improvements: - [ ] Look into changing the mod into the more safe and sane kotlin (I love java) - [ ] Add game tests - [ ] Find the easiest way to backport the mod to older version (help) @@ -56,34 +56,31 @@ Here is the [Changelog](https://github.com/MrSn0wy/TeleportCommands/blob/main/CH - [x] Add Quilt support and NeoForge -## Want to help? +### Want to help? 1. You can create a translation file so other people can use the mod in their native language: [translations.md](./common/src/main/resources/assets/teleport_commands/lang/translations.md) -## How to build -### Getting the correct environment -#### Nixos +### How to build +#### Getting the correct environment If you are on nixos you can simply go into the folder of where you cloned the repo, and run `nix develop .`. This will give you the environment I use (apart from the IDE) :3. -#### Generic linux On any other linux distro, just install the jetbrains jdk, or try openjdk21. -#### Windows -On windows probably go to the openjdk website and install the 21 version? Idk goodluck. +On windows probably go to the openjdk website and install the 21 version? idk goodluck. -### Building -Then on linux just run `./gradlew build`. To make it into a single mod jar just run `./gradlew mergeJars`. +#### Building +Then on linux just do `./gradlew build` and to make it in a single mod jar `./gradlew mergeJars`. Or on windows, just do `.\gradlew.bat build` and `.\gradlew.bat mergeJars`. Note that this isn't tested for windows, but I think that is how it works. -### Getting the jars +#### Getting the jars Then you can find your jars in `fabric/build/libs/` (for fabric), `neoforge/build/libs/` (for neoforge) or `merged/build/libs/` (if you made the merged jar file). If you have any issues just make an issue or contact me on Discord `@mrsnowy_` -## Random notes lol -Text Colors: +### Notes +Colors: - Green = When something succeeds and an action will happen - Aqua = When something needs attention - White = When something is done diff --git a/common/build.gradle b/common/build.gradle index a3d45d8..e47427c 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -37,4 +37,4 @@ configurations { artifacts { commonJava sourceSets.main.java.sourceDirectories.singleFile commonResources sourceSets.main.resources.sourceDirectories.singleFile -} +} \ No newline at end of file diff --git a/common/src/main/java/dev/mrsnowy/teleport_commands/TeleportCommands.java b/common/src/main/java/dev/mrsnowy/teleport_commands/TeleportCommands.java index c2d215e..8dfd2e4 100644 --- a/common/src/main/java/dev/mrsnowy/teleport_commands/TeleportCommands.java +++ b/common/src/main/java/dev/mrsnowy/teleport_commands/TeleportCommands.java @@ -5,15 +5,21 @@ import com.mojang.brigadier.CommandDispatcher; import dev.mrsnowy.teleport_commands.storage.StorageManager; import dev.mrsnowy.teleport_commands.commands.*; import dev.mrsnowy.teleport_commands.storage.DeathLocationStorage; -import dev.mrsnowy.teleport_commands.storage.ConfigManager; import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.storage.LevelResource; -import net.minecraft.core.BlockPos; + import java.io.*; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + +import net.minecraft.core.BlockPos; + +import static dev.mrsnowy.teleport_commands.storage.StorageManager.*; public class TeleportCommands { public static String MOD_LOADER; @@ -30,9 +36,9 @@ public class TeleportCommands { CONFIG_DIR = Paths.get(System.getProperty("user.dir")).resolve("config"); // Construct the game directory path SERVER = server; - StorageManager.StorageInit(); // Initialize the storage file - ConfigManager.ConfigInit(); + StorageManager.STORAGE = storageValidator(); // Initialize the storage file DeathLocationStorage.clearDeathLocations(); // Clear data of death locations. + } // initialize commands, also allows me to easily disable any when there is a config @@ -42,7 +48,6 @@ public class TeleportCommands { tpa.register(dispatcher); warp.register(dispatcher); worldspawn.register(dispatcher); - main.register(dispatcher); } // Runs when the playerDeath mixin calls it, updates the /back command position @@ -53,4 +58,175 @@ public class TeleportCommands { DeathLocationStorage.setDeathLocation(uuid, pos, world); } + + // cleans and updates Storage to the newest "version". This is painful + private static StorageClass storageValidator() { + Constants.LOGGER.info("Cleaning and updating Storage!"); + + try { + StorageInit(); + + long startFileSize = Files.size(StorageManager.STORAGE_FILE); + + FileReader reader = new FileReader(StorageManager.STORAGE_FILE.toString()); + JsonElement jsonElement = JsonParser.parseReader(reader); + + if (jsonElement.isJsonObject()) { + + JsonObject mainJsonObject = jsonElement.getAsJsonObject(); + JsonArray newWarpsArray = new JsonArray(); + JsonArray newPlayersArray = new JsonArray(); + + // get the Warps list + if (mainJsonObject.has("Warps") && mainJsonObject.get("Warps").isJsonArray()) { + + // Warps + for (JsonElement warpElement : mainJsonObject.get("Warps").getAsJsonArray()) { + + // Warp + if (warpElement.isJsonObject()) { + JsonObject warp = warpElement.getAsJsonObject(); + + String warpName = warp.has("name") ? warp.get("name").getAsString() : ""; + Integer warpX = warp.has("x") ? warp.get("x").getAsInt() : null; + Integer warpY = warp.has("y") ? warp.get("y").getAsInt() : null; + Integer warpZ = warp.has("z") ? warp.get("z").getAsInt() : null; + String warpWorld = warp.has("world") ? warp.get("world").getAsString() : ""; + + // check if it is valid + if (!warpName.isBlank() && !warpWorld.isBlank() && warpX != null && warpY != null && warpZ != null) { + JsonObject newWarp = new JsonObject(); + + newWarp.addProperty("name", warpName); + newWarp.addProperty("x", warpX); + newWarp.addProperty("y", warpY); + newWarp.addProperty("z", warpZ); + newWarp.addProperty("world", warpWorld); + + newWarpsArray.add(newWarp); + } + } + } + } + + + // get the Players list + if (mainJsonObject.has("Players") && mainJsonObject.get("Players").isJsonArray()) { + + // players + for (JsonElement playerElement : mainJsonObject.get("Players").getAsJsonArray()) { + + // player + if (playerElement.isJsonObject()) { + + JsonObject player = playerElement.getAsJsonObject(); + boolean hasInformation = false; + + String UUID = player.has("Player_UUID") + ? player.get("Player_UUID").getAsString() : (player.has("UUID") + ? player.get("UUID").getAsString() : null); + + String DefaultHome = player.has("DefaultHome") + ? player.get("DefaultHome").getAsString() : ""; + + JsonArray homes = new JsonArray(); + + if (player.has("Homes") && player.get("Homes").isJsonArray() ) { + JsonArray tempHomes = player.get("Homes").getAsJsonArray(); + boolean defaultHomeFound = false; + + + for (JsonElement homeElement : tempHomes) { + if (homeElement.isJsonObject()) { + JsonObject home = homeElement.getAsJsonObject(); + + String homeName = home.has("name") + ? home.get("name").getAsString() : ""; + + // upgrade doubles to int + Integer homeX = home.has("x") && home.get("x").isJsonPrimitive() && home.get("x").getAsJsonPrimitive().isNumber() + ? (int) Math.floor(home.get("x").getAsDouble()) : null; + + Integer homeY = home.has("y") && home.get("y").isJsonPrimitive() && home.get("y").getAsJsonPrimitive().isNumber() + ? (int) Math.floor(home.get("y").getAsDouble()) : null; + + Integer homeZ = home.has("z") && home.get("z").isJsonPrimitive() && home.get("z").getAsJsonPrimitive().isNumber() + ? (int) Math.floor(home.get("z").getAsDouble()) : null; + + String homeWorld = home.has("world") + ? home.get("world").getAsString() : ""; + + // check if it is valid + if (!homeName.isBlank() && !homeWorld.isBlank() && homeX != null && homeY != null && homeZ != null) { + + // check if it is the default home + if (!DefaultHome.isBlank() && homeName.equals(DefaultHome)) { + defaultHomeFound = true; + } + + JsonObject newHome = new JsonObject(); + + newHome.addProperty("name", homeName); + newHome.addProperty("x", homeX); + newHome.addProperty("y", homeY); + newHome.addProperty("z", homeZ); + newHome.addProperty("world", homeWorld); + + homes.add(newHome); + hasInformation = true; + } + } + } + + // clean DefaultHome if there is no home with the name + if (!defaultHomeFound) { + DefaultHome = ""; + } + } + + // if it isn't empty it gets added to the newPlayersArray + if ((UUID != null && !UUID.isBlank()) && hasInformation) { + + JsonObject newPlayer = new JsonObject(); + + newPlayer.addProperty("UUID", UUID); + newPlayer.addProperty("DefaultHome", DefaultHome); + newPlayer.add("Homes", homes); + + newPlayersArray.add(newPlayer); + } + } + } + } + + // save the cleaned and updated file + mainJsonObject.remove("Warps"); + mainJsonObject.add("Warps", newWarpsArray); + + mainJsonObject.remove("Players"); + mainJsonObject.add("Players", newPlayersArray); + + // save the cleaned database + Gson gson = new GsonBuilder().create(); + byte[] json = gson.toJson(mainJsonObject).getBytes(); + Files.write(StorageManager.STORAGE_FILE, json, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING); + + // Only show amount cleaned when it isn't 0B lool + int diff = Math.round(( startFileSize - Files.size(StorageManager.STORAGE_FILE) )); + + if (diff > 0) { + Constants.LOGGER.info("Success! Cleaned: {}B", diff); + } else { + Constants.LOGGER.info("Success!"); + } + + return gson.fromJson(mainJsonObject, StorageManager.StorageClass.class); + } + + } catch (IOException e) { + Constants.LOGGER.error("Error while cleaning the database!", e); + } + + return null; + } } \ No newline at end of file diff --git a/common/src/main/java/dev/mrsnowy/teleport_commands/commands/main.java b/common/src/main/java/dev/mrsnowy/teleport_commands/commands/main.java index 1abad90..952618f 100644 --- a/common/src/main/java/dev/mrsnowy/teleport_commands/commands/main.java +++ b/common/src/main/java/dev/mrsnowy/teleport_commands/commands/main.java @@ -1,138 +1,76 @@ -package dev.mrsnowy.teleport_commands.commands; - -import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -import com.mojang.brigadier.suggestion.SuggestionProvider; -import dev.mrsnowy.teleport_commands.Constants; -import dev.mrsnowy.teleport_commands.TeleportCommands; -import dev.mrsnowy.teleport_commands.storage.ConfigManager; -import net.minecraft.ChatFormatting; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.Commands; -import net.minecraft.commands.SharedSuggestionProvider; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.server.level.ServerPlayer; - -import java.util.Arrays; - -import static dev.mrsnowy.teleport_commands.utils.tools.*; - -public class main { - - // TODO! Make this automatically generate based on the commands we have - private static final String[] available_commands = { - "back", - "home", - "tpa", - "warp", - "worldspawn" - }; - - // sum lists - private static final String[] enabled_commands = available_commands; // TODO! get enabled commands - private static final String[] disabled_commands = available_commands; // TODO! get disabled commands - - // Create sum suggestion providers - private static final SuggestionProvider disabled_commands_suggester = (context, builder) -> SharedSuggestionProvider.suggest(disabled_commands, builder); - private static final SuggestionProvider enabled_commands_suggester = (context, builder) -> SharedSuggestionProvider.suggest(enabled_commands, builder); - - - public static void register(CommandDispatcher dispatcher) { - - dispatcher.register(Commands.literal("teleportcommands") - .then(Commands.literal("reloadConfig") - .executes(context -> { - try { - ConfigManager.ConfigLoader(); - } catch (Exception e) { - Constants.LOGGER.error("Failed to reload config!", e); - throw new SimpleCommandExceptionType(Component.literal(e.toString())).create(); - } - return 0; - })) - .then(Commands.literal("disable") - .then(Commands.argument("command", StringArgumentType.word()) - .suggests(enabled_commands_suggester) - .requires(source -> source.hasPermission(4)) // Require OP - .requires(source -> source.getPlayer() != null) - .executes(context -> { - final ServerPlayer player = context.getSource().getPlayerOrException(); - final String string = StringArgumentType.getString(context, "command"); - - // todo! maybe move this check outside for reusability? - if (!Arrays.asList(enabled_commands).contains(string)) { - // TODO! make this translatable - throw new SimpleCommandExceptionType(Component.literal("\"" + string + "\" is not available as an command!").withStyle(ChatFormatting.RED, ChatFormatting.BOLD)).create(); - } - - try { - player.displayClientMessage(Component.literal("meow " + string), true); - - } catch (Exception e) { - Constants.LOGGER.error("Error while disabling a command! => ", e); - // TODO replace the error below with something normal? - throw new SimpleCommandExceptionType(getTranslatedText("commands.teleport_commands.common.error", player).withStyle(ChatFormatting.RED, ChatFormatting.BOLD)).create(); - } - return 0; - }) - )) - .then(Commands.literal("enable") - .then(Commands.argument("command", StringArgumentType.word()) - .suggests(disabled_commands_suggester) - .requires(source -> source.hasPermission(4)) // Require OP - .requires(source -> source.getPlayer() != null) - .executes(context -> { - final ServerPlayer player = context.getSource().getPlayerOrException(); - final String string = StringArgumentType.getString(context, "command"); - - // todo! maybe move this check outside for reusability? - if (!Arrays.asList(disabled_commands).contains(string)) { - // TODO! make this translatable - throw new SimpleCommandExceptionType(Component.literal("\"" + string + "\" is not available as an command!")).create(); - } - - try { - player.displayClientMessage(Component.literal("meow " + string), true); - - } catch (Exception e) { - Constants.LOGGER.error("Error while disabling a command! => ", e); - // TODO replace the error below with something normal? - throw new SimpleCommandExceptionType(getTranslatedText("commands.teleport_commands.common.error", player).withStyle(ChatFormatting.RED, ChatFormatting.BOLD)).create(); - } - return 0; - }) - )) - // Todo! Is this still needed? - .then(Commands.literal("reload") - .requires(source -> source.hasPermission(4)) // Require OP - .executes(context -> { - TeleportCommands.registerCommands(context.getSource().dispatcher()); - return 0; - })) - - .then(Commands.literal("help") - .executes(context -> { - context.getSource().sendSuccess(main::printCommands, false); - return 0; - })) - ); - } - - - // ----- - - - private static MutableComponent printCommands() { - MutableComponent message = Component.empty(); - - message.append(Component.literal("Thank you for using Teleport Commands (V" + Constants.VERSION + ")!").withStyle(ChatFormatting.AQUA)); - message.append(Component.literal("Teleport Commands is a server-side mod that adds various teleportation related commands").withStyle(ChatFormatting.AQUA)); - - message.append(Component.literal("----").withStyle(ChatFormatting.AQUA)); - message.append(Component.literal("Usage:").withStyle(ChatFormatting.AQUA)); - - return message; - } -} +//package dev.mrsnowy.teleport_commands.commands; +// +//import com.mojang.brigadier.arguments.BoolArgumentType; +//import dev.mrsnowy.teleport_commands.TeleportCommands; +//import dev.mrsnowy.teleport_commands.common.DeathLocation; +//import dev.mrsnowy.teleport_commands.storage.DeathLocationStorage; +//import net.minecraft.ChatFormatting; +//import net.minecraft.commands.Commands; +//import net.minecraft.core.BlockPos; +//import net.minecraft.network.chat.ClickEvent; +//import net.minecraft.network.chat.Component; +//import net.minecraft.server.level.ServerLevel; +//import net.minecraft.server.level.ServerPlayer; +//import net.minecraft.world.phys.Vec3; +// +//import java.util.Optional; +// +//import static dev.mrsnowy.teleport_commands.utils.tools.*; +//import static net.minecraft.commands.Commands.argument; +// +//// TODO! add option to reload registered commands! +// +//public class main { +// +// public static void register(Commands commandManager) { +// +// commandManager.getDispatcher().register(Commands.literal("teleportcommands") +// .then(Commands.literal("help") +// .requires(source -> source.getPlayer() != null) +// .executes(context -> { +// final ServerPlayer player = context.getSource().getPlayerOrException(); +// +// try { +// printCommands(player); +// +// } catch (Exception e) { +// TeleportCommands.LOGGER.error("Error while going back! => ", e); +// player.displayClientMessage(getTranslatedText("commands.teleport_commands.common.error", player).withStyle(ChatFormatting.RED, ChatFormatting.BOLD), true); +// return 1; +// } +// return 0; +// })) +// .then(argument("Disable Safety", BoolArgumentType.bool()) +// .requires(source -> source.getPlayer() != null) +// .executes(context -> { +// final boolean safety = BoolArgumentType.getBool(context, "Disable Safety"); +// final ServerPlayer player = context.getSource().getPlayerOrException(); +// +// try { +//// ToDeathLocation(player, safety); +// +// } catch (Exception e) { +// TeleportCommands.LOGGER.error("Error while going back! => ", e); +// player.displayClientMessage(getTranslatedText("commands.teleport_commands.common.error", player).withStyle(ChatFormatting.RED, ChatFormatting.BOLD), true); +// return 1; +// } +// return 0; +// })) +// ); +// } +// +// +// // ----- +// +// +// // Gets the DeathLocation of the player and teleports the player to it +// private static void printCommands(ServerPlayer player) throws Exception { +// +// player.displayClientMessage(Component.literal("Thank you for using Teleport Commands (V)!").withStyle(ChatFormatting.AQUA), false); +// player.displayClientMessage(Component.literal("Teleport Commands is a server-side mod that adds various teleportation related commands").withStyle(ChatFormatting.AQUA), false); +// +// player.displayClientMessage(Component.literal("----").withStyle(ChatFormatting.AQUA), false); +// +// player.displayClientMessage(Component.literal("Usage:").withStyle(ChatFormatting.AQUA), false); +// } +//} diff --git a/common/src/main/java/dev/mrsnowy/teleport_commands/common/ModCommand.java b/common/src/main/java/dev/mrsnowy/teleport_commands/common/ModCommand.java deleted file mode 100644 index cdcc41a..0000000 --- a/common/src/main/java/dev/mrsnowy/teleport_commands/common/ModCommand.java +++ /dev/null @@ -1,9 +0,0 @@ -package dev.mrsnowy.teleport_commands.common; - -public enum ModCommand { - back, - home, - tpa, - warp, - worldspawn, -} diff --git a/common/src/main/java/dev/mrsnowy/teleport_commands/common/Player.java b/common/src/main/java/dev/mrsnowy/teleport_commands/common/Player.java index 20f7c99..a27cd4a 100644 --- a/common/src/main/java/dev/mrsnowy/teleport_commands/common/Player.java +++ b/common/src/main/java/dev/mrsnowy/teleport_commands/common/Player.java @@ -1,6 +1,7 @@ package dev.mrsnowy.teleport_commands.common; import dev.mrsnowy.teleport_commands.storage.StorageManager; +import net.minecraft.core.BlockPos; import java.util.ArrayList; import java.util.List; diff --git a/common/src/main/java/dev/mrsnowy/teleport_commands/storage/ConfigManager.java b/common/src/main/java/dev/mrsnowy/teleport_commands/storage/ConfigManager.java deleted file mode 100644 index 5de172f..0000000 --- a/common/src/main/java/dev/mrsnowy/teleport_commands/storage/ConfigManager.java +++ /dev/null @@ -1,252 +0,0 @@ -package dev.mrsnowy.teleport_commands.storage; - -import com.google.gson.*; -import dev.mrsnowy.teleport_commands.Constants; -import dev.mrsnowy.teleport_commands.TeleportCommands; - -import java.io.FileReader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; - -public class ConfigManager { - public static Path CONFIG_FILE; - public static ConfigClass CONFIG; - private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); - private static final int defaultVersion = new ConfigClass().getVersion(); - - public static void ConfigInit() { - CONFIG_FILE = TeleportCommands.CONFIG_DIR.resolve("teleport_commands.json"); - - try { - ConfigLoader(); - - } catch (Exception e) { - // crashing is probably better here, otherwise the whole mod will be broken - Constants.LOGGER.error("Error while initializing the config file! Exiting! => ", e); - throw new RuntimeException("Error while initializing the config file! Exiting! => ", e); - } - } - - public static void ConfigLoader() throws Exception { - if (!CONFIG_FILE.toFile().exists() || CONFIG_FILE.toFile().length() == 0) { - Files.createDirectories(TeleportCommands.CONFIG_DIR); - - Constants.LOGGER.warn("Config file was not found or was empty! Initializing config"); - CONFIG = new ConfigClass(); - ConfigSaver(); - Constants.LOGGER.info("Config created successfully!"); - } - - ConfigMigrator(); - - FileReader reader = new FileReader(CONFIG_FILE.toFile()); - CONFIG = GSON.fromJson(reader, ConfigClass.class); - if (CONFIG == null) { - Constants.LOGGER.warn("Config file was empty! Loading defaults..."); - CONFIG = new ConfigClass(); - ConfigSaver(); - } - - ConfigSaver(); // Save it so any missing values get added to the file. - Constants.LOGGER.info("Config loaded successfully!"); - } - - /// This function checks what version the config file is and migrates it to the current version of the mod. - public static void ConfigMigrator() throws Exception { - FileReader reader = new FileReader(CONFIG_FILE.toFile()); - JsonObject jsonObject = GSON.fromJson(reader, JsonObject.class); - - int version = jsonObject.has("version") ? jsonObject.get("version").getAsInt() : 0; - - if (version < defaultVersion) { -// Constants.LOGGER.warn("Config file is v{}, migrating to v{}!", version, defaultVersion); -// -// // Save the storage :3 -// byte[] json = GSON.toJson(jsonObject, JsonArray.class).getBytes(); -// Files.write(CONFIG_FILE, json, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); -// -// Constants.LOGGER.info("Config file migrated to v{} successfully!", defaultVersion); - } else if (version > defaultVersion) { - String message = String.format("Teleport Commands: The config file's version is newer than the supported version, found v%s, expected <= v%s.\n" + - "If you intentionally backported then you can attempt to downgrade the config file located at this location: \"%s\".\n", - version, defaultVersion, CONFIG_FILE.toAbsolutePath()); - - throw new IllegalStateException(message); - } - } - - public static void ConfigSaver() throws Exception { - // todo! maybe throttle saves? - byte[] json = GSON.toJson( ConfigManager.CONFIG ).getBytes(); - - Files.write(CONFIG_FILE, json, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); - } - - public static class ConfigClass { - private final int version = 0; - public Teleporting teleporting = new Teleporting(); - public Back back = new Back(); - public Home home = new Home(); - public Tpa tpa = new Tpa(); - public Warp warp = new Warp(); - public WorldSpawn worldSpawn = new WorldSpawn(); - - public int getVersion() { - return version; - } - - public static final class Teleporting { - private int delay = 5; - private boolean whileMoving = true; - private boolean whileFighting = false; - private int fightCooldown = 10; - - public int getDelay() { - return delay; - } - - public void setDelay(int delay) { - this.delay = delay; - } - - public boolean isWhileMoving() { - return whileMoving; - } - - public void setWhileMoving(boolean whileMoving) { - this.whileMoving = whileMoving; - } - - public boolean isWhileFighting() { - return whileFighting; - } - - public void setWhileFighting(boolean whileFighting) { - this.whileFighting = whileFighting; - } - - public int getFightCooldown() { - return fightCooldown; - } - - public void setFightCooldown(int fightCooldown) { - this.fightCooldown = fightCooldown; - } - } - - public final class Back { - private boolean enabled = true; - private boolean deleteAfterTeleport = false; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public boolean isDeleteAfterTeleport() { - return deleteAfterTeleport; - } - - public void setDeleteAfterTeleport(boolean deleteAfterTeleport) { - this.deleteAfterTeleport = deleteAfterTeleport; - } - } - - public final class Home { - private boolean enabled = true; - private int playerMaximum = 20; - private boolean deleteInvalid = false; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public int getPlayerMaximum() { - return playerMaximum; - } - - public void setPlayerMaximum(int playerMaximum) { - this.playerMaximum = playerMaximum; - } - - public boolean isDeleteInvalid() { - return deleteInvalid; - } - - public void setDeleteInvalid(boolean deleteInvalid) { - this.deleteInvalid = deleteInvalid; - } - } - - public final class Tpa { - private boolean enabled = true; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - } - - public final class Warp { - private boolean enabled = true; - private boolean deleteInvalid = false; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public boolean isDeleteInvalid() { - return deleteInvalid; - } - - public void setDeleteInvalid(boolean deleteInvalid) { - this.deleteInvalid = deleteInvalid; - } - } - - public final class WorldSpawn { - private boolean enabled = true; - private String world_id = "minecraft:overworld"; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getWorld_id() { - return world_id; - } - - public void setWorld_id(String world_id) { - this.world_id = world_id; - } - } - } - - // --- Ideas! --- - // Make config options for disabling certain commands - // Make config options for renaming certain commands - // Make config option for changing required permission level for certain commands - // Make config for setting max homes - // Make config that adds a delay between teleports and when fighting. (in teleport function?) - // Make config that automatically deletes namedLocations (warps/homes) with invalid world id's - // Make config for setting the world_id for /worldspawn ? -} diff --git a/common/src/main/java/dev/mrsnowy/teleport_commands/storage/StorageManager.java b/common/src/main/java/dev/mrsnowy/teleport_commands/storage/StorageManager.java index 5689348..f66aa0d 100644 --- a/common/src/main/java/dev/mrsnowy/teleport_commands/storage/StorageManager.java +++ b/common/src/main/java/dev/mrsnowy/teleport_commands/storage/StorageManager.java @@ -1,12 +1,13 @@ package dev.mrsnowy.teleport_commands.storage; -import com.google.gson.*; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import dev.mrsnowy.teleport_commands.Constants; import dev.mrsnowy.teleport_commands.TeleportCommands; import dev.mrsnowy.teleport_commands.common.NamedLocation; import dev.mrsnowy.teleport_commands.common.Player; -import java.io.FileReader; +import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; @@ -21,150 +22,49 @@ public class StorageManager { public static Path STORAGE_FOLDER; public static Path STORAGE_FILE; public static StorageClass STORAGE; - private static final Gson GSON = new GsonBuilder().create(); - private static final int defaultVersion = new StorageClass().getVersion(); - /// Initializes the StorageManager class and loads the storage from the filesystem. public static void StorageInit() { STORAGE_FOLDER = TeleportCommands.SAVE_DIR.resolve("TeleportCommands/"); STORAGE_FILE = STORAGE_FOLDER.resolve("storage.json"); try { - StorageLoader(); - - } catch (Exception e) { - // crashing is probably better here, otherwise the whole mod will be broken - Constants.LOGGER.error("Error while initializing the storage file! Exiting! => ", e); - throw new RuntimeException("Error while initializing the storage file! Exiting! => ", e); - } - } - - /// Loads the storage from the filesystem - public static void StorageLoader() throws Exception { - - if (!STORAGE_FILE.toFile().exists() || STORAGE_FILE.toFile().length() == 0) { - Constants.LOGGER.warn("Storage file was not found or was empty! Initializing storage"); - - Files.createDirectories(STORAGE_FOLDER); - STORAGE = new StorageClass(); - StorageSaver(); - Constants.LOGGER.info("Storage created successfully!"); - } - - StorageMigrator(); - - FileReader reader = new FileReader(STORAGE_FILE.toFile()); - STORAGE = GSON.fromJson(reader, StorageClass.class); - if (STORAGE == null) { - Constants.LOGGER.warn("Storage file was empty! Initializing storage"); - STORAGE = new StorageClass(); - StorageSaver(); - } - - STORAGE.cleanup(); - - StorageSaver(); // Save it so any missing values get added to the file. - Constants.LOGGER.info("Storage loaded successfully!"); - } - - /// This function checks what version the storage file is and migrates it to the current version of the mod. - public static void StorageMigrator() throws Exception { - FileReader reader = new FileReader(STORAGE_FILE.toFile()); - JsonObject jsonObject = GSON.fromJson(reader, JsonObject.class); - - int version = jsonObject.has("version") ? jsonObject.get("version").getAsInt() : 0; - - if (version < defaultVersion) { - Constants.LOGGER.warn("Storage file is v{}, migrating to v{}!", version, defaultVersion); - - // In v1.1.0 "Player_UUID" got renamed to "UUID". Since the storage file didn't have a version yet, it is set to version 0. - if (version == 0) { - - if (jsonObject.has("Players") && jsonObject.get("Players").isJsonArray()) { - - JsonArray players = jsonObject.get("Players").getAsJsonArray(); - - for (JsonElement playerElement : players) { - JsonObject player = playerElement.getAsJsonObject(); - - String UUID = player.has("Player_UUID") - ? player.get("Player_UUID").getAsString() : (player.has("UUID") - ? player.get("UUID").getAsString() : null); - - if (UUID == null || UUID.isBlank()) { - // remove it then, it's an invalid entry 0.0 - players.remove(player); // may return true or false for success, but idc - - } else { - player.remove("Player_UUID"); - player.addProperty("UUID", UUID); - } - } - } - - jsonObject.addProperty("version", 1); + // check if the folder exists and create it + if (!Files.exists(STORAGE_FOLDER)) { + Files.createDirectories(STORAGE_FOLDER); } - // Save the storage :3 - byte[] json = GSON.toJson(jsonObject, JsonArray.class).getBytes(); - Files.write(STORAGE_FILE, json, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); + // check if the file exists and create it + if (!Files.exists(STORAGE_FILE)) { + Files.createFile(STORAGE_FILE); + } - Constants.LOGGER.info("Storage file migrated to v{} successfully!", defaultVersion); - } else if (version > defaultVersion) { - String message = String.format("Teleport Commands: The storage file's version is newer than the supported version, found v%s, expected <= v%s.\n" + - "If you intentionally backported then you can attempt to downgrade the storage file located at this location: \"%s\".\n", - version, defaultVersion, STORAGE_FILE.toAbsolutePath()); + // create the basic storage if it is empty + if (new File(String.valueOf(STORAGE_FILE)).length() == 0) { + StorageManager.STORAGE = new StorageClass(); + StorageSaver(); // todo! verify that it creates em correctly + } - throw new IllegalStateException(message); + } catch (Exception e) { + Constants.LOGGER.error("Error while creating the storage file! Exiting! => ", e); + // crashing is probably better here, otherwise the whole mod will be broken + System.exit(1); } } - /// Saves the storage to the filesystem public static void StorageSaver() throws Exception { // todo! maybe throttle saves? - byte[] json = GSON.toJson( StorageManager.STORAGE ).getBytes(); + Gson gson = new GsonBuilder().create(); + byte[] json = gson.toJson( StorageManager.STORAGE ).getBytes(); - Files.write(STORAGE_FILE, json, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); + Files.write(STORAGE_FILE, json, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING); } public static class StorageClass { - private final int version = 1; private final ArrayList Warps = new ArrayList<>(); private final ArrayList Players = new ArrayList<>(); - /// Cleans up any values in the storage class - public void cleanup() throws Exception { - for (Player player : Players) { - // Remove players with invalid UUID's - if (player.getUUID().isBlank()) { - Players.remove(player); - } - - List homes = player.getHomes(); - - // Delete any homes with an invalid world_id (if enabled in config) - if (ConfigManager.CONFIG.home.isDeleteInvalid()) { - homes.removeIf(home -> home.getWorld().isEmpty()); - } - - // Remove players with no homes - if (homes.isEmpty()) { - Players.remove(player); - } - } - - // Delete any warps with an invalid world_id (if enabled in config) - if (ConfigManager.CONFIG.warp.isDeleteInvalid()) { - Warps.removeIf(warp -> warp.getWorld().isEmpty()); - } - - StorageSaver(); - } - - public int getVersion() { - return version; - } + // ----- // returns all warps public List getWarps() { diff --git a/common/src/main/java/dev/mrsnowy/teleport_commands/storage/configManager.java b/common/src/main/java/dev/mrsnowy/teleport_commands/storage/configManager.java new file mode 100644 index 0000000..8b307eb --- /dev/null +++ b/common/src/main/java/dev/mrsnowy/teleport_commands/storage/configManager.java @@ -0,0 +1,14 @@ +package dev.mrsnowy.teleport_commands.storage; + +public class configManager { +// Currently nothing to see here... yet + + // --- Ideas! --- + // Make config options for disabling certain commands + // Make config options for renaming certain commands + // Make config option for changing required permission level for certain commands + // Make config for setting max homes + // Make config that adds a delay between teleports and when fighting. (in teleport function?) + // Make config that automatically deletes namedLocations (warps/homes) with invalid world id's + // Make config for setting the world_id for /worldspawn ? +} diff --git a/flake.nix b/flake.nix index 4a9edad..ea84758 100644 --- a/flake.nix +++ b/flake.nix @@ -22,7 +22,6 @@ default = pkgs.mkShell { packages = with pkgs; [ jetbrains.jdk-no-jcef # Jetbrains jdk - just # for the justfile flite # Make mc not complain # Took these from https://github.com/NixOS/nixpkgs/blob/nixos-25.05/pkgs/by-name/pr/prismlauncher/package.nix#L123 diff --git a/justfile b/justfile index 48992e6..fc07239 100644 --- a/justfile +++ b/justfile @@ -1,13 +1,3 @@ -# A justfile :3 - -build: - ./gradlew build - -clean: - ./gradlew clean - -mergeJars: - ./gradlew mergeJars ide: - nohup idea ./ >/dev/null 2>&1 & + nohup idea-ultimate ./ >/dev/null 2>&1 &