diff --git a/.gradle/8.8/checksums/checksums.lock b/.gradle/8.8/checksums/checksums.lock
index b805391..23b57d2 100644
Binary files a/.gradle/8.8/checksums/checksums.lock and b/.gradle/8.8/checksums/checksums.lock differ
diff --git a/.gradle/8.8/checksums/sha1-checksums.bin b/.gradle/8.8/checksums/sha1-checksums.bin
index c7b9d8c..de94fcc 100644
Binary files a/.gradle/8.8/checksums/sha1-checksums.bin and b/.gradle/8.8/checksums/sha1-checksums.bin differ
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