Bläddra i källkod

Better Claim management, Clan Settings, improved access to modules and individual parts of code

Jan 2 veckor sedan
förälder
incheckning
12bb4e7733
41 ändrade filer med 684 tillägg och 246 borttagningar
  1. 31 0
      src/main/java/me/lethunderhawk/bazaarflux/service/Services.java
  2. 16 4
      src/main/java/me/lethunderhawk/bazaarflux/util/CustomHeadCreator.java
  3. 1 4
      src/main/java/me/lethunderhawk/bazaarflux/util/gui/ConfirmationMenu.java
  4. 6 4
      src/main/java/me/lethunderhawk/bazaarflux/util/gui/InventoryGUI.java
  5. 0 1
      src/main/java/me/lethunderhawk/bazaarflux/util/gui/input/SignMenuFactory.java
  6. 10 5
      src/main/java/me/lethunderhawk/bazaarflux/util/interfaces/BazaarFluxModule.java
  7. 9 1
      src/main/java/me/lethunderhawk/clans/Clan.java
  8. 5 7
      src/main/java/me/lethunderhawk/clans/ClanManager.java
  9. 26 23
      src/main/java/me/lethunderhawk/clans/ClanModule.java
  10. 22 2
      src/main/java/me/lethunderhawk/clans/claim/Claim.java
  11. 49 26
      src/main/java/me/lethunderhawk/clans/claim/ClaimListener.java
  12. 132 28
      src/main/java/me/lethunderhawk/clans/claim/ClaimManager.java
  13. 7 5
      src/main/java/me/lethunderhawk/clans/command/ClanCommand.java
  14. 57 0
      src/main/java/me/lethunderhawk/clans/gui/AdminMenuGUI.java
  15. 32 15
      src/main/java/me/lethunderhawk/clans/gui/ClaimSettingsGUI.java
  16. 7 5
      src/main/java/me/lethunderhawk/clans/gui/ClanMenu.java
  17. 108 15
      src/main/java/me/lethunderhawk/clans/gui/ClanSettingsGUI.java
  18. 3 2
      src/main/java/me/lethunderhawk/clans/placeholder/ClanPlaceHolder.java
  19. 2 0
      src/main/java/me/lethunderhawk/clans/settings/ClanSetting.java
  20. 24 0
      src/main/java/me/lethunderhawk/clans/settings/ClanSettings.java
  21. 7 7
      src/main/java/me/lethunderhawk/custom/item/CustomItemModule.java
  22. 8 6
      src/main/java/me/lethunderhawk/custom/item/concrete/ClaimTool.java
  23. 21 13
      src/main/java/me/lethunderhawk/economy/EconomyModule.java
  24. 3 2
      src/main/java/me/lethunderhawk/economy/currency/EconomyManager.java
  25. 2 2
      src/main/java/me/lethunderhawk/economy/util/EconomyUtil.java
  26. 32 25
      src/main/java/me/lethunderhawk/main/Main.java
  27. 6 6
      src/main/java/me/lethunderhawk/minion/MinionModule.java
  28. 2 1
      src/main/java/me/lethunderhawk/minion/api/MinionLevel.java
  29. 2 1
      src/main/java/me/lethunderhawk/minion/enchantedVariant/item/abstraction/EnchantedItem.java
  30. 2 1
      src/main/java/me/lethunderhawk/minion/enchantedVariant/recipe/EnchantedItemRecipe.java
  31. 2 3
      src/main/java/me/lethunderhawk/minion/factory/MinionFactory.java
  32. 4 2
      src/main/java/me/lethunderhawk/minion/item/MinionItem.java
  33. 1 2
      src/main/java/me/lethunderhawk/minion/manager/MinionManager.java
  34. 1 1
      src/main/java/me/lethunderhawk/minion/runtime/PlacedMinion.java
  35. 4 3
      src/main/java/me/lethunderhawk/minion/ui/MinionMenu.java
  36. 1 2
      src/main/java/me/lethunderhawk/minion/ui/minionList/MinionLevelListMenu.java
  37. 1 2
      src/main/java/me/lethunderhawk/minion/ui/minionList/MinionListMenu.java
  38. 18 7
      src/main/java/me/lethunderhawk/tradeplugin/TradeModule.java
  39. 10 6
      src/main/java/me/lethunderhawk/tradeplugin/listener/TradeInventoryListener.java
  40. 2 1
      src/main/java/me/lethunderhawk/tradeplugin/trade/TradeRequestManager.java
  41. 8 6
      src/main/java/me/lethunderhawk/tradeplugin/trade/TradeSession.java

+ 31 - 0
src/main/java/me/lethunderhawk/bazaarflux/service/Services.java

@@ -0,0 +1,31 @@
+package me.lethunderhawk.bazaarflux.service;
+
+import me.lethunderhawk.bazaarflux.util.interfaces.BazaarFluxModule;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public final class Services {
+
+    private static final Map<Class<?>, Object> services = new ConcurrentHashMap<>();
+
+    public static <T> void register(Class<T> type, T service) {
+        services.put(type, service);
+    }
+    public static <T> void registerModule(Class<? extends BazaarFluxModule> type, T service) {
+        services.put(type, service);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T get(Class<T> type) {
+        return (T) services.get(type);
+    }
+    @SuppressWarnings("unchecked")
+    public static <T> T unregister(Class<T> type) {
+        return (T) services.remove(type);
+    }
+
+    public static <T> void unregisterModule(Class<? extends BazaarFluxModule> type) {
+        services.remove(type);
+    }
+}

+ 16 - 4
src/main/java/me/lethunderhawk/bazaarflux/util/CustomHeadCreator.java

@@ -2,9 +2,11 @@ package me.lethunderhawk.bazaarflux.util;
 
 import com.destroystokyo.paper.profile.PlayerProfile;
 import com.destroystokyo.paper.profile.ProfileProperty;
+import me.lethunderhawk.main.util.UnItalic;
 import net.kyori.adventure.text.Component;
 import org.bukkit.Bukkit;
 import org.bukkit.Material;
+import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.meta.SkullMeta;
 
@@ -14,7 +16,6 @@ import java.util.UUID;
 public class CustomHeadCreator {
 
     public static ItemStack createCustomHead(String textureValue, Component displayName, Component loreText) {
-        // Create the player head ItemStack
         ItemStack playerHead = createCustomHead(textureValue);
         SkullMeta meta = (SkullMeta) playerHead.getItemMeta();
 
@@ -23,10 +24,9 @@ public class CustomHeadCreator {
 
         playerHead.setItemMeta(meta);
 
-        return playerHead; // Return the custom head ItemStack
+        return playerHead;
     }
     public static ItemStack createCustomHead(String textureValue, Component displayName, List<Component> loreText) {
-        // Create the player head ItemStack
         ItemStack playerHead = createCustomHead(textureValue);
         SkullMeta meta = (SkullMeta) playerHead.getItemMeta();
 
@@ -35,7 +35,19 @@ public class CustomHeadCreator {
 
         playerHead.setItemMeta(meta);
 
-        return playerHead; // Return the custom head ItemStack
+        return playerHead;
+    }
+    public static ItemStack createCustomHead(Player player, Component displayName, List<Component> loreText) {
+
+        ItemStack playerHead = new ItemStack(Material.PLAYER_HEAD);
+        SkullMeta meta = (SkullMeta) playerHead.getItemMeta();
+
+        meta.setOwningPlayer(player);
+        meta.displayName(displayName);
+        meta.lore(loreText);
+
+        playerHead.setItemMeta(UnItalic.removeItalicFromMeta(meta));
+        return playerHead;
     }
 
     public static ItemStack createCustomHead(String textureValue) {

+ 1 - 4
src/main/java/me/lethunderhawk/clans/gui/ConfirmationMenu.java → src/main/java/me/lethunderhawk/bazaarflux/util/gui/ConfirmationMenu.java

@@ -1,6 +1,5 @@
-package me.lethunderhawk.clans.gui;
+package me.lethunderhawk.bazaarflux.util.gui;
 
-import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
 import me.lethunderhawk.main.util.UnItalic;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.format.NamedTextColor;
@@ -16,7 +15,6 @@ public class ConfirmationMenu extends InventoryGUI {
 
     public ConfirmationMenu(String title, Consumer<Player> callback ) {
         super(title, 27);
-
         this.callback = callback;
         setupItems();
     }
@@ -32,7 +30,6 @@ public class ConfirmationMenu extends InventoryGUI {
             callback.accept(p);
             openPrevious(p);
         });
-
         ItemStack NoPleaseNot = new ItemStack(Material.BARRIER);
         ItemMeta noMeta = NoPleaseNot.getItemMeta();
         noMeta.displayName(Component.text("No, i changed my mind", NamedTextColor.RED));

+ 6 - 4
src/main/java/me/lethunderhawk/bazaarflux/util/gui/InventoryGUI.java

@@ -84,7 +84,9 @@ public abstract class InventoryGUI implements InventoryHolder {
             }
         }
     }
-
+    public void openWithListener(Player player){
+        InventoryManager.openFor(player, this);
+    }
     /**
      * Opens this GUI for a player.
      */
@@ -96,12 +98,12 @@ public abstract class InventoryGUI implements InventoryHolder {
      * Opens another GUI and remembers this one for navigation.
      */
     public void openNext(Player player, InventoryGUI nextGui) {
-        // Push current GUI onto the next GUI's stack
         nextGui.previousGuis.push(this);
-        // Actually open the next GUI
         InventoryManager.openFor(player, nextGui);
     }
-
+    public boolean hasPreviousGUI() {
+        return !previousGuis.isEmpty();
+    }
 
     /**
      * Opens the previous GUI if available.

+ 0 - 1
src/main/java/me/lethunderhawk/bazaarflux/util/gui/input/SignMenuFactory.java

@@ -53,7 +53,6 @@ public final class SignMenuFactory {
                     if (!success && menu.reopenIfFail && !menu.forceClose) {
                         Bukkit.getScheduler().runTaskLater(plugin, () -> menu.open(player), 2L);
                     }
-
                     if (player.isOnline()) {
                         player.sendBlockChange(
                                 menu.location,

+ 10 - 5
src/main/java/me/lethunderhawk/bazaarflux/util/interfaces/BazaarFluxModule.java

@@ -3,12 +3,17 @@ package me.lethunderhawk.bazaarflux.util.interfaces;
 import me.lethunderhawk.bazaarflux.util.MessageSender;
 import net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.text.Component;
+import org.bukkit.plugin.java.JavaPlugin;
 
-public interface BazaarFluxModule {
-    String getPrefix();
-    void onEnable();
-    void onDisable();
-    default void sendText(Audience receiver, Component infoText){
+public abstract class BazaarFluxModule{
+    protected JavaPlugin plugin;
+    public BazaarFluxModule(JavaPlugin plugin) {
+        this.plugin = plugin;
+    }
+    public abstract String getPrefix();
+    public abstract void onEnable();
+    public abstract void onDisable();
+    void sendText(Audience receiver, Component infoText){
         MessageSender.sendText(receiver, infoText, getPrefix());
     }
 }

+ 9 - 1
src/main/java/me/lethunderhawk/clans/Clan.java

@@ -17,7 +17,7 @@ public class Clan {
     private final Set<UUID> members;
     private final Map<String, UUID> pendingRequests = new HashMap<>(); //name of player, Player UUID
     private final String name;
-    private final ClanSettings settings = new ClanSettings();
+    private final ClanSettings settings;
     private final List<Claim> claims = new ArrayList<>();
     private final UUID id;
 
@@ -26,6 +26,14 @@ public class Clan {
         this.owner = owner;
         this.members = members;
         this.id = id;
+        this.settings = new ClanSettings();
+    }
+    public Clan(String name, UUID owner, UUID id, Set<UUID> members, ClanSettings settings){
+        this.name = name;
+        this.owner = owner;
+        this.members = members;
+        this.id = id;
+        this.settings = settings;
     }
     public String toTabComplete() {
         return name.toLowerCase().trim();

+ 5 - 7
src/main/java/me/lethunderhawk/clans/ClanManager.java

@@ -77,14 +77,11 @@ public class ClanManager {
                     .map(UUID::fromString)
                     .collect(Collectors.toSet());
 
-//            Set<ClanSettings> clanSettings = clansConfig.getStringList(base + ".rules")
-//                    .stream()
-//                    .map(ClanSettings::fromString)
-//                    .collect(Collectors.toSet());
+            Map<String, Object> settingsMap = Objects.requireNonNull(clansConfig.getConfigurationSection(base + ".settings")).getValues(false);
 
-            Clan clan = new Clan(name, owner, id, members);
+            ClanSettings settings = ClanSettings.fromMap(settingsMap);
 
-//            clan.setRules(clanSettings);
+            Clan clan = new Clan(name, owner, id, members, settings);
 
             // ---- Claims laden ----
             List<Map<?, ?>> claimData = clansConfig.getMapList(base + ".claims");
@@ -98,6 +95,7 @@ public class ClanManager {
                 }
             }
 
+
             clans.put(id, clan);
         }
     }
@@ -124,7 +122,7 @@ public class ClanManager {
             }
 
             clansConfig.set(path + ".claims", claimList);
-            clansConfig.set(path + ".settings", basicClanSettings);
+            clansConfig.set(path + ".settings", clan.getSettings().toStringMap());
         }
 
         try {

+ 26 - 23
src/main/java/me/lethunderhawk/clans/ClanModule.java

@@ -1,6 +1,8 @@
 package me.lethunderhawk.clans;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.bazaarflux.util.MessageSender;
+import me.lethunderhawk.bazaarflux.util.interfaces.BazaarFluxModule;
 import me.lethunderhawk.clans.claim.ClaimListener;
 import me.lethunderhawk.clans.claim.ClaimManager;
 import me.lethunderhawk.clans.command.ClanCommand;
@@ -11,27 +13,36 @@ import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.format.NamedTextColor;
 import org.bukkit.event.HandlerList;
 
-public class ClanModule {
-    private ClanManager clanManager;
-    private ClaimManager claimManager;
-    private ClaimListener claimListener;
+public class ClanModule extends BazaarFluxModule {
+
+    public ClanModule() {
+        super(Services.get(Main.class));
+    }
 
     public String getPrefix(){
         return "[Clan]";
     }
 
     public void onEnable(){
+        Main mainPlugin = Services.get(Main.class);
+        ClaimManager claimManager = new ClaimManager();
+        ClanManager clanManager = new ClanManager(mainPlugin, claimManager);
+
+        Services.register(ClaimManager.class, claimManager);
+        Services.register(ClanManager.class, clanManager);
+
+
+
+        ClaimListener claimListener = new ClaimListener(claimManager, clanManager);
+        Services.register(ClaimListener.class, claimListener);
 
-        claimManager = new ClaimManager();
-        clanManager = new ClanManager(Main.getInstance(), claimManager);
-        this.claimListener = new ClaimListener(claimManager, clanManager);
-        Main.getInstance().getCommand("clan").setExecutor(new ClanCommand(clanManager));
-        Main.getInstance().getCommand("clan").setTabCompleter(new ClanCommand(clanManager));
+        mainPlugin.getCommand("clan").setExecutor(new ClanCommand(clanManager));
+        mainPlugin.getCommand("clan").setTabCompleter(new ClanCommand(clanManager));
 
-        Main.getInstance().getServer().getPluginManager().registerEvents(claimListener, Main.getInstance());
-        //Main.getInstance().getServer().getPluginManager().registerEvents(new ToolListener(), Main.getInstance());
-        if (Main.getInstance().getServer().getPluginManager().isPluginEnabled("PlaceholderAPI")) {
-            new ClanPlaceHolder(clanManager).register();
+        mainPlugin.getServer().getPluginManager().registerEvents(claimListener, mainPlugin);
+
+        if (mainPlugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI")) {
+            new ClanPlaceHolder().register();
         }
 
     }
@@ -42,16 +53,8 @@ public class ClanModule {
         MessageSender.sendText(receiver, infoText, "[Clan]");
     }
 
-    public ClanManager getClanManager() {
-        return clanManager;
-    }
-
-    public ClaimManager getClaimManager() {
-        return claimManager;
-    }
-
     public void onDisable(){
-        HandlerList.unregisterAll(claimListener);
-        clanManager.saveClans();
+        HandlerList.unregisterAll(Services.get(ClaimListener.class));
+        Services.get(ClanManager.class).saveClans();
     }
 }

+ 22 - 2
src/main/java/me/lethunderhawk/clans/claim/Claim.java

@@ -1,16 +1,21 @@
 package me.lethunderhawk.clans.claim;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.clans.Clan;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.clans.ClanManager;
+import org.bukkit.Chunk;
 import org.bukkit.Location;
 
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 
 public class Claim {
 
     private final UUID clanId; // or clan name if you don’t have IDs
     private final String world;
+    Set<Long> chunks = new HashSet<>();
 
     private final int minX, maxX;
     private final int minZ, maxZ;
@@ -53,6 +58,21 @@ public class Claim {
         return (maxX - minX + 1)
                 * (maxZ - minZ + 1);
     }
+    public Set<Long> getCoveredChunks() {
+        if(!chunks.isEmpty()) return chunks;
+
+        int minChunkX = minX >> 4;
+        int maxChunkX = maxX >> 4;
+        int minChunkZ = minZ >> 4;
+        int maxChunkZ = maxZ >> 4;
+
+        for (int x = minChunkX; x <= maxChunkX; x++) {
+            for (int z = minChunkZ; z <= maxChunkZ; z++) {
+                chunks.add(Chunk.getChunkKey(x, z));
+            }
+        }
+        return chunks;
+    }
     public UUID getClanId(){
         return clanId;
     }
@@ -80,7 +100,7 @@ public class Claim {
     }
     public String getName() {
         if(name == null || name.isEmpty()) {
-            Clan clan = Main.getInstance().getClanModule().getClanManager().getClanById(clanId);
+            Clan clan = Services.get(ClanManager.class).getClanById(clanId);
             if(clan == null) return "Unknown";
             else return clan.getName();
         }

+ 49 - 26
src/main/java/me/lethunderhawk/clans/claim/ClaimListener.java

@@ -1,9 +1,11 @@
 package me.lethunderhawk.clans.claim;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.clans.Clan;
 import me.lethunderhawk.clans.ClanManager;
 import me.lethunderhawk.clans.settings.ClanSetting;
-import me.lethunderhawk.main.Main;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
 import org.bukkit.Location;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
@@ -11,12 +13,14 @@ import org.bukkit.block.Container;
 import org.bukkit.block.data.BlockData;
 import org.bukkit.block.data.Openable;
 import org.bukkit.block.data.Powerable;
+import org.bukkit.entity.Player;
 import org.bukkit.event.EventHandler;
 import org.bukkit.event.Listener;
 import org.bukkit.event.block.Action;
 import org.bukkit.event.block.BlockBreakEvent;
 import org.bukkit.event.block.BlockIgniteEvent;
 import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
 import org.bukkit.event.player.PlayerInteractEntityEvent;
 import org.bukkit.event.player.PlayerInteractEvent;
 
@@ -33,34 +37,34 @@ public class ClaimListener implements Listener {
 
     @EventHandler(ignoreCancelled = true)
     public void onPlayerInteract(PlayerInteractEvent event) {
-        if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
+        if (event.getAction() == Action.RIGHT_CLICK_BLOCK ) {
+            Block block = event.getClickedBlock();
+            if (block == null) return;
 
-        Block block = event.getClickedBlock();
-        if (block == null) return;
+            Location loc = block.getLocation();
 
-        Location loc = block.getLocation();
+            BlockData data = block.getBlockData();
 
-        BlockData data = block.getBlockData();
-
-        // Containers
-        if (block.getState() instanceof Container) {
-            if (preventChange(event.getPlayer().getUniqueId(), loc, ClanSetting.OPEN_CONTAINER)) {
-                event.setCancelled(true);
+            // Containers
+            if (block.getState() instanceof Container) {
+                if (preventChange(event.getPlayer().getUniqueId(), loc, ClanSetting.OPEN_CONTAINER)) {
+                    event.setCancelled(true);
+                }
+                return;
             }
-            return;
-        }
-        Material blockType = block.getType();
-        if (blockType.equals(Material.ANVIL) || blockType.equals(Material.CHIPPED_ANVIL)|| blockType.equals(Material.DAMAGED_ANVIL)) {
-            if (preventChange(event.getPlayer().getUniqueId(), loc, ClanSetting.USE_ANVIL)) {
-                event.setCancelled(true);
+            Material blockType = block.getType();
+            if (blockType.equals(Material.ANVIL) || blockType.equals(Material.CHIPPED_ANVIL)|| blockType.equals(Material.DAMAGED_ANVIL)) {
+                if (preventChange(event.getPlayer().getUniqueId(), loc, ClanSetting.USE_ANVIL)) {
+                    event.setCancelled(true);
+                }
+                return;
             }
-            return;
-        }
 
-        // Doors, fence gates, trapdoors, etc.
-        if (data instanceof Openable || data instanceof Powerable) {
-            if (preventChange(event.getPlayer().getUniqueId(), loc, ClanSetting.INTERACT_BLOCK)) {
-                event.setCancelled(true);
+            // Doors, fence gates, trapdoors, etc.
+            if (data instanceof Openable || data instanceof Powerable) {
+                if (preventChange(event.getPlayer().getUniqueId(), loc, ClanSetting.INTERACT_BLOCK)) {
+                    event.setCancelled(true);
+                }
             }
         }
     }
@@ -81,7 +85,17 @@ public class ClaimListener implements Listener {
             e.getPlayer().sendMessage("§cThis land belongs to another clan!");
         }
     }
-
+    @EventHandler
+    public void onPlayerHittingEvent(EntityDamageByEntityEvent e) {
+        if(!(e.getDamager() instanceof Player p)) return;
+        if(e.getEntity() instanceof Player && preventForAll(e.getEntity().getLocation(), ClanSetting.ALLOW_HITTING_PLAYERS)){
+            e.setCancelled(true);
+            e.getDamager().sendMessage(Component.text("You cant damage other Players in this region!", NamedTextColor.RED));
+        }else if(!(e.getEntity() instanceof Player) && preventForAll(e.getEntity().getLocation(), ClanSetting.ALLOW_HITTING_MOBS)){
+            e.setCancelled(true);
+            e.getDamager().sendMessage(Component.text("You cant damage Mobs in this region!", NamedTextColor.RED));
+        }
+    }
     @EventHandler
     public void onEntityInteract(PlayerInteractEntityEvent e){
         if(preventChange(e.getPlayer().getUniqueId(), e.getRightClicked().getLocation(), ClanSetting.INTERACT_ENTITY)){
@@ -97,11 +111,20 @@ public class ClaimListener implements Listener {
             e.getPlayer().sendMessage("§cThis land belongs to another clan!");
         }
     }
-
+    private boolean preventForAll(Location location, ClanSetting setting){
+        Claim claim = claimManager.getClaimAt(location);
+        if(claim != null){
+            Clan clan = Services.get(ClanManager.class).getClanById(claim.getClanId());
+            if (clan != null) {
+                return !clan.allows(setting);
+            }
+        }
+        return false;
+    }
     private boolean preventChange(UUID playerUUID, Location location, ClanSetting setting){
         Claim claim = claimManager.getClaimAt(location);
         if(claim != null){
-            Clan clan = Main.getInstance().getClanModule().getClanManager().getClanById(claim.getClanId());
+            Clan clan = Services.get(ClanManager.class).getClanById(claim.getClanId());
             if (clan != null && !clan.isInClan(playerUUID)) {
                 return !clan.allows(setting);
             }

+ 132 - 28
src/main/java/me/lethunderhawk/clans/claim/ClaimManager.java

@@ -1,57 +1,161 @@
 package me.lethunderhawk.clans.claim;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.clans.Clan;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.clans.ClanManager;
 import org.bukkit.Location;
+import org.bukkit.entity.Player;
 
-import javax.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
 
-public class ClaimManager {
+public final class ClaimManager {
 
-    private List<Claim> allClaims = new ArrayList<>();
+    // All claims (authoritative list)
+    private final List<Claim> allClaims = new ArrayList<>();
+
+    // ChunkKey -> Claims touching this chunk
+    private final Map<Long, List<Claim>> claimsByChunk = new HashMap<>();
+
+    // Player -> last known claim (scoreboard cache)
+    private final Map<UUID, Claim> playerClaimCache = new HashMap<>();
+
+    /* =====================================================
+       LOOKUP
+       ===================================================== */
 
     public Claim getClaimAt(Location loc) {
-        for (Claim c : allClaims) {
-            if (c.contains(loc)) return c;
+        long chunkKey = loc.getChunk().getChunkKey();
+        List<Claim> claims = claimsByChunk.get(chunkKey);
+
+        if (claims == null) return null;
+
+        for (Claim c : claims) {
+            if (c.contains(loc)) {
+                return c;
+            }
         }
         return null;
     }
 
-    public void registerClaim(Claim claim){
+    public Claim getClaimAt(Player player) {
+        UUID id = player.getUniqueId();
+        Location loc = player.getLocation();
+
+        Claim cached = playerClaimCache.get(id);
+        if (cached != null && cached.contains(loc)) {
+            return cached; // FAST PATH
+        }
+
+        Claim fresh = getClaimAt(loc);
+        playerClaimCache.put(id, fresh);
+        return fresh;
+    }
+
+    /* =====================================================
+       REGISTRATION
+       ===================================================== */
+
+    public void registerClaim(Claim claim) {
         allClaims.add(claim);
+
+        for (long chunkKey : claim.getCoveredChunks()) {
+            claimsByChunk
+                    .computeIfAbsent(chunkKey, k -> new ArrayList<>())
+                    .add(claim);
+        }
     }
 
-    public boolean overlaps(Claim a, Claim b) {
-        if (!a.getWorld().equals(b.getWorld())) return false;
+    /* =====================================================
+       REMOVAL
+       ===================================================== */
 
-        return a.getMinX() <= b.getMaxX() && a.getMaxX() >= b.getMinX()
-                && a.getMinZ() <= b.getMaxZ() && a.getMaxZ() >= b.getMinZ();
+    public void removeClaim(Claim claim) {
+        allClaims.remove(claim);
+
+        for (long chunkKey : claim.getCoveredChunks()) {
+            List<Claim> list = claimsByChunk.get(chunkKey);
+            if (list != null) {
+                list.remove(claim);
+                if (list.isEmpty()) {
+                    claimsByChunk.remove(chunkKey);
+                }
+            }
+        }
+
+        // Clean player cache
+        playerClaimCache.values().removeIf(c -> c == claim);
+
+        Clan clan = Services.get(ClanManager.class).getClanById(claim.getClanId());
+        if (clan != null) {
+            clan.removeClaim(claim);
+        }
     }
+    public void removeClaims(List<Claim> claims) {
+        if(claims == null) return;
+        for(Claim claim : claims) {
+            allClaims.remove(claim);
+
+            for (long chunkKey : claim.getCoveredChunks()) {
+                List<Claim> list = claimsByChunk.get(chunkKey);
+                if (list != null) {
+                    list.remove(claim);
+                    if (list.isEmpty()) {
+                        claimsByChunk.remove(chunkKey);
+                    }
+                }
+            }
+
+            // Clean player cache
+            playerClaimCache.values().removeIf(c -> c == claim);
+
+            Clan clan = Services.get(ClanManager.class).getClanById(claim.getClanId());
+            if (clan != null) {
+                clan.removeClaim(claim);
+            }
+        }
+    }
+
+    public void removeAllClaims() {
+        for (Claim claim : new ArrayList<>(allClaims)) {
+            removeClaim(claim);
+        }
+    }
+
+    /* =====================================================
+       OVERLAP CHECK
+       ===================================================== */
 
-    /**
-     * @param newClaim The claim you want to check
-     * @return The Claim it overlaps with or null if it doesn't overlap with any claims
-     */
-    @Nullable
     public Claim overlaps(Claim newClaim) {
-        for (Claim existing : allClaims) {
-            if (overlaps(newClaim, existing)) {
-                return existing;
+        for (long chunkKey : newClaim.getCoveredChunks()) {
+            List<Claim> list = claimsByChunk.get(chunkKey);
+            if (list == null) continue;
+
+            for (Claim existing : list) {
+                if (overlaps(newClaim, existing)) {
+                    return existing;
+                }
             }
         }
         return null;
     }
 
-    public void removeAllClaims() {
-        allClaims = new ArrayList<>();
+    private boolean overlaps(Claim a, Claim b) {
+        if (!a.getWorld().equals(b.getWorld())) return false;
+
+        return a.getMinX() <= b.getMaxX() && a.getMaxX() >= b.getMinX()
+                && a.getMinZ() <= b.getMaxZ() && a.getMaxZ() >= b.getMinZ();
     }
 
-    public void removeClaim(Claim claim) {
-        Clan clan = Main.getInstance().getClanModule().getClanManager().getClanById(claim.getClanId());
-        assert clan != null;
-        clan.removeClaim(claim);
-        allClaims.remove(claim);
+    /* =====================================================
+       CACHE MAINTENANCE
+       ===================================================== */
+
+    public void invalidatePlayer(Player player) {
+        playerClaimCache.remove(player.getUniqueId());
+    }
+
+    public void invalidateAllPlayers() {
+        playerClaimCache.clear();
     }
 }
+

+ 7 - 5
src/main/java/me/lethunderhawk/clans/command/ClanCommand.java

@@ -1,12 +1,14 @@
 package me.lethunderhawk.clans.command;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.bazaarflux.util.command.CommandNode;
 import me.lethunderhawk.bazaarflux.util.gui.InventoryManager;
 import me.lethunderhawk.clans.Clan;
 import me.lethunderhawk.clans.ClanManager;
 import me.lethunderhawk.clans.ClanModule;
 import me.lethunderhawk.clans.claim.Claim;
-import me.lethunderhawk.clans.gui.ClanGUI;
+import me.lethunderhawk.clans.claim.ClaimManager;
+import me.lethunderhawk.clans.gui.ClanMenu;
 import me.lethunderhawk.custom.item.concrete.ClaimTool;
 import me.lethunderhawk.main.Main;
 import net.kyori.adventure.text.Component;
@@ -65,18 +67,18 @@ public class ClanCommand implements CommandExecutor, TabCompleter {
 
     private void getClaimTool(CommandSender sender, String[] strings) {
         if(!(sender instanceof Player p)) return;
-        p.getInventory().addItem(new ClaimTool(Main.getInstance()).createItem());
+        p.getInventory().addItem(new ClaimTool(Services.get(Main.class)).createItem());
         ClanModule.sendText(p, Component.text("The tool magically appears in your inventory! How convenient!"));
     }
 
     private void handleSave(CommandSender sender, String[] strings) {
         if(!sender.isOp()) return;
-        Main.getInstance().getClanModule().getClanManager().saveClans();
+        Services.get(ClanManager.class).saveClans();
     }
 
     private void removeAllClaims(CommandSender sender, String[] strings) {
         if(!(sender instanceof Player player) || !sender.isOp()) return;
-        Main.getInstance().getClanModule().getClaimManager().removeAllClaims();
+        Services.get(ClaimManager.class).removeAllClaims();
     }
 
     private void infoClaims(CommandSender sender, String[] strings) {
@@ -103,7 +105,7 @@ public class ClanCommand implements CommandExecutor, TabCompleter {
         if(!(sender instanceof Player player)) return;
         Clan myClan =  manager.getMyClan(player.getUniqueId());
         if(myClan == null) return;
-        InventoryManager.openFor(player, new ClanGUI(myClan, player));
+        InventoryManager.openFor(player, new ClanMenu(myClan, player));
     }
 
 

+ 57 - 0
src/main/java/me/lethunderhawk/clans/gui/AdminMenuGUI.java

@@ -1,7 +1,21 @@
 package me.lethunderhawk.clans.gui;
 
+import me.lethunderhawk.bazaarflux.service.Services;
+import me.lethunderhawk.bazaarflux.util.CustomHeadCreator;
+import me.lethunderhawk.bazaarflux.util.gui.ConfirmationMenu;
 import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
+import me.lethunderhawk.clans.Clan;
+import me.lethunderhawk.clans.ClanManager;
+import me.lethunderhawk.clans.ClanModule;
+import me.lethunderhawk.clans.claim.ClaimManager;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
 import org.bukkit.entity.Player;
+import org.bukkit.event.inventory.ClickType;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.ArrayList;
+import java.util.List;
 
 public class AdminMenuGUI extends InventoryGUI {
     private final Player player;
@@ -16,6 +30,49 @@ public class AdminMenuGUI extends InventoryGUI {
         fillGlassPaneBackground();
         setBackButton(30);
         setCloseButton(31);
+        fillClansMenuWithClans();
+    }
+
+    private void fillClansMenuWithClans() {
+        ArrayList<Clan> clans = Services.get(ClanManager.class).getClans();
+        for(int i = 0; i< clans.size(); i++){
+            Clan clan = clans.get(i);
+            ItemStack descriptor = buildItemStackFromClan(clan);
+            setItemWithClickAction(i, descriptor, (p, type) ->{
+                if(type == ClickType.RIGHT){
+                    ConfirmationMenu menu = new ConfirmationMenu("Remove clan " + clan.getName(), (player) -> {
+                        ClanModule.sendText(player, "You removed the clan " + clan.getName());
+                        removeClan(clan);
+                        openPrevious(player);
+                    });
+                    menu.openWithListener(p);
+                }else if(type == ClickType.LEFT){
+                    openClanGUI(clan);
+                }
+            });
+        }
+    }
+
+    private void openClanGUI(Clan clan) {
+        ClanMenu menu = new ClanMenu(clan, player);
+        menu.setBackButton(30);
+        openNext(player, menu);
+    }
+
+    private void removeClan(Clan clan) {
+        Services.get(ClaimManager.class).removeClaims(clan.getClaims());
+        Services.get(ClanManager.class).removeClan(clan.getName());
+    }
+
+    private ItemStack buildItemStackFromClan(Clan clan) {
+        return CustomHeadCreator.createCustomHead(clan.getOwner(),
+                Component.text(clan.getName()),
+                List.of(
+                        Component.text("Owner: " + clan.getOwner().getName(), NamedTextColor.GOLD),
+                        Component.text(""),
+                        Component.text("Right click to remove", NamedTextColor.YELLOW),
+                        Component.text("Left click to open a GUI for this clan", NamedTextColor.YELLOW)
+                ));
     }
 
 

+ 32 - 15
src/main/java/me/lethunderhawk/clans/gui/ClaimSettingsGUI.java

@@ -1,6 +1,9 @@
 package me.lethunderhawk.clans.gui;
 
+import me.lethunderhawk.bazaarflux.service.Services;
+import me.lethunderhawk.bazaarflux.util.gui.ConfirmationMenu;
 import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
+import me.lethunderhawk.bazaarflux.util.gui.input.SignMenuFactory;
 import me.lethunderhawk.clans.Clan;
 import me.lethunderhawk.clans.claim.Claim;
 import me.lethunderhawk.clans.claim.ClaimManager;
@@ -15,7 +18,6 @@ import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.meta.ItemMeta;
 
 import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
 
 public class ClaimSettingsGUI extends InventoryGUI {
 
@@ -37,30 +39,45 @@ public class ClaimSettingsGUI extends InventoryGUI {
     }
 
     private void buildItems() {
-        AtomicInteger slot = new AtomicInteger();
+        final int[] slot = {0};
         clan.getClaims().forEach(claim -> {
-            setItemWithClickAction(slot.get(), buildItemFromClaim(claim), (p, type)->{
-                if(type == ClickType.LEFT || type == ClickType.SHIFT_LEFT){
+            setItemWithClickAction(slot[0], buildItemFromClaim(claim), (p, type)->{
+                if(type == ClickType.RIGHT || type == ClickType.SHIFT_RIGHT){
                     renameClaim(claim);
-                }else if(type == ClickType.RIGHT || type == ClickType.SHIFT_RIGHT){
-                    ConfirmationMenu confirmationMenu = new ConfirmationMenu("Delete Claim?", (pl) ->{
-                        removeClaim(claim);
-                        this.update();
-                    });
-                    this.openNext(p, confirmationMenu);
+                    update();
+                }else if(type == ClickType.LEFT || type == ClickType.SHIFT_LEFT){
+                    showRemoveClaimDialog(claim, p);
                 }
             });
-            slot.getAndIncrement();
+            slot[0]++;
         });
     }
 
+    private void showRemoveClaimDialog(Claim claim, Player p) {
+        ConfirmationMenu confirmationMenu = new ConfirmationMenu("Delete Claim?", (pl) ->{
+            removeClaim(claim);
+        });
+        openNext(p, confirmationMenu);
+    }
+
     private void removeClaim(Claim claim) {
-        ClaimManager manager = Main.getInstance().getClanModule().getClaimManager();
-        manager.removeClaim(claim);
+        Services.get(ClaimManager.class).removeClaim(claim);
     }
 
     private void renameClaim(Claim claim) {
+        SignMenuFactory.Menu menu = new SignMenuFactory(Services.get(Main.class)).newMenu(List.of("", "^^^^^^^^^^^^", "Enter the new", "name of the claim"))
+                .reopenIfFail(true)
+                .response((p, strings) -> {
+                    rename(strings[0], claim);
+                    update();
+                    open(p);
+                    return true;
+                });
+        menu.open(player);
+    }
 
+    private void rename(String input, Claim claim) {
+        claim.setName(input);
     }
 
     private ItemStack buildItemFromClaim(Claim claim) {
@@ -72,8 +89,8 @@ public class ClaimSettingsGUI extends InventoryGUI {
                 Component.text("to x=" + claim.getMinX() + ", z=" + claim.getMinZ(), NamedTextColor.GRAY),
                 Component.text("Volume: " + claim.getVolume() + " blocks²", NamedTextColor.GRAY),
                 Component.text(""),
-                Component.text("Left click to rename", NamedTextColor.YELLOW),
-                Component.text("Right click to remove", NamedTextColor.YELLOW)
+                Component.text("Left click to remove", NamedTextColor.YELLOW),
+                Component.text("Right click to rename", NamedTextColor.YELLOW)
         ));
         item.setItemMeta(UnItalic.removeItalicFromMeta(meta));
         return item;

+ 7 - 5
src/main/java/me/lethunderhawk/clans/gui/ClanGUI.java → src/main/java/me/lethunderhawk/clans/gui/ClanMenu.java

@@ -12,13 +12,13 @@ import org.bukkit.inventory.meta.ItemMeta;
 
 import java.util.List;
 
-public class ClanGUI extends InventoryGUI {
+public class ClanMenu extends InventoryGUI {
 
     private final Clan clan;
     private final Player player;
 
-    public ClanGUI(Clan clan, Player player) {
-        super("Main Clan Menu", 36);
+    public ClanMenu(Clan clan, Player player) {
+        super("Clan Menu - " + clan.getName(), 36);
         this.clan = clan;
         this.player = player;
         buildMenu();
@@ -26,7 +26,7 @@ public class ClanGUI extends InventoryGUI {
 
     private void buildMenu() {
         fillBackground(Material.GRAY_STAINED_GLASS_PANE, " ");
-
+        setCloseButton(31);
         buildSettings();
         buildMemberList();
         buildClaimList();
@@ -106,7 +106,9 @@ public class ClanGUI extends InventoryGUI {
         ItemMeta meta = admin.getItemMeta();
         meta.displayName(Component.text("Open the Admin panel", NamedTextColor.GOLD));
         meta.lore(List.of(
-                Component.text("Get access to all clans and edit their properties")
+                Component.text("Get access to all clans ", NamedTextColor.GRAY),
+                Component.text("and edit their properties", NamedTextColor.GRAY),
+                Component.text("USE WITH CAUTION!", NamedTextColor.RED)
         ));
         admin.setItemMeta(UnItalic.removeItalicFromMeta(meta));
         return admin;

+ 108 - 15
src/main/java/me/lethunderhawk/clans/gui/ClanSettingsGUI.java

@@ -5,11 +5,14 @@ import me.lethunderhawk.clans.settings.ClanSetting;
 import me.lethunderhawk.clans.settings.ClanSettings;
 import me.lethunderhawk.main.util.UnItalic;
 import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
 import org.bukkit.Material;
 import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemFlag;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.meta.ItemMeta;
 
+import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
 public class ClanSettingsGUI extends InventoryGUI {
@@ -28,12 +31,11 @@ public class ClanSettingsGUI extends InventoryGUI {
         fillGlassPaneBackground();
         setBackButton(30);
         setCloseButton(31);
-
         buildItems();
     }
 
     private void buildItems() {
-        AtomicInteger slot = new AtomicInteger(10);
+        AtomicInteger slot = new AtomicInteger(9);
         settings.asMap().forEach((setting, value) -> {
             ItemStack settingsItem;
             if(value == true){
@@ -42,44 +44,135 @@ public class ClanSettingsGUI extends InventoryGUI {
                 settingsItem = new ItemStack(Material.RED_STAINED_GLASS_PANE);
             }
             ItemMeta meta = settingsItem.getItemMeta();
-            meta.displayName(getReadableNameFromSetting(setting));
+            meta.displayName(
+                    value ? Component.text("Enabled", NamedTextColor.GREEN) : Component.text("Disabled", NamedTextColor.RED)
+            );
             settingsItem.setItemMeta(UnItalic.removeItalicFromMeta(meta));
-            setItemWithClickAction(slot.get(), settingsItem, (p, type) -> {
-                settings.toggleSetting(setting);
-                update();
+
+            setItemWithClickAction(slot.get() -9, buildDecorationItem(setting), (p, type) ->{
+                toggleAndUpdate(p, setting);
+            });
+            setItemWithClickAction(slot.get(), settingsItem, (p, type) ->{
+                toggleAndUpdate(p, setting);
             });
+
             slot.getAndIncrement();
         });
     }
 
-    private Component getReadableNameFromSetting(ClanSetting setting) {
+    private void toggleAndUpdate(Player p, ClanSetting setting) {
+        settings.toggleSetting(setting);
+        update();
+    }
+
+    private ItemStack buildDecorationItem(ClanSetting setting) {
         switch (setting){
             case ClanSetting.BLOCK_BREAK -> {
-                return Component.text("Breaking Blocks");
+                List<Component> lore = List.of(
+                        Component.text(""),
+                        Component.text("Enable / Disable the ability of other", NamedTextColor.GRAY),
+                        Component.text("Players not in your clan to", NamedTextColor.GRAY),
+                        Component.text("break all kinds of blocks!", NamedTextColor.GRAY)
+                );
+                return buildItemFromParams(Material.DIAMOND_PICKAXE, Component.text("Breaking blocks"), lore);
             }
             case ClanSetting.BLOCK_PLACE -> {
-                return Component.text("Placing Blocks");
+                List<Component> lore = List.of(
+                        Component.text(""),
+                        Component.text("Enable / Disable the ability of other", NamedTextColor.GRAY),
+                        Component.text("Players not in your clan to", NamedTextColor.GRAY),
+                        Component.text("place blocks inside your territory!", NamedTextColor.GRAY)
+                );
+
+                return buildItemFromParams(Material.OAK_PLANKS, Component.text("Placing Blocks"), lore);
             }
             case ClanSetting.INTERACT_IGNITION -> {
-                return Component.text("Igniting Blocks");
+                List<Component> lore = List.of(
+                        Component.text(""),
+                        Component.text("Allow or prevent outsiders from", NamedTextColor.GRAY),
+                        Component.text("using flint and steel to ignite", NamedTextColor.GRAY),
+                        Component.text("blocks within your clan land!", NamedTextColor.GRAY),
+                        Component.text(""),
+                        Component.text("WARNING: This doesn't prevent", NamedTextColor.RED),
+                        Component.text("others from igniting TNT!", NamedTextColor.RED)
+                );
+
+                return buildItemFromParams(Material.FLINT_AND_STEEL, Component.text("Igniting blocks"), lore);
             }
             case ClanSetting.INTERACT_BLOCK -> {
-                return Component.text("Interacting with Blocks");
+                List<Component> lore = List.of(
+                        Component.text(""),
+                        Component.text("Controls whether non-clan players", NamedTextColor.GRAY),
+                        Component.text("can interact with mechanisms like", NamedTextColor.GRAY),
+                        Component.text("buttons, levers, and doors!", NamedTextColor.GRAY)
+                );
+
+                return buildItemFromParams(Material.LEVER, Component.text("Interacting with blocks"), lore);
             }
             case ClanSetting.INTERACT_ENTITY -> {
-                return Component.text("Interacting with Entities");
+                List<Component> lore = List.of(
+                        Component.text(""),
+                        Component.text("Determines if outsiders may", NamedTextColor.GRAY),
+                        Component.text("right-click or otherwise interact", NamedTextColor.GRAY),
+                        Component.text("with animals and NPC entities!", NamedTextColor.GRAY)
+                );
+
+                return buildItemFromParams(Material.VILLAGER_SPAWN_EGG, Component.text("Interacting with entities"), lore);
             }
             case ClanSetting.OPEN_CONTAINER -> {
-                return Component.text("Opening Containers");
+                List<Component> lore = List.of(
+                        Component.text(""),
+                        Component.text("Determines if outsiders may", NamedTextColor.GRAY),
+                        Component.text("right-click or otherwise interact", NamedTextColor.GRAY),
+                        Component.text("with animals and NPC entities!", NamedTextColor.GRAY)
+                );
+
+                return buildItemFromParams(Material.CHEST, Component.text("Opening Containers"), lore);
             }
             case ClanSetting.USE_ANVIL -> {
-                return Component.text("Using Anvil");
+                List<Component> lore = List.of(
+                        Component.text(""),
+                        Component.text("Control if outsiders can use", NamedTextColor.GRAY),
+                        Component.text("anvils inside your territory", NamedTextColor.GRAY),
+                        Component.text("to repair or rename items!", NamedTextColor.GRAY)
+                );
+
+                return buildItemFromParams(Material.ANVIL, Component.text("Using Anvils"), lore);
+            }
+            case ClanSetting.ALLOW_HITTING_MOBS -> {
+                List<Component> lore = List.of(
+                        Component.text(""),
+                        Component.text("Determines whether players inside", NamedTextColor.GRAY),
+                        Component.text("your claims may attack hostile", NamedTextColor.GRAY),
+                        Component.text("or passive mobs in your land!", NamedTextColor.GRAY)
+                );
+
+                return buildItemFromParams(Material.ZOMBIE_HEAD, Component.text("Hitting mobs"), lore);
+            }
+            case ClanSetting.ALLOW_HITTING_PLAYERS -> {
+                List<Component> lore = List.of(
+                        Component.text(""),
+                        Component.text("Toggle whether players inside", NamedTextColor.GRAY),
+                        Component.text("of your claim are allowed to", NamedTextColor.GRAY),
+                        Component.text("fight other Players (PvP)!", NamedTextColor.GRAY)
+                );
+
+                return buildItemFromParams(Material.PLAYER_HEAD, Component.text("PvP"), lore);
             }
             default -> {
-                return Component.text(setting.name());
+                return new ItemStack(Material.AIR);
             }
         }
     }
+    private ItemStack buildItemFromParams(Material material, Component displayName, List<Component> lore) {
+        ItemStack item = new ItemStack(material);
+        ItemMeta meta = item.getItemMeta();
+        meta.displayName(displayName.color(NamedTextColor.GOLD));
+        meta.lore(lore);
+        meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
+        item.setItemMeta(UnItalic.removeItalicFromMeta(meta));
+        return item;
+    }
 
     @Override
     public void update() {

+ 3 - 2
src/main/java/me/lethunderhawk/clans/placeholder/ClanPlaceHolder.java

@@ -1,6 +1,7 @@
 package me.lethunderhawk.clans.placeholder;
 
 import me.clip.placeholderapi.expansion.PlaceholderExpansion;
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.clans.Clan;
 import me.lethunderhawk.clans.ClanManager;
 import org.bukkit.entity.Player;
@@ -10,8 +11,8 @@ public class ClanPlaceHolder extends PlaceholderExpansion {
 
     private final ClanManager manager;
 
-    public ClanPlaceHolder(ClanManager manager){
-        this.manager = manager;
+    public ClanPlaceHolder(){
+        this.manager = Services.get(ClanManager.class);
     }
 
     @Override

+ 2 - 0
src/main/java/me/lethunderhawk/clans/settings/ClanSetting.java

@@ -8,6 +8,8 @@ public enum ClanSetting {
     OPEN_CONTAINER,   // chests, barrels, shulker boxes, hoppers
     INTERACT_BLOCK,   // buttons, levers, doors, trapdoors
     INTERACT_ENTITY,  // item frames, armor stands, villagers
+    ALLOW_HITTING_PLAYERS,
+    ALLOW_HITTING_MOBS,
     INTERACT_IGNITION,
     USE_ANVIL;
 }

+ 24 - 0
src/main/java/me/lethunderhawk/clans/settings/ClanSettings.java

@@ -1,6 +1,10 @@
 package me.lethunderhawk.clans.settings;
 
+import me.lethunderhawk.bazaarflux.service.Services;
+import me.lethunderhawk.main.Main;
+
 import java.util.EnumMap;
+import java.util.HashMap;
 import java.util.Map;
 
 public final class ClanSettings {
@@ -26,4 +30,24 @@ public final class ClanSettings {
     public Map<ClanSetting, Boolean> asMap() {
         return settings;
     }
+    public Map<String, Object> toStringMap() {
+        Map<String, Object> map = new HashMap<>();
+        for (Map.Entry<ClanSetting, Boolean> entry : settings.entrySet()) {
+            map.put(entry.getKey().name(), entry.getValue());
+        }
+        return map;
+    }
+    public static ClanSettings fromMap(Map<String, Object> map) {
+        ClanSettings s = new ClanSettings();
+
+        for (Map.Entry<String, Object> entry : map.entrySet()) {
+            try {
+                ClanSetting key = ClanSetting.valueOf(entry.getKey());
+                s.set(key, (Boolean) entry.getValue());
+            } catch (IllegalArgumentException e) {
+                Services.get(Main.class).getLogger().warning("Unknown ClanSetting: " + entry.getKey());
+            }
+        }
+        return s;
+    }
 }

+ 7 - 7
src/main/java/me/lethunderhawk/custom/item/CustomItemModule.java

@@ -1,5 +1,6 @@
 package me.lethunderhawk.custom.item;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.bazaarflux.util.interfaces.BazaarFluxModule;
 import me.lethunderhawk.custom.item.command.CustomItemCommand;
 import me.lethunderhawk.custom.item.concrete.ClaimTool;
@@ -8,15 +9,13 @@ import me.lethunderhawk.custom.item.manager.CustomItemManager;
 import me.lethunderhawk.main.Main;
 import org.bukkit.command.CommandSender;
 import org.bukkit.event.HandlerList;
-import org.bukkit.plugin.java.JavaPlugin;
 
-public class CustomItemModule implements BazaarFluxModule {
+public class CustomItemModule extends BazaarFluxModule{
     private CustomItemManager itemManager;
-    private final JavaPlugin plugin;
     private CustomItemListener listener;
 
-    public CustomItemModule(JavaPlugin plugin) {
-        this.plugin = plugin;
+    public CustomItemModule() {
+        super(Services.get(Main.class));
     }
     private void registerCustomItems(){
         itemManager.registerItem(new ClaimTool(plugin));
@@ -43,8 +42,8 @@ public class CustomItemModule implements BazaarFluxModule {
 
     private void registerCommands() {
         CustomItemCommand customItemCommand = new CustomItemCommand(itemManager, this);
-        Main.getInstance().getCommand("customItem").setExecutor(customItemCommand);
-        Main.getInstance().getCommand("customItem").setTabCompleter(customItemCommand);
+        Services.get(Main.class).getCommand("customItem").setExecutor(customItemCommand);
+        Services.get(Main.class).getCommand("customItem").setTabCompleter(customItemCommand);
     }
 
     @Override
@@ -63,4 +62,5 @@ public class CustomItemModule implements BazaarFluxModule {
             onEnable();
         }
     }
+
 }

+ 8 - 6
src/main/java/me/lethunderhawk/custom/item/concrete/ClaimTool.java

@@ -1,8 +1,11 @@
 package me.lethunderhawk.custom.item.concrete;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.clans.Clan;
+import me.lethunderhawk.clans.ClanManager;
 import me.lethunderhawk.clans.ClanModule;
 import me.lethunderhawk.clans.claim.Claim;
+import me.lethunderhawk.clans.claim.ClaimManager;
 import me.lethunderhawk.custom.item.abstraction.CustomItem;
 import me.lethunderhawk.main.Main;
 import net.kyori.adventure.text.Component;
@@ -49,8 +52,7 @@ public class ClaimTool extends CustomItem {
         Location second = block.getLocation();
 
         UUID uuid = p.getUniqueId();
-        ClanModule module = Main.getInstance().getClanModule();
-        Clan clan = module.getClanManager().getMyClan(uuid);
+        Clan clan = Services.get(ClanManager.class).getMyClan(uuid);
         if(clan == null){
             e.setCancelled(true);
             ClanModule.sendText(p,"§cJoin a clan first!");
@@ -65,16 +67,16 @@ public class ClaimTool extends CustomItem {
             // create claim
             Claim claim = new Claim(clan.getId(), first.getWorld().getName(), first.getBlockX(), second.getBlockX(), first.getBlockZ(), second.getBlockZ());
 
-            int maxBlocks = Main.getInstance().getConfig().getInt("claims.max-blocks");
+            int maxBlocks = Services.get(Main.class).getConfig().getInt("claims.max-blocks");
 
             if (clan.getUsedBlocks() + claim.getVolume() > maxBlocks) {
                 p.sendMessage("§cClaim too large. Current use of space: " + clan.getUsedBlocks() + "/" + maxBlocks);
                 return;
             }
-            Claim overlapping = module.getClaimManager().overlaps(claim);
+            Claim overlapping = Services.get(ClaimManager.class).overlaps(claim);
 
             if(overlapping != null) {
-                Clan overlappingClan = module.getClanManager().getClanById(overlapping.getClanId());
+                Clan overlappingClan = Services.get(ClanManager.class).getClanById(overlapping.getClanId());
 
                 if (overlappingClan != null) {
                     ClanModule.sendText(p,"§cThis area is overlapping with already claimed land from Clan " + overlappingClan.getName() + ".");
@@ -84,7 +86,7 @@ public class ClaimTool extends CustomItem {
             }
 
 
-            module.getClaimManager().registerClaim(claim);
+            Services.get(ClaimManager.class).registerClaim(claim);
             clan.addClaim(claim);
             ClanModule.sendText(p,"§aSecond corner set.");
             ClanModule.sendText(p,"§aClaim created.");

+ 21 - 13
src/main/java/me/lethunderhawk/economy/EconomyModule.java

@@ -1,36 +1,42 @@
 package me.lethunderhawk.economy;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.bazaarflux.util.MessageSender;
+import me.lethunderhawk.bazaarflux.util.interfaces.BazaarFluxModule;
 import me.lethunderhawk.economy.api.EconomyAPI;
 import me.lethunderhawk.economy.api.EconomyPlaceholder;
 import me.lethunderhawk.economy.command.EcoCommand;
 import me.lethunderhawk.economy.currency.EconomyManager;
 import me.lethunderhawk.economy.listener.PlayerJoinListener;
 import me.lethunderhawk.economy.scoreboard.ScoreboardManager;
+import me.lethunderhawk.main.Main;
 import me.lethunderhawk.tradeplugin.api.TradePlaceholder;
 import net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.text.Component;
 import org.bukkit.plugin.java.JavaPlugin;
 
-public class EconomyModule {
+public class EconomyModule extends BazaarFluxModule {
 
-    private static EconomyModule instance;
-
-    private EconomyManager economyManager;
     private EconomyAPI economyAPI;
     private ScoreboardManager scoreboardManager;
-    private JavaPlugin plugin;
-    public EconomyModule(JavaPlugin plugin) {
-        this.plugin = plugin;
+    public EconomyModule() {
+        super(Services.get(Main.class));
+    }
+
+    @Override
+    public String getPrefix() {
+        return "[Economy]";
     }
+
     public void onEnable() {
-        instance = this;
 
         plugin.saveDefaultConfig();
         plugin.saveResource("scoreboards/default.yml", false);
 
-        economyManager = new EconomyManager(this);
+        EconomyManager economyManager = new EconomyManager();
+
         economyAPI = new EconomyAPI(economyManager);
+        Services.register(EconomyAPI.class, economyAPI);
         scoreboardManager = new ScoreboardManager(this);
 
         plugin.getCommand("eco").setExecutor(new EcoCommand(this));
@@ -43,6 +49,12 @@ public class EconomyModule {
 
         plugin.getServer().getPluginManager().registerEvents(new PlayerJoinListener(scoreboardManager), plugin);
     }
+
+    @Override
+    public void onDisable() {
+
+    }
+
     public static void sendText(Audience receiver, Component infoText){
         MessageSender.sendText(receiver, infoText, "[Eco]");
     }
@@ -53,10 +65,6 @@ public class EconomyModule {
         scoreboardManager.reload();
     }
 
-    public static EconomyModule getInstance() {
-        return instance;
-    }
-
     public EconomyAPI getEconomyAPI() {
         return economyAPI;
     }

+ 3 - 2
src/main/java/me/lethunderhawk/economy/currency/EconomyManager.java

@@ -1,5 +1,6 @@
 package me.lethunderhawk.economy.currency;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.economy.EconomyModule;
 import org.bukkit.configuration.file.FileConfiguration;
 
@@ -10,8 +11,8 @@ public class EconomyManager {
     private final EconomyModule module;
     private final FileConfiguration config;
 
-    public EconomyManager(EconomyModule module) {
-        this.module = module;
+    public EconomyManager() {
+        this.module = Services.get(EconomyModule.class);
         this.config = module.getPlugin().getConfig();
     }
 

+ 2 - 2
src/main/java/me/lethunderhawk/economy/util/EconomyUtil.java

@@ -3,7 +3,7 @@ package me.lethunderhawk.economy.util;
 public class EconomyUtil {
     public static long longFromString(String s) {
         if (s == null || s.isBlank()) {
-            throw new IllegalArgumentException("Input is null or empty");
+            return 0;
         }
 
         s = s.trim().toLowerCase();
@@ -31,7 +31,7 @@ public class EconomyUtil {
         try {
             base = Long.parseLong(s);
         } catch (NumberFormatException e) {
-            throw new IllegalArgumentException("Invalid number: " + s);
+            return 0;
         }
 
         long result = base * multiplier;

+ 32 - 25
src/main/java/me/lethunderhawk/main/Main.java

@@ -1,58 +1,65 @@
 package me.lethunderhawk.main;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.bazaarflux.util.gui.InventoryManager;
+import me.lethunderhawk.bazaarflux.util.interfaces.BazaarFluxModule;
 import me.lethunderhawk.clans.ClanModule;
 import me.lethunderhawk.custom.item.CustomItemModule;
-import me.lethunderhawk.custom.item.manager.CustomItemManager;
 import me.lethunderhawk.economy.EconomyModule;
 import me.lethunderhawk.minion.MinionModule;
 import me.lethunderhawk.tradeplugin.TradeModule;
 import org.bukkit.plugin.java.JavaPlugin;
-import org.jetbrains.annotations.NotNull;
 
-public class Main extends JavaPlugin {
-    private static Main instance;
-    public boolean isEnchantedItemCraftingEventRegistered;
-    private ClanModule clanModule;
-    private CustomItemModule customItemModule;
+import java.util.ArrayList;
+import java.util.List;
 
-    public static @NotNull Main getInstance() {
-        return instance;
-    }
+public class Main extends JavaPlugin{
 
+    private final List<BazaarFluxModule> bazaarFluxModules = new ArrayList<>();
     @Override
     public void onEnable() {
-        instance = this;
+        Services.register(Main.class, this);
+
         InventoryManager.register(this);
+        registerAllModules(new CustomItemModule(), new TradeModule(), new ClanModule(), new EconomyModule(), new MinionModule());
 
-        customItemModule = new CustomItemModule(this);
+        /*CustomItemModule customItemModule = new CustomItemModule();
         customItemModule.onEnable();
+        Services.register(CustomItemModule.class, customItemModule);
 
-        TradeModule tradeModule = new TradeModule(this);
+        TradeModule tradeModule = new TradeModule();
         tradeModule.onEnable();
+        Services.register(TradeModule.class, tradeModule);
 
-        clanModule = new ClanModule();
+        ClanModule clanModule = new ClanModule();
         clanModule.onEnable();
+        Services.register(ClanModule.class, clanModule);
 
-        EconomyModule economyModule = new EconomyModule(this);
+        EconomyModule economyModule = new EconomyModule();
         economyModule.onEnable();
+        Services.register(EconomyModule.class, economyModule);
 
-        MinionModule minionModule = new MinionModule(this);
+        MinionModule minionModule = new MinionModule();
         minionModule.onEnable();
+        Services.register(MinionModule.class, minionModule);*/
     }
-
-
-
-    public ClanModule getClanModule(){
-        return clanModule;
+    private void registerAllModules(BazaarFluxModule... modules){
+        for(BazaarFluxModule module : modules){
+            bazaarFluxModules.add(module);
+            registerModule(module);
+        }
+    }
+    private void registerModule(BazaarFluxModule module){
+        Services.registerModule(module.getClass(), module);
+        module.onEnable();
     }
 
     @Override
     public void onDisable(){
-        clanModule.onDisable();
+        for(BazaarFluxModule module : bazaarFluxModules){
+            module.onDisable();
+            Services.unregisterModule(module.getClass());
+        }
     }
 
-    public CustomItemManager getCustomItemManager() {
-        return customItemModule.getManager();
-    }
 }

+ 6 - 6
src/main/java/me/lethunderhawk/minion/MinionModule.java

@@ -1,5 +1,6 @@
 package me.lethunderhawk.minion;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.bazaarflux.util.interfaces.BazaarFluxModule;
 import me.lethunderhawk.main.Main;
 import me.lethunderhawk.minion.command.MinionCommand;
@@ -24,17 +25,16 @@ import org.bukkit.inventory.ItemStack;
 import java.util.ArrayList;
 import java.util.List;
 
-public class MinionModule implements BazaarFluxModule {
+public class MinionModule extends BazaarFluxModule {
 
-    private final Main plugin;
     private List<ItemStack> allMinions;
     private MinionListener minionListener;
     private MinionFactory factory;
     private MinionStorage storage;
     private RecipeManager recipeManager;
 
-    public MinionModule(Main plugin) {
-        this.plugin = plugin;
+    public MinionModule() {
+        super(Services.get(Main.class));
     }
 
     @Override
@@ -50,7 +50,7 @@ public class MinionModule implements BazaarFluxModule {
         MinionCommand cmd = new MinionCommand(this);
         plugin.getServer().getPluginCommand("minion").setExecutor(cmd);
         plugin.getServer().getPluginCommand("minion").setTabCompleter(cmd);
-        this.factory = new MinionFactory(plugin);
+        this.factory = new MinionFactory();
         registerMinions();
 
         loadAllMinions();
@@ -61,7 +61,7 @@ public class MinionModule implements BazaarFluxModule {
 
     private void customRecipes() {
 
-        this.recipeManager = new RecipeManager(Main.getInstance());
+        this.recipeManager = new RecipeManager(Services.get(Main.class));
         plugin.getServer().getPluginManager().registerEvents(new DisableEnchantedItemPlacingListener(), plugin);
 
         registerRecipes();

+ 2 - 1
src/main/java/me/lethunderhawk/minion/api/MinionLevel.java

@@ -1,5 +1,6 @@
 package me.lethunderhawk.minion.api;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.main.Main;
 import org.bukkit.configuration.file.FileConfiguration;
 import org.bukkit.configuration.file.YamlConfiguration;
@@ -19,7 +20,7 @@ public class MinionLevel {
 
     public MinionLevelTable create() {
 
-        JavaPlugin plugin = Main.getInstance();
+        JavaPlugin plugin = Services.get(Main.class);
         // Return cached version if available
 
         Map<Integer, MinionLevelData> levelDataMap = new HashMap<>();

+ 2 - 1
src/main/java/me/lethunderhawk/minion/enchantedVariant/item/abstraction/EnchantedItem.java

@@ -1,5 +1,6 @@
 package me.lethunderhawk.minion.enchantedVariant.item.abstraction;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.main.Main;
 import me.lethunderhawk.main.util.UnItalic;
 import net.kyori.adventure.text.Component;
@@ -30,7 +31,7 @@ public abstract class EnchantedItem {
         this.lore = lore;
         this.baseMaterial = baseMaterial;
         this.itemId = itemId;
-        this.itemIdKey = new NamespacedKey(Main.getInstance(), itemId);
+        this.itemIdKey = new NamespacedKey(Services.get(Main.class), itemId);
         this.itemStack = createItem();
     }
 

+ 2 - 1
src/main/java/me/lethunderhawk/minion/enchantedVariant/recipe/EnchantedItemRecipe.java

@@ -1,5 +1,6 @@
 package me.lethunderhawk.minion.enchantedVariant.recipe;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.main.Main;
 import org.bukkit.Bukkit;
 import org.bukkit.Material;
@@ -105,7 +106,7 @@ public class EnchantedItemRecipe implements Recipe {
     }
 
     public static void register(Material ingredient, ItemStack result) {
-        Plugin plugin = Main.getInstance(); // Replace with your plugin name
+        Plugin plugin = Services.get(Main.class); // Replace with your plugin name
 
         NamespacedKey key = new NamespacedKey(plugin,
                 "enchanted_" + ingredient.name().toLowerCase());

+ 2 - 3
src/main/java/me/lethunderhawk/minion/factory/MinionFactory.java

@@ -5,7 +5,6 @@ import me.lethunderhawk.minion.api.MinionType;
 import me.lethunderhawk.minion.item.MinionItem;
 import me.lethunderhawk.minion.registry.MinionRegistry;
 import org.bukkit.inventory.ItemStack;
-import org.bukkit.plugin.java.JavaPlugin;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -14,8 +13,8 @@ public class MinionFactory {
 
     private final MinionItem item;
 
-    public MinionFactory(JavaPlugin plugin) {
-        this.item = new MinionItem(plugin);
+    public MinionFactory() {
+        this.item = new MinionItem();
     }
 
     public ItemStack createItem(String typeId, int level) {

+ 4 - 2
src/main/java/me/lethunderhawk/minion/item/MinionItem.java

@@ -1,7 +1,9 @@
 package me.lethunderhawk.minion.item;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.bazaarflux.util.CustomHeadCreator;
 import me.lethunderhawk.bazaarflux.util.lang.RomanNumbers;
+import me.lethunderhawk.main.Main;
 import me.lethunderhawk.main.util.UnItalic;
 import me.lethunderhawk.minion.api.MinionType;
 import me.lethunderhawk.minion.registry.MinionRegistry;
@@ -11,7 +13,6 @@ import org.bukkit.NamespacedKey;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.meta.ItemMeta;
 import org.bukkit.persistence.PersistentDataType;
-import org.bukkit.plugin.java.JavaPlugin;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -21,7 +22,8 @@ public class MinionItem {
     private final NamespacedKey typeKey;
     private final NamespacedKey levelKey;
 
-    public MinionItem(JavaPlugin plugin) {
+    public MinionItem() {
+        Main plugin = Services.get(Main.class);
         this.typeKey = new NamespacedKey(plugin, "minion_type");
         this.levelKey = new NamespacedKey(plugin, "minion_level");
     }

+ 1 - 2
src/main/java/me/lethunderhawk/minion/manager/MinionManager.java

@@ -1,6 +1,5 @@
 package me.lethunderhawk.minion.manager;
 
-import me.lethunderhawk.main.Main;
 import me.lethunderhawk.minion.runtime.PlacedMinion;
 import org.bukkit.Location;
 import org.bukkit.plugin.java.JavaPlugin;
@@ -55,7 +54,7 @@ public class MinionManager {
         return false;
     }
 
-    public static void startAndRegisterAll(Main plugin, List<PlacedMinion> minions) {
+    public static void startAndRegisterAll(JavaPlugin plugin, List<PlacedMinion> minions) {
         for(PlacedMinion minion : minions){
             startAndRegister(minion, plugin);
         }

+ 1 - 1
src/main/java/me/lethunderhawk/minion/runtime/PlacedMinion.java

@@ -138,7 +138,7 @@ public class PlacedMinion {
 
     public PlacedMinion getUpgrade(JavaPlugin plugin) {
         int newLevel = this.level + 1;
-        ItemStack newHelmet = new MinionFactory(plugin).createItem(this.type, newLevel);
+        ItemStack newHelmet = new MinionFactory().createItem(this.type, newLevel);
         if(newHelmet == null) return null;
         PlacedMinion newMinion = new PlacedMinion(this.minionId, this.ownerId, this.type, newLevel, this.placedLocation, newHelmet, this.armorColor);
         inventory.resize(this.type.getLevelTable().get(newLevel).storageSize());

+ 4 - 3
src/main/java/me/lethunderhawk/minion/ui/MinionMenu.java

@@ -1,5 +1,6 @@
 package me.lethunderhawk.minion.ui;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
 import me.lethunderhawk.bazaarflux.util.gui.InventoryManager;
 import me.lethunderhawk.main.Main;
@@ -58,7 +59,7 @@ public class MinionMenu extends InventoryGUI implements InventoryGUI.AutoCloseHa
         ItemStack upgradeItem = buildQuickUpgradeItem();
         setItemWithClickAction(50, upgradeItem, (p, type) -> {
 
-            JavaPlugin plugin = Main.getInstance();
+            JavaPlugin plugin = Services.get(Main.class);
             PlacedMinion newMinion = minion.getUpgrade(plugin);
             if(newMinion != null) {
                 MinionManager.stopAndUnregister(minion);
@@ -287,7 +288,7 @@ public class MinionMenu extends InventoryGUI implements InventoryGUI.AutoCloseHa
             // Back button
             ItemStack backItem = new ItemStack(Material.ARROW);
             ItemMeta backMeta = backItem.getItemMeta();
-            backMeta.setDisplayName("§aGo Back");
+            backMeta.displayName(Component.text("Go Back", NamedTextColor.RED));
             backItem.setItemMeta(backMeta);
             setItemWithClickAction(49, backItem, (p, type) -> {
                 new MinionMenu(minion).open(p);
@@ -317,7 +318,7 @@ public class MinionMenu extends InventoryGUI implements InventoryGUI.AutoCloseHa
             // Back button
             ItemStack backItem = new ItemStack(Material.ARROW);
             ItemMeta backMeta = backItem.getItemMeta();
-            backMeta.setDisplayName("§aGo Back");
+            backMeta.displayName(Component.text("Go Back", NamedTextColor.RED));
             backItem.setItemMeta(backMeta);
             setItemWithClickAction(22, backItem, (p, type) -> {
                 new MinionMenu(minion).open(p);

+ 1 - 2
src/main/java/me/lethunderhawk/minion/ui/minionList/MinionLevelListMenu.java

@@ -2,7 +2,6 @@ package me.lethunderhawk.minion.ui.minionList;
 
 import me.lethunderhawk.bazaarflux.util.gui.GoBackItem;
 import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
-import me.lethunderhawk.main.Main;
 import me.lethunderhawk.minion.api.MinionLevelData;
 import me.lethunderhawk.minion.api.MinionLevelTable;
 import me.lethunderhawk.minion.factory.MinionFactory;
@@ -25,7 +24,7 @@ public class MinionLevelListMenu extends InventoryGUI {
         MinionLevelTable table = MinionRegistry.get(typeId).getLevelTable();
         int slot = 0;
         for(MinionLevelData data : table.getAllLevels()){
-            ItemStack item = new MinionFactory(Main.getInstance()).createItem(typeId, data.level());
+            ItemStack item = new MinionFactory().createItem(typeId, data.level());
             setItemWithClickAction(slot, item, (player, clickType) -> {
                 getMinionItem(player, item);
             });

+ 1 - 2
src/main/java/me/lethunderhawk/minion/ui/minionList/MinionListMenu.java

@@ -1,7 +1,6 @@
 package me.lethunderhawk.minion.ui.minionList;
 
 import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
-import me.lethunderhawk.main.Main;
 import me.lethunderhawk.minion.api.MinionType;
 import me.lethunderhawk.minion.factory.MinionFactory;
 import me.lethunderhawk.minion.registry.MinionRegistry;
@@ -24,7 +23,7 @@ public class MinionListMenu extends InventoryGUI {
         Map<String, MinionType> types = MinionRegistry.getAllRegisteredTypes();
         int slot = 0;
         for(String typeId : types.keySet()){
-            ItemStack item = new MinionFactory(Main.getInstance()).createItem(typeId, 1);
+            ItemStack item = new MinionFactory().createItem(typeId, 1);
 
             setItemWithClickAction(slot, item, (player, clickType) -> {
                 openBiggerMinionListMenu(player, typeId);

+ 18 - 7
src/main/java/me/lethunderhawk/tradeplugin/TradeModule.java

@@ -1,24 +1,30 @@
 package me.lethunderhawk.tradeplugin;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.bazaarflux.util.MessageSender;
+import me.lethunderhawk.bazaarflux.util.interfaces.BazaarFluxModule;
+import me.lethunderhawk.main.Main;
 import me.lethunderhawk.tradeplugin.command.TradeAcceptCommand;
 import me.lethunderhawk.tradeplugin.command.TradeCommand;
-import me.lethunderhawk.tradeplugin.listener.InventoryListener;
 import me.lethunderhawk.tradeplugin.listener.PlayerInteractListener;
+import me.lethunderhawk.tradeplugin.listener.TradeInventoryListener;
 import me.lethunderhawk.tradeplugin.trade.TradeManager;
 import me.lethunderhawk.tradeplugin.trade.TradeRequestManager;
 import net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.text.Component;
-import org.bukkit.plugin.java.JavaPlugin;
 
-public class TradeModule {
+public class TradeModule extends BazaarFluxModule {
 
     private static TradeManager tradeManager;
     private static TradeRequestManager requestManager;
-    private final JavaPlugin plugin;
 
-    public TradeModule(JavaPlugin plugin) {
-        this.plugin = plugin;
+    public TradeModule() {
+        super(Services.get(Main.class));
+    }
+
+    @Override
+    public String getPrefix() {
+        return "[Trade]";
     }
 
     public void onEnable() {
@@ -26,12 +32,17 @@ public class TradeModule {
         requestManager = new TradeRequestManager();
 
         plugin.getServer().getPluginManager().registerEvents(new PlayerInteractListener(this), plugin);
-        plugin.getServer().getPluginManager().registerEvents(new InventoryListener(this), plugin);
+        plugin.getServer().getPluginManager().registerEvents(new TradeInventoryListener(this), plugin);
 
         plugin.getCommand("trade").setExecutor(new TradeCommand());
         plugin.getCommand("tradeaccept").setExecutor(new TradeAcceptCommand());
     }
 
+    @Override
+    public void onDisable() {
+
+    }
+
     public static void sendText(Audience receiver, Component infoText){
         MessageSender.sendText(receiver, infoText, "[Trade]");
     }

+ 10 - 6
src/main/java/me/lethunderhawk/tradeplugin/listener/InventoryListener.java → src/main/java/me/lethunderhawk/tradeplugin/listener/TradeInventoryListener.java

@@ -1,7 +1,8 @@
 package me.lethunderhawk.tradeplugin.listener;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.bazaarflux.util.gui.input.SignMenuFactory;
-import me.lethunderhawk.economy.EconomyModule;
+import me.lethunderhawk.economy.api.EconomyAPI;
 import me.lethunderhawk.economy.util.EconomyUtil;
 import me.lethunderhawk.main.Main;
 import me.lethunderhawk.tradeplugin.TradeModule;
@@ -26,11 +27,11 @@ import java.util.List;
 import static me.lethunderhawk.tradeplugin.trade.TradeSession.getFluxKey;
 import static me.lethunderhawk.tradeplugin.trade.TradeSession.getValueKey;
 
-public class InventoryListener implements Listener {
+public class TradeInventoryListener implements Listener {
 
     private final TradeManager manager;
 
-    public InventoryListener(TradeModule plugin) {
+    public TradeInventoryListener(TradeModule plugin) {
         this.manager = TradeModule.getTradeManager();
     }
 
@@ -106,13 +107,13 @@ public class InventoryListener implements Listener {
     }
 
     private void openSignMenu(Player p) {
-        SignMenuFactory.Menu signInput = new SignMenuFactory(Main.getInstance()).newMenu(List.of("", "^^^^^^^^^^^^", "Input the amount", "to trade"))
+        SignMenuFactory.Menu signInput = new SignMenuFactory(Services.get(Main.class)).newMenu(List.of("", "^^^^^^^^^^^^", "Input the amount", "to trade"))
                 .reopenIfFail(true)
                 .response((player, input) -> {
                     long value = EconomyUtil.longFromString(input[0]);
                     TradeSession originalSession = manager.getSession(player);
                     if (value > 0) {
-                        if(EconomyModule.getInstance().getEconomyAPI().getMoney(player.getUniqueId()) >= originalSession.getMoneyFor(p) + value){
+                        if(Services.get(EconomyAPI.class).getMoney(player.getUniqueId()) >= originalSession.getMoneyFor(p) + value){
                             if(originalSession.addFluxValue(player, value)){
                                 player.openInventory(originalSession.getTradeInventory().getInventoryFor(player));
                             }else{
@@ -123,8 +124,11 @@ public class InventoryListener implements Listener {
                             TradeModule.sendText(player,Component.text("You don't have enough money!", NamedTextColor.RED));
                             return false;
                         }
-                    } else {
+                    } else if(value == 0) {
+                        return true;
+                    }else{
                         TradeModule.sendText(player,Component.text("You cant pay negative amounts!!", NamedTextColor.RED));
+                        player.openInventory(originalSession.getTradeInventory().getInventoryFor(player));
                         return false;
                     }
                     player.openInventory(originalSession.getTradeInventory().getInventoryFor(player));

+ 2 - 1
src/main/java/me/lethunderhawk/tradeplugin/trade/TradeRequestManager.java

@@ -1,5 +1,6 @@
 package me.lethunderhawk.tradeplugin.trade;
 
+import me.lethunderhawk.bazaarflux.service.Services;
 import me.lethunderhawk.main.Main;
 import me.lethunderhawk.tradeplugin.TradeModule;
 import net.kyori.adventure.key.Key;
@@ -76,7 +77,7 @@ public class TradeRequestManager {
             );
 
             int task = Bukkit.getScheduler().scheduleSyncDelayedTask(
-                    Main.getInstance(),
+                    Services.get(Main.class),
                     () -> {
                         if (isPending(target, sender)) {
                             requests.remove(target.getUniqueId());

+ 8 - 6
src/main/java/me/lethunderhawk/tradeplugin/trade/TradeSession.java

@@ -1,7 +1,8 @@
 package me.lethunderhawk.tradeplugin.trade;
 
 import me.clip.placeholderapi.PlaceholderAPI;
-import me.lethunderhawk.economy.EconomyModule;
+import me.lethunderhawk.bazaarflux.service.Services;
+import me.lethunderhawk.economy.api.EconomyAPI;
 import me.lethunderhawk.main.Main;
 import me.lethunderhawk.main.util.UnItalic;
 import me.lethunderhawk.tradeplugin.TradeModule;
@@ -29,11 +30,11 @@ public class TradeSession {
     private final List<ItemStack> p1Items = new ArrayList<>();
     private final List<ItemStack> p2Items = new ArrayList<>();
     private static final NamespacedKey FLUX_KEY =
-            new NamespacedKey(Main.getInstance(), "flux_item");
+            new NamespacedKey(Services.get(Main.class), "flux_item");
     private static final NamespacedKey OWNER_KEY =
-            new NamespacedKey(Main.getInstance(), "flux_owner");
+            new NamespacedKey(Services.get(Main.class), "flux_owner");
     private static final NamespacedKey VALUE_KEY =
-            new NamespacedKey(Main.getInstance(), "flux_value");
+            new NamespacedKey(Services.get(Main.class), "flux_value");
 
     private TradeState state = TradeState.WAITING;
     private long p1Flux = 0, p2Flux = 0;
@@ -179,11 +180,12 @@ public class TradeSession {
     }
 
     private void transferFlux() {
+        EconomyAPI eco = Services.get(EconomyAPI.class);
         if(p2Flux > 0){
-            EconomyModule.getInstance().getEconomyAPI().pay(p2.getUniqueId(), p1.getUniqueId(), p2Flux);
+            eco.pay(p2.getUniqueId(), p1.getUniqueId(), p2Flux);
         }
         if(p1Flux > 0){
-            EconomyModule.getInstance().getEconomyAPI().pay(p1.getUniqueId(), p2.getUniqueId(), p1Flux);
+            eco.pay(p1.getUniqueId(), p2.getUniqueId(), p1Flux);
         }
     }