From d724d64334aebc8c8d5673f45b76f10d68deef44 Mon Sep 17 00:00:00 2001 From: DaTTV Date: Sun, 16 Feb 2025 18:35:41 +0100 Subject: [PATCH 1/3] Add JSON storage support for clans, homes, and protected blocks - Implemented the **Clan** class to load, reload, and save clan data (including chunk locations and ownership) using Gson and the Paper API. - Added the **Homes** class to manage player home locations, converting JSON-stored coordinates into Bukkit `Location` objects. - Created **ProtectedBlocks** and **ProtectedBlock** classes to handle protected block data (owner, key, and block location) from JSON. --- .gradle/8.8/checksums/checksums.lock | Bin 17 -> 17 bytes .gradle/8.8/checksums/sha1-checksums.bin | Bin 27947 -> 28001 bytes .idea/compiler.xml | 9 + .idea/misc.xml | 3 + .idea/modules/BlazeSMP.main.iml | 5 + .../plugins/papermc/blazesmp/BlazeSMP.java | 4 + .../plugins/papermc/blazesmp/module/Clan.java | 209 +++++++++++++++++- .../blazesmp/module/ProtectedBlock.java | 11 + .../blazesmp/module/manager/Homes.java | 124 +++++++++++ .../module/manager/ProtectedBlocks.java | 129 +++++++++++ src/main/resources/storage/clans/clan.json | 2 + .../resources/storage/protected_blocks.json | 10 +- 12 files changed, 500 insertions(+), 6 deletions(-) create mode 100644 src/main/java/me/freezy/plugins/papermc/blazesmp/module/ProtectedBlock.java create mode 100644 src/main/java/me/freezy/plugins/papermc/blazesmp/module/manager/Homes.java create mode 100644 src/main/java/me/freezy/plugins/papermc/blazesmp/module/manager/ProtectedBlocks.java diff --git a/.gradle/8.8/checksums/checksums.lock b/.gradle/8.8/checksums/checksums.lock index b805391a313425876c39272011e98bcd01a069b1..23b57d2679c818b9cea8b8062c77d014de9a66d4 100644 GIT binary patch literal 17 VcmZR+o2qd{^swUx1~6b`1pqXG1VI1* literal 17 VcmZR+o2qd{^swUx1~6b`0su6A1U>)& diff --git a/.gradle/8.8/checksums/sha1-checksums.bin b/.gradle/8.8/checksums/sha1-checksums.bin index c7b9d8c8113a128fb3d809da29d89ac7364a202f..de94fcc03c221557cadc691d1abcb8f74d504002 100644 GIT binary patch delta 107 zcmZ2|i}B$t#tkMCj2kwaO6+9i*KPj!u|Qjx0St1rH$Rm<%*8lyqv8+ojRqa;n;kt~ zshAl9C3S&V6@*3fk^}d>et4*l?S23+Gs||{_Vv~u7#J9*^3UL!3N}TG)f`A00RWr{ BAN~LU delta 36 ucmV+<0NelJ+5xND0kAX}0k5+)7`X+r1|GT!0eP_@_!qG-pa-)-Na`dM{tk5j diff --git a/.idea/compiler.xml b/.idea/compiler.xml index b86273d..1f51b49 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index f0c744c..2758df8 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,9 @@ + + + diff --git a/.idea/modules/BlazeSMP.main.iml b/.idea/modules/BlazeSMP.main.iml index bbeeb3e..d329813 100644 --- a/.idea/modules/BlazeSMP.main.iml +++ b/.idea/modules/BlazeSMP.main.iml @@ -1,5 +1,10 @@ + + + + + diff --git a/src/main/java/me/freezy/plugins/papermc/blazesmp/BlazeSMP.java b/src/main/java/me/freezy/plugins/papermc/blazesmp/BlazeSMP.java index 9072202..a965c7c 100644 --- a/src/main/java/me/freezy/plugins/papermc/blazesmp/BlazeSMP.java +++ b/src/main/java/me/freezy/plugins/papermc/blazesmp/BlazeSMP.java @@ -4,6 +4,10 @@ import org.bukkit.plugin.java.JavaPlugin; public final class BlazeSMP extends JavaPlugin { + @Override + public void onLoad() { + } + @Override public void onEnable() { // Plugin startup logic diff --git a/src/main/java/me/freezy/plugins/papermc/blazesmp/module/Clan.java b/src/main/java/me/freezy/plugins/papermc/blazesmp/module/Clan.java index 734f8b1..e16dbbf 100644 --- a/src/main/java/me/freezy/plugins/papermc/blazesmp/module/Clan.java +++ b/src/main/java/me/freezy/plugins/papermc/blazesmp/module/Clan.java @@ -1,5 +1,212 @@ package me.freezy.plugins.papermc.blazesmp.module; -public class Clan { +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.Getter; +import lombok.Setter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.World; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; +import java.util.logging.Logger; + +@Getter +public class Clan { + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final String STORAGE_PATH = "plugins/BlazeSMP/storage/clans/"; + private static final Logger LOGGER = Logger.getLogger("Clan"); + + private final UUID uuid; + @Setter private String name; + @Setter private Component tag; + @Setter private UUID leaderUUID; + @Setter private UUID viceUUID; + private final LinkedList members; + private final LinkedList chunks; + private final LinkedHashMap chunkOwnerMap; + private int chunkAmount; + + public Clan(String name, Component tag, UUID leaderUUID) { + this.uuid = UUID.randomUUID(); + this.name = name; + this.tag = tag; + this.leaderUUID = leaderUUID; + this.viceUUID = null; + this.members = new LinkedList<>(); + this.chunks = new LinkedList<>(); + this.chunkOwnerMap = new LinkedHashMap<>(); + this.chunkAmount = 0; + } + + public Clan(UUID clanUUID, String name, Component tag, UUID leaderUUID, UUID viceUUID, + LinkedList members, LinkedList chunks, LinkedHashMap chunkOwnerMap) { + this.uuid = clanUUID; + this.name = name; + this.tag = tag; + this.leaderUUID = leaderUUID; + this.viceUUID = viceUUID; + this.members = members; + this.chunks = chunks; + this.chunkOwnerMap = chunkOwnerMap; + this.chunkAmount = chunks.size(); + } + + /** + * Loads a Clan from the JSON file corresponding to the given UUID. + * + * @param uuid The UUID of the clan. + * @return The loaded Clan or null if the file does not exist. + */ + public static Clan load(UUID uuid) { + File file = new File(STORAGE_PATH + uuid + ".json"); + if (!file.exists()) { + LOGGER.warning("Clan file " + file.getAbsolutePath() + " does not exist."); + return null; + } + try (FileReader reader = new FileReader(file)) { + ClanJson jsonClan = GSON.fromJson(reader, ClanJson.class); + if (jsonClan == null) { + LOGGER.warning("Failed to parse clan JSON for UUID " + uuid); + return null; + } + Component tagComponent = MiniMessage.miniMessage().deserialize(jsonClan.tag); + UUID leader = (jsonClan.leader == null || jsonClan.leader.isEmpty()) ? null : UUID.fromString(jsonClan.leader); + UUID vice = (jsonClan.vize == null || jsonClan.vize.isEmpty()) ? null : UUID.fromString(jsonClan.vize); + + // Convert members + LinkedList memberUUIDs = new LinkedList<>(); + if (jsonClan.members != null) { + for (String s : jsonClan.members) { + if (s != null && !s.isEmpty()) { + memberUUIDs.add(UUID.fromString(s)); + } + } + } + + // Process chunks with world information + LinkedList chunkList = new LinkedList<>(); + LinkedHashMap chunkOwnerMap = new LinkedHashMap<>(); + if (jsonClan.chunks != null && jsonClan.chunks.locations != null) { + for (LocationJson loc : jsonClan.chunks.locations) { + World world = Bukkit.getWorld(loc.world); + if (world == null) { + LOGGER.warning("World '" + loc.world + "' not found. Skipping chunk at " + loc.x + ", " + loc.z); + continue; + } + int x = Integer.parseInt(loc.x); + int z = Integer.parseInt(loc.z); + Chunk chunk = world.getChunkAt(x, z); + chunkList.add(chunk); + UUID ownerUUID = (loc.owner == null || loc.owner.isEmpty()) ? null : UUID.fromString(loc.owner); + chunkOwnerMap.put(chunk, ownerUUID); + } + } + + Clan clan = new Clan(uuid, jsonClan.name, tagComponent, leader, vice, memberUUIDs, chunkList, chunkOwnerMap); + clan.chunkAmount = (jsonClan.chunks != null) ? jsonClan.chunks.amount : chunkList.size(); + return clan; + } catch (IOException e) { + LOGGER.severe("Error loading clan: " + e.getMessage()); + return null; + } + } + + /** + * Reloads the clan from its corresponding JSON file. + */ + public void reload() { + Clan loaded = load(this.uuid); + if (loaded == null) { + LOGGER.warning("Failed to reload clan with UUID: " + this.uuid); + return; + } + this.name = loaded.name; + this.tag = loaded.tag; + this.leaderUUID = loaded.leaderUUID; + this.viceUUID = loaded.viceUUID; + this.members.clear(); + this.members.addAll(loaded.members); + this.chunks.clear(); + this.chunks.addAll(loaded.chunks); + this.chunkOwnerMap.clear(); + this.chunkOwnerMap.putAll(loaded.chunkOwnerMap); + this.chunkAmount = loaded.chunkAmount; + } + + /** + * Saves the clan data to its corresponding JSON file. + */ + public void save() { + ClanJson jsonClan = new ClanJson(); + jsonClan.name = this.name; + jsonClan.tag = MiniMessage.miniMessage().serialize(this.tag); + jsonClan.leader = (this.leaderUUID == null) ? "" : this.leaderUUID.toString(); + jsonClan.vize = (this.viceUUID == null) ? "" : this.viceUUID.toString(); + jsonClan.members = this.members.stream().map(UUID::toString).toList(); + + // Prepare chunks JSON + jsonClan.chunks = new ChunksJson(); + jsonClan.chunks.amount = this.chunkAmount; + jsonClan.chunks.locations = new LinkedList<>(); + for (Chunk chunk : this.chunks) { + LocationJson loc = new LocationJson(); + // Assuming the owner mapping may be null + UUID owner = this.chunkOwnerMap.getOrDefault(chunk, null); + loc.owner = (owner == null) ? "" : owner.toString(); + // Store world name along with chunk coordinates + loc.world = chunk.getWorld().getName(); + loc.x = String.valueOf(chunk.getX()); + loc.z = String.valueOf(chunk.getZ()); + jsonClan.chunks.locations.add(loc); + } + + // Ensure directory exists + File dir = new File(STORAGE_PATH); + if (!dir.exists()) { + if (dir.mkdirs()) { + LOGGER.info("Successfully created folder structure!"); + } else { + LOGGER.severe("Failed to create folder structure!"); + } + } + File file = new File(dir, this.uuid + ".json"); + try (FileWriter writer = new FileWriter(file)) { + GSON.toJson(jsonClan, writer); + } catch (IOException e) { + LOGGER.severe("Error saving clan: " + e.getMessage()); + } + } + + // Helper classes to represent the JSON structure + + private static class ClanJson { + String name; + String tag; + String leader; + String vize; + List members; + ChunksJson chunks; + } + + private static class ChunksJson { + int amount; + List locations; + } + + private static class LocationJson { + String owner; + String world; + String x; + String z; + } } diff --git a/src/main/java/me/freezy/plugins/papermc/blazesmp/module/ProtectedBlock.java b/src/main/java/me/freezy/plugins/papermc/blazesmp/module/ProtectedBlock.java new file mode 100644 index 0000000..46fac6f --- /dev/null +++ b/src/main/java/me/freezy/plugins/papermc/blazesmp/module/ProtectedBlock.java @@ -0,0 +1,11 @@ +package me.freezy.plugins.papermc.blazesmp.module; + +import lombok.Getter; +import org.bukkit.Location; + +import java.util.UUID; + +/** + * Represents a protected block with an owner, a key, and a location. + */ +public record ProtectedBlock(UUID owner, UUID key, Location location) {} diff --git a/src/main/java/me/freezy/plugins/papermc/blazesmp/module/manager/Homes.java b/src/main/java/me/freezy/plugins/papermc/blazesmp/module/manager/Homes.java new file mode 100644 index 0000000..d43e63d --- /dev/null +++ b/src/main/java/me/freezy/plugins/papermc/blazesmp/module/manager/Homes.java @@ -0,0 +1,124 @@ +package me.freezy.plugins.papermc.blazesmp.module.manager; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Logger; + +public class Homes { + private static final String FILE_PATH = "plugins/BlazeSMP/storage/homes.json"; + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final Logger LOGGER = Logger.getLogger("Homes"); + + // Mapping of player UUID to their home location + @Getter private final LinkedHashMap homes; + + public Homes() { + this.homes = new LinkedHashMap<>(); + } + + /** + * Loads homes from the JSON file. + */ + public void load() { + File file = new File(FILE_PATH); + if (!file.exists()) { + LOGGER.info("Homes file does not exist, a new one will be created upon saving."); + return; + } + try (FileReader reader = new FileReader(file)) { + // Use a TypeToken to handle the Map structure + Type type = new TypeToken>() {}.getType(); + Map jsonMap = GSON.fromJson(reader, type); + if (jsonMap == null) { + return; + } + for (Map.Entry entry : jsonMap.entrySet()) { + UUID uuid; + try { + uuid = UUID.fromString(entry.getKey()); + } catch (IllegalArgumentException ex) { + LOGGER.warning("Invalid UUID key in homes file: " + entry.getKey()); + continue; + } + LocationJson locJson = entry.getValue(); + // Assume the default world "world" for homes + World world = Bukkit.getWorld("world"); + if (world == null) { + LOGGER.warning("Default world 'world' not found. Skipping home for " + uuid); + continue; + } + try { + double x = Double.parseDouble(locJson.x); + double y = Double.parseDouble(locJson.y); + double z = Double.parseDouble(locJson.z); + float yaw = Float.parseFloat(locJson.yaw); + float pitch = Float.parseFloat(locJson.pitch); + Location location = new Location(world, x, y, z, yaw, pitch); + homes.put(uuid, location); + } catch (NumberFormatException ex) { + LOGGER.warning("Invalid number format for home of " + uuid + ": " + ex.getMessage()); + } + } + } catch (IOException e) { + LOGGER.severe("Error loading homes: " + e.getMessage()); + } + } + + /** + * Saves the homes mapping to the JSON file. + */ + public void save() { + // Convert the homes map to a map of String keys (UUIDs) to LocationJson objects. + Map jsonMap = new LinkedHashMap<>(); + for (Map.Entry entry : homes.entrySet()) { + Location location = entry.getValue(); + LocationJson locJson = new LocationJson(); + locJson.x = String.valueOf(location.getX()); + locJson.y = String.valueOf(location.getY()); + locJson.z = String.valueOf(location.getZ()); + locJson.yaw = String.valueOf(location.getYaw()); + locJson.pitch = String.valueOf(location.getPitch()); + jsonMap.put(entry.getKey().toString(), locJson); + } + File file = new File(FILE_PATH); + // Ensure the parent directory exists + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) { + if (parent.mkdirs()) { + LOGGER.info("Successfully created folder structure!"); + } else { + LOGGER.severe("Failed to create folder structure!"); + } + } + try (FileWriter writer = new FileWriter(file)) { + GSON.toJson(jsonMap, writer); + } catch (IOException e) { + LOGGER.severe("Error saving homes: " + e.getMessage()); + } + } + + /** + * Inner class representing the JSON structure for a location. + */ + private static class LocationJson { + String x; + String y; + String z; + String yaw; + String pitch; + } +} diff --git a/src/main/java/me/freezy/plugins/papermc/blazesmp/module/manager/ProtectedBlocks.java b/src/main/java/me/freezy/plugins/papermc/blazesmp/module/manager/ProtectedBlocks.java new file mode 100644 index 0000000..4460fb7 --- /dev/null +++ b/src/main/java/me/freezy/plugins/papermc/blazesmp/module/manager/ProtectedBlocks.java @@ -0,0 +1,129 @@ +package me.freezy.plugins.papermc.blazesmp.module.manager; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import me.freezy.plugins.papermc.blazesmp.module.ProtectedBlock; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.logging.Logger; + +/** + * Manager class for loading and saving protected blocks. + */ +public class ProtectedBlocks { + private static final String FILE_PATH = "plugins/BlazeSMP/storage/protected_blocks.json"; + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final Logger LOGGER = Logger.getLogger("ProtectedBlocks"); + + // List of protected blocks + private final List blocks; + + public ProtectedBlocks() { + this.blocks = new ArrayList<>(); + } + + public List getBlocks() { + return blocks; + } + + /** + * Loads protected blocks from the JSON file. + */ + public void load() { + File file = new File(FILE_PATH); + if (!file.exists()) { + LOGGER.info("Protected blocks file does not exist, a new one will be created upon saving."); + return; + } + try (FileReader reader = new FileReader(file)) { + // Deserialize the JSON into a ProtectedBlocksJson object + ProtectedBlocksJson jsonData = GSON.fromJson(reader, ProtectedBlocksJson.class); + if (jsonData == null || jsonData.blocks == null) { + return; + } + blocks.clear(); + for (BlockJson blockJson : jsonData.blocks) { + try { + UUID owner = (blockJson.owner == null || blockJson.owner.isEmpty()) + ? null : UUID.fromString(blockJson.owner); + UUID key = (blockJson.key == null || blockJson.key.isEmpty()) + ? null : UUID.fromString(blockJson.key); + + // Use default world "world" since no world field is provided + World world = Bukkit.getWorld("world"); + if (world == null) { + LOGGER.warning("Default world 'world' not found. Skipping block for owner: " + blockJson.owner); + continue; + } + double x = Double.parseDouble(blockJson.location.x); + double y = Double.parseDouble(blockJson.location.y); + double z = Double.parseDouble(blockJson.location.z); + Location location = new Location(world, x, y, z); + blocks.add(new ProtectedBlock(owner, key, location)); + } catch (Exception e) { + LOGGER.warning("Error loading a protected block: " + e.getMessage()); + } + } + } catch (IOException e) { + LOGGER.severe("Error loading protected blocks: " + e.getMessage()); + } + } + + /** + * Saves the protected blocks to the JSON file. + */ + public void save() { + ProtectedBlocksJson jsonData = new ProtectedBlocksJson(); + jsonData.blocks = new ArrayList<>(); + for (ProtectedBlock block : blocks) { + BlockJson blockJson = new BlockJson(); + blockJson.owner = (block.owner() == null) ? "" : block.owner().toString(); + blockJson.key = (block.key() == null) ? "" : block.key().toString(); + blockJson.location = new LocationJson(); + blockJson.location.x = String.valueOf(block.location().getX()); + blockJson.location.y = String.valueOf(block.location().getY()); + blockJson.location.z = String.valueOf(block.location().getZ()); + jsonData.blocks.add(blockJson); + } + File file = new File(FILE_PATH); + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) { + if (parent.mkdirs()) { + LOGGER.info("Successfully created folder structure!"); + } else { + LOGGER.severe("Failed to create folder structure!"); + } } + try (FileWriter writer = new FileWriter(file)) { + GSON.toJson(jsonData, writer); + } catch (IOException e) { + LOGGER.severe("Error saving protected blocks: " + e.getMessage()); + } + } + + // Inner classes to match the JSON structure + + private static class ProtectedBlocksJson { + List blocks; + } + + private static class BlockJson { + String owner; + String key; + LocationJson location; + } + + private static class LocationJson { + String x; + String y; + String z; + } +} diff --git a/src/main/resources/storage/clans/clan.json b/src/main/resources/storage/clans/clan.json index c7c8416..c3ffca2 100644 --- a/src/main/resources/storage/clans/clan.json +++ b/src/main/resources/storage/clans/clan.json @@ -9,11 +9,13 @@ "locations": [ { "owner": "", + "world": "", "x": "12", "z": "4" }, { "owner": "", + "world": "", "x": "13", "z": "4" } diff --git a/src/main/resources/storage/protected_blocks.json b/src/main/resources/storage/protected_blocks.json index 3433cc2..a49c59f 100644 --- a/src/main/resources/storage/protected_blocks.json +++ b/src/main/resources/storage/protected_blocks.json @@ -1,12 +1,12 @@ { "blocks": [ { - "owner": "", - "key": "", + "owner": "uuid", + "key": "uuid", "location": { - "x": "", - "y": "", - "z": "" + "x": "blockx", + "y": "blocky", + "z": "blockz" } } ] From e4e48db818cd4edf102011c1f353093d77f1bc2e Mon Sep 17 00:00:00 2001 From: DaTTV Date: Sun, 16 Feb 2025 18:49:38 +0100 Subject: [PATCH 2/3] Added clan manager! Loading all storage files --- .idea/gradle.xml | 1 + .../plugins/papermc/blazesmp/BlazeSMP.java | 14 ++ .../blazesmp/module/manager/Clans.java | 127 ++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 src/main/java/me/freezy/plugins/papermc/blazesmp/module/manager/Clans.java diff --git a/.idea/gradle.xml b/.idea/gradle.xml index f9163b4..ce1c62c 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,5 +1,6 @@ +