Răsfoiți Sursa

Improved Claims protection, GUI for Clans, ClanSettings needs serialization

Jan 3 săptămâni în urmă
părinte
comite
c2573168db

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

@@ -1,5 +1,8 @@
 package me.lethunderhawk.bazaarflux.util.gui;
 
+import me.lethunderhawk.main.util.UnItalic;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
 import org.bukkit.Bukkit;
 import org.bukkit.Material;
 import org.bukkit.entity.Player;
@@ -57,12 +60,24 @@ public abstract class InventoryGUI implements InventoryHolder {
     /**
      * Fills all empty slots with a background item.
      */
+    public void fillGlassPaneBackground(){
+        ItemStack background = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
+        ItemMeta meta = background.getItemMeta();
+        meta.displayName(Component.text(" "));
+        meta.setHideTooltip(true);
+        background.setItemMeta(meta);
+        for (int i = 0; i < size; i++) {
+            if (inventory.getItem(i) == null) {
+                inventory.setItem(i, background);
+            }
+        }
+    }
     public void fillBackground(Material material, String displayName) {
         ItemStack background = new ItemStack(material);
         ItemMeta meta = background.getItemMeta();
-        meta.setDisplayName(displayName);
+        meta.displayName(Component.text(displayName));
+        meta.setHideTooltip(true);
         background.setItemMeta(meta);
-
         for (int i = 0; i < size; i++) {
             if (inventory.getItem(i) == null) {
                 inventory.setItem(i, background);
@@ -94,11 +109,28 @@ public abstract class InventoryGUI implements InventoryHolder {
     public void openPrevious(Player player) {
         if (!previousGuis.isEmpty()) {
             InventoryGUI previousGui = previousGuis.pop();
-            // Don't use InventoryManager.close() here as it triggers close events
-            // Instead, directly open the previous GUI
+            previousGui.update();
             InventoryManager.openFor(player, previousGui);
         }
     }
+    public void setBackButton(int slot){
+        ItemStack item = new ItemStack(Material.ARROW);
+        ItemMeta meta = item.getItemMeta();
+        meta.displayName(Component.text("Go Back", NamedTextColor.GREEN));
+        item.setItemMeta(UnItalic.removeItalicFromMeta(meta));
+        setItemWithClickAction(slot, item, (p, type) -> {
+            openPrevious(p);
+        });
+    }
+    public void setCloseButton(int slot){
+        ItemStack item = new ItemStack(Material.BARRIER);
+        ItemMeta meta = item.getItemMeta();
+        meta.displayName(Component.text("Close", NamedTextColor.RED));
+        item.setItemMeta(UnItalic.removeItalicFromMeta(meta));
+        setItemWithClickAction(slot, item, (p, type) -> {
+            InventoryManager.close(p.getUniqueId());
+        });
+    }
 
     // Also need to update the overloaded version:
     public void openPrevious(Player player, ClickType type) {

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

@@ -41,7 +41,6 @@ public final class InventoryManager implements Listener {
         // Close current inventory if open
         InventoryGUI current = openGuis.get(player.getUniqueId());
         if (current != null) {
-            player.closeInventory();
             openGuis.remove(player.getUniqueId());
         }
 

+ 18 - 17
src/main/java/me/lethunderhawk/clans/Clan.java

@@ -1,7 +1,8 @@
 package me.lethunderhawk.clans;
 
 import me.lethunderhawk.clans.claim.Claim;
-import me.lethunderhawk.clans.rules.Rule;
+import me.lethunderhawk.clans.settings.ClanSetting;
+import me.lethunderhawk.clans.settings.ClanSettings;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.event.ClickEvent;
 import net.kyori.adventure.text.format.NamedTextColor;
@@ -16,33 +17,20 @@ 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 Set<Rule> ruleSet;
+    private final ClanSettings settings = new ClanSettings();
     private final List<Claim> claims = new ArrayList<>();
     private final UUID id;
 
-    public Clan(String name, UUID owner, Set<Rule> ruleSet, Set<UUID> members){
-        this.name = name;
-        this.owner = owner;
-        this.ruleSet = ruleSet;
-        this.members = members;
-        id = UUID.randomUUID();
-    }
-
     public Clan(String name, UUID owner, UUID id, Set<UUID> members){
         this.name = name;
         this.owner = owner;
         this.members = members;
         this.id = id;
-        ruleSet = new HashSet<>();
     }
     public String toTabComplete() {
         return name.toLowerCase().trim();
     }
 
-    public Set<Rule> getRules() {
-        return ruleSet;
-    }
-
     public boolean isInClan(UUID player) {
         return owner.equals(player) || members.contains(player);
     }
@@ -107,6 +95,7 @@ public class Clan {
     public Set<String> getRequests() {
         return pendingRequests.keySet();
     }
+
     public int getUsedBlocks() {
         return claims.stream().mapToInt(Claim::getVolume).sum();
     }
@@ -145,7 +134,19 @@ public class Clan {
         return playerList;
     }
 
-    public void setRules(Set<Rule> rules) {
-        this.ruleSet = rules;
+    public void toggleSetting(ClanSetting setting) {
+        settings.toggleSetting(setting);
+    }
+
+    public boolean allows(ClanSetting setting) {
+        return settings.isAllowed(setting);
+    }
+
+    public ClanSettings getSettings() {
+        return settings;
+    }
+
+    public void removeClaim(Claim claim) {
+        claims.remove(claim);
     }
 }

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

@@ -2,7 +2,7 @@ package me.lethunderhawk.clans;
 
 import me.lethunderhawk.clans.claim.Claim;
 import me.lethunderhawk.clans.claim.ClaimManager;
-import me.lethunderhawk.clans.rules.Rule;
+import me.lethunderhawk.clans.settings.ClanSettings;
 import org.bukkit.Bukkit;
 import org.bukkit.Location;
 import org.bukkit.configuration.ConfigurationSection;
@@ -18,7 +18,7 @@ import java.util.*;
 import java.util.stream.Collectors;
 
 public class ClanManager {
-    private final Set<Rule> basicRules = new HashSet<>();
+    private final ClanSettings basicClanSettings = new ClanSettings();
     private final HashMap<UUID, Clan> clans = new HashMap<>();
 
     private final File clansFile;
@@ -77,13 +77,14 @@ public class ClanManager {
                     .map(UUID::fromString)
                     .collect(Collectors.toSet());
 
-            Set<Rule> rules = clansConfig.getStringList(base + ".rules")
-                    .stream()
-                    .map(Rule::fromString)
-                    .collect(Collectors.toSet());
+//            Set<ClanSettings> clanSettings = clansConfig.getStringList(base + ".rules")
+//                    .stream()
+//                    .map(ClanSettings::fromString)
+//                    .collect(Collectors.toSet());
 
             Clan clan = new Clan(name, owner, id, members);
-            clan.setRules(rules);
+
+//            clan.setRules(clanSettings);
 
             // ---- Claims laden ----
             List<Map<?, ?>> claimData = clansConfig.getMapList(base + ".claims");
@@ -123,6 +124,7 @@ public class ClanManager {
             }
 
             clansConfig.set(path + ".claims", claimList);
+            clansConfig.set(path + ".settings", basicClanSettings);
         }
 
         try {

+ 5 - 2
src/main/java/me/lethunderhawk/clans/ClanModule.java

@@ -9,10 +9,12 @@ import me.lethunderhawk.main.Main;
 import net.kyori.adventure.audience.Audience;
 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 String getPrefix(){
         return "[Clan]";
@@ -22,11 +24,11 @@ public class ClanModule {
 
         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));
 
-        Main.getInstance().getServer().getPluginManager().registerEvents(new ClaimListener(claimManager), Main.getInstance());
+        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();
@@ -49,6 +51,7 @@ public class ClanModule {
     }
 
     public void onDisable(){
+        HandlerList.unregisterAll(claimListener);
         clanManager.saveClans();
     }
 }

+ 71 - 7
src/main/java/me/lethunderhawk/clans/claim/ClaimListener.java

@@ -1,25 +1,90 @@
 package me.lethunderhawk.clans.claim;
 
 import me.lethunderhawk.clans.Clan;
+import me.lethunderhawk.clans.ClanManager;
+import me.lethunderhawk.clans.settings.ClanSetting;
 import me.lethunderhawk.main.Main;
 import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+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.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.player.PlayerInteractEntityEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
 
 import java.util.UUID;
 
 public class ClaimListener implements Listener {
     private final ClaimManager claimManager;
+    private final ClanManager clanManager;
 
-    public ClaimListener(ClaimManager claimManager) {
+    public ClaimListener(ClaimManager claimManager, ClanManager clanManager) {
         this.claimManager = claimManager;
+        this.clanManager = clanManager;
     }
 
+    @EventHandler(ignoreCancelled = true)
+    public void onPlayerInteract(PlayerInteractEvent event) {
+        if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
+
+        Block block = event.getClickedBlock();
+        if (block == null) return;
+
+        Location loc = block.getLocation();
+
+        BlockData data = block.getBlockData();
+
+        // Containers
+        if (block.getState() instanceof Container) {
+            if (preventChange(event.getPlayer().getUniqueId(), loc, ClanSetting.OPEN_CONTAINER)) {
+                event.setCancelled(true);
+            }
+            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);
+            }
+            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);
+            }
+        }
+    }
+
+
     @EventHandler
     public void onBreak(BlockBreakEvent e) {
-        if(preventChange(e.getPlayer().getUniqueId(), e.getBlock().getLocation())){
+        if(preventChange(e.getPlayer().getUniqueId(), e.getBlock().getLocation(), ClanSetting.BLOCK_BREAK)){
+            e.setCancelled(true);
+            e.getPlayer().sendMessage("§cThis land belongs to another clan!");
+        }
+    }
+    @EventHandler
+    public void onIgnition(BlockIgniteEvent e){
+        if(e.getPlayer() == null) return;
+        if(preventChange(e.getPlayer().getUniqueId(), e.getBlock().getLocation(), ClanSetting.INTERACT_IGNITION)){
+            e.setCancelled(true);
+            e.getPlayer().sendMessage("§cThis land belongs to another clan!");
+        }
+    }
+
+    @EventHandler
+    public void onEntityInteract(PlayerInteractEntityEvent e){
+        if(preventChange(e.getPlayer().getUniqueId(), e.getRightClicked().getLocation(), ClanSetting.INTERACT_ENTITY)){
             e.setCancelled(true);
             e.getPlayer().sendMessage("§cThis land belongs to another clan!");
         }
@@ -27,19 +92,18 @@ public class ClaimListener implements Listener {
 
     @EventHandler
     public void onBlockPlace(BlockPlaceEvent e){
-        if(preventChange(e.getPlayer().getUniqueId(), e.getBlock().getLocation())){
+        if(preventChange(e.getPlayer().getUniqueId(), e.getBlock().getLocation(), ClanSetting.BLOCK_PLACE)){
             e.setCancelled(true);
             e.getPlayer().sendMessage("§cThis land belongs to another clan!");
         }
     }
 
-    private boolean preventChange(UUID playerUUID, Location location){
+    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());
-
-            if (clan != null) {
-                return !clan.isInClan(playerUUID);
+            if (clan != null && !clan.isInClan(playerUUID)) {
+                return !clan.allows(setting);
             }
         }
         return false;

+ 9 - 0
src/main/java/me/lethunderhawk/clans/claim/ClaimManager.java

@@ -1,5 +1,7 @@
 package me.lethunderhawk.clans.claim;
 
+import me.lethunderhawk.clans.Clan;
+import me.lethunderhawk.main.Main;
 import org.bukkit.Location;
 
 import javax.annotation.Nullable;
@@ -45,4 +47,11 @@ public class ClaimManager {
     public void removeAllClaims() {
         allClaims = new ArrayList<>();
     }
+
+    public void removeClaim(Claim claim) {
+        Clan clan = Main.getInstance().getClanModule().getClanManager().getClanById(claim.getClanId());
+        assert clan != null;
+        clan.removeClaim(claim);
+        allClaims.remove(claim);
+    }
 }

+ 10 - 71
src/main/java/me/lethunderhawk/clans/command/ClanCommand.java

@@ -1,12 +1,12 @@
 package me.lethunderhawk.clans.command;
 
 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.rules.Rule;
 import me.lethunderhawk.custom.item.concrete.ClaimTool;
 import me.lethunderhawk.main.Main;
 import net.kyori.adventure.text.Component;
@@ -24,12 +24,11 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
 import java.util.stream.Collectors;
 
 public class ClanCommand implements CommandExecutor, TabCompleter {
-    private ClanManager manager;
-    private CommandNode rootCommand;
+    private final ClanManager manager;
+    private final CommandNode rootCommand;
 
     public ClanCommand(ClanManager manager) {
         this.manager = manager;
@@ -37,7 +36,6 @@ public class ClanCommand implements CommandExecutor, TabCompleter {
         setupDefaultCommands();
     }
     private void setupDefaultCommands() {
-        // Register default commands
 
         registerCommand("list", "List all clans", this::handleList);
         registerCommand("help", "Gives information about the use of clan commands", this::handleHelp);
@@ -45,7 +43,8 @@ public class ClanCommand implements CommandExecutor, TabCompleter {
         registerCommand("reload", "Reload the clan Plugin", this::handleReload);
         registerCommand("members", "Show the members of your clan", this::handleShowMembers);
         registerCommand("save", "Save all clans and Claims", this::handleSave);
-        //registerCommand("menu", "Shows a GUI to handle your clan if you are the owner", this::handleGUI);
+        registerCommand("menu", "Shows a GUI to handle your clan if you are the owner", this::handleGUI);
+
         CommandNode claimNode = registerCommand("claim", "Claim land for your clan", this::handleClaim);
         claimNode.registerSubCommand("info", "Get information about your claims", this::infoClaims);
         claimNode.registerSubCommand("removeAll", "Remove all current claims", this::removeAllClaims);
@@ -62,14 +61,6 @@ public class ClanCommand implements CommandExecutor, TabCompleter {
         CommandNode joinNode = registerCommand("join", "Join a clan", this::handleJoin);
         joinNode.setTabCompleter(this::completeClans);
 
-        CommandNode ruleNode = registerCommand("rule", "Manage clan rules", null);
-        ruleNode.registerSubCommand("list", "List all rules", this::handleRuleList);
-        ruleNode.registerSubCommand("set", "Set a rule value", this::handleRuleSet)
-                .setTabCompleter(this::completeRules);
-        ruleNode.registerSubCommand("add", "Add a new rule", this::handleRuleAdd);
-        ruleNode.registerSubCommand("remove", "Remove a rule", this::handleRuleRemove)
-                .setTabCompleter(this::completeRules);
-
         registerCommand("create", "Create a new clan", this::handleCreate);
     }
 
@@ -106,13 +97,14 @@ public class ClanCommand implements CommandExecutor, TabCompleter {
     }
 
     private void handleClaim(CommandSender sender, String[] strings) {
-        sender.sendMessage("Nothing yet implemented! come back later!");
+
     }
 
     private void handleGUI(CommandSender sender, String[] strings) {
         if(!(sender instanceof Player player)) return;
-        if(manager.getMyClan(player.getUniqueId()) == null) return;
-        new ClanGUI(manager, player).open();
+        Clan myClan =  manager.getMyClan(player.getUniqueId());
+        if(myClan == null) return;
+        InventoryManager.openFor(player, new ClanGUI(myClan, player));
     }
 
 
@@ -199,26 +191,11 @@ public class ClanCommand implements CommandExecutor, TabCompleter {
         else ClanModule.sendText(player,"The Name for the Clan " + name + " is already taken or you are already in a clan!");
     }
 
-    private void handleRuleRemove(CommandSender commandSender, String[] strings) {
-
-    }
-
-    private void handleRuleAdd(CommandSender commandSender, String[] strings) {
-
-    }
-
-    private void handleRuleSet(CommandSender commandSender, String[] strings) {
-
-    }
-
-    private void handleRuleList(CommandSender commandSender, String[] strings) {
-
-    }
-
     // Helper method to easily register commands
     public CommandNode registerCommand(String name, String description, BiConsumer<CommandSender, String[]> executor) {
         return rootCommand.registerSubCommand(name, description, executor);
     }
+
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
         if (args.length == 0) {
@@ -318,30 +295,6 @@ public class ClanCommand implements CommandExecutor, TabCompleter {
         }
     }
 
-    // Dynamic registration API
-    public void registerDynamicCommand(String path, String description,
-                                       BiConsumer<CommandSender, String[]> executor,
-                                       BiFunction<CommandSender, String[], List<String>> tabCompleter) {
-        String[] parts = path.split("\\.");
-        CommandNode currentNode = rootCommand;
-
-        for (String part : parts) {
-            CommandNode nextNode = currentNode.getSubCommand(part);
-            if (nextNode == null) {
-                nextNode = new CommandNode(part, "", null);
-                currentNode.addSubCommand(nextNode);
-            }
-            currentNode = nextNode;
-        }
-
-        currentNode.setExecutor(executor);
-        currentNode.setTabCompleter(tabCompleter);
-        if (!description.isEmpty()) {
-            // Can't directly set description as it's final, would need to modify CommandNode
-            // or use a different approach
-        }
-    }
-
     // Example command handlers
     private void handleList(CommandSender sender, String[] args) {
         ClanModule.sendText(sender,"Aktuelle Liste an Clans: ");
@@ -369,20 +322,6 @@ public class ClanCommand implements CommandExecutor, TabCompleter {
                 .filter(name -> name.toLowerCase().startsWith(partial))
                 .collect(Collectors.toList());
     }
-
-    private List<String> completeRules(CommandSender sender, String[] args) {
-        if(!(sender instanceof Player player)) return List.of("Your not a player!");
-
-        Clan clan = manager.getMyClan(player.getUniqueId());
-        if (clan == null) return List.of("You are not in a clan!");
-        if (clan.getRules() == null) return List.of("No rules set yet!");
-
-        String partial = args.length > 0 ? args[args.length - 1].toLowerCase() : "";
-        return clan.getRules().stream()
-                .map(Rule::getName)
-                .filter(name -> name.toLowerCase().startsWith(partial))
-                .collect(Collectors.toList());
-    }
     private List<String> completeRequests(CommandSender sender, String[] args) {
         if(!(sender instanceof Player player)) return List.of("Your not a player!");
 

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

@@ -0,0 +1,26 @@
+package me.lethunderhawk.clans.gui;
+
+import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
+import org.bukkit.entity.Player;
+
+public class AdminMenuGUI extends InventoryGUI {
+
+    private final Player player;
+
+    public AdminMenuGUI(Player player) {
+        super("Admin Panel - Edit all clans", 36);
+        this.player = player;
+        buildGUI();
+    }
+
+    private void buildGUI() {
+        fillGlassPaneBackground();
+        setBackButton(30);
+        setCloseButton(31);
+    }
+
+    @Override
+    public void update() {
+
+    }
+}

+ 85 - 0
src/main/java/me/lethunderhawk/clans/gui/ClaimSettingsGUI.java

@@ -0,0 +1,85 @@
+package me.lethunderhawk.clans.gui;
+
+import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
+import me.lethunderhawk.clans.Clan;
+import me.lethunderhawk.clans.claim.Claim;
+import me.lethunderhawk.clans.claim.ClaimManager;
+import me.lethunderhawk.main.Main;
+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.event.inventory.ClickType;
+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 {
+
+    private final Player player;
+    private final Clan clan;
+
+    public ClaimSettingsGUI(Player player, Clan clan) {
+        super("Claim Settings", 36);
+        this.player = player;
+        this.clan = clan;
+        buildGUI();
+    }
+
+    private void buildGUI() {
+        fillGlassPaneBackground();
+        setBackButton(30);
+        setCloseButton(31);
+        buildItems();
+    }
+
+    private void buildItems() {
+        AtomicInteger slot = new AtomicInteger();
+        clan.getClaims().forEach(claim -> {
+            setItemWithClickAction(slot.get(), buildItemFromClaim(claim), (p, type)->{
+                if(type == ClickType.LEFT || type == ClickType.SHIFT_LEFT){
+                    renameClaim(claim);
+                }else if(type == ClickType.RIGHT || type == ClickType.SHIFT_RIGHT){
+                    ConfirmationMenu confirmationMenu = new ConfirmationMenu("Delete Claim?", (pl) ->{
+                        removeClaim(claim);
+                    });
+                    this.openNext(p, confirmationMenu);
+                }
+            });
+            slot.getAndIncrement();
+        });
+    }
+
+    private void removeClaim(Claim claim) {
+        ClaimManager manager = Main.getInstance().getClanModule().getClaimManager();
+        manager.removeClaim(claim);
+    }
+
+    private void renameClaim(Claim claim) {
+
+    }
+
+    private ItemStack buildItemFromClaim(Claim claim) {
+        ItemStack item = new ItemStack(Material.GRASS_BLOCK);
+        ItemMeta meta = item.getItemMeta();
+        meta.displayName(Component.text(claim.getName(), NamedTextColor.GOLD));
+        meta.lore(List.of(
+                Component.text("Spans from x=" + claim.getMaxX() + ", z=" + claim.getMaxZ(), NamedTextColor.GRAY),
+                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)
+        ));
+        item.setItemMeta(UnItalic.removeItalicFromMeta(meta));
+        return item;
+    }
+
+    @Override
+    public void update() {
+        buildGUI();
+    }
+}

+ 95 - 27
src/main/java/me/lethunderhawk/clans/gui/ClanGUI.java

@@ -1,50 +1,118 @@
 package me.lethunderhawk.clans.gui;
 
 import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
-import me.lethunderhawk.bazaarflux.util.gui.PlayerHeadListGUI;
-import me.lethunderhawk.clans.ClanManager;
+import me.lethunderhawk.clans.Clan;
+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.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.List;
 
 public class ClanGUI extends InventoryGUI {
 
-    private final ClanManager manager;
+    private final Clan clan;
     private final Player player;
 
-    public ClanGUI(ClanManager manager, Player player) {
-        super("Main Clan Menu", 54);
-        this.manager = manager;
+    public ClanGUI(Clan clan, Player player) {
+        super("Main Clan Menu", 36);
+        this.clan = clan;
         this.player = player;
-        setup();
+        buildMenu();
     }
-    private void setup(){
-
-        ItemStack stick = new ItemStack(Material.STICK);
-        ItemStack arrow = new ItemStack(Material.ARROW);
-        setItemWithClickAction(0, stick, (p, type) ->
-                p.sendMessage("Hello")
-        );
 
+    private void buildMenu() {
         fillBackground(Material.GRAY_STAINED_GLASS_PANE, " ");
 
-        PlayerHeadListGUI headGui = new PlayerHeadListGUI(
-                "Players",
-                54,
-                manager.getMyClan(player.getUniqueId()).getAllMembers()
-                ,
-                (clicker, target) -> clicker.sendMessage("Clicked: " + target.getName())
-        );
+        buildSettings();
+        buildMemberList();
+        buildClaimList();
+        buildAdminList();
+    }
+
+
 
-        setItemWithClickAction(22, stick, (p, type) ->
-                openNext(p, headGui)
-        );
-        headGui.setItemWithClickAction(53, arrow, headGui::openPrevious);
+    private void buildClaimList() {
+        ItemStack claimList = buildClaimListItem();
+        setItemWithClickAction(15, claimList, (p, click) -> {
+            openNext(p, new ClaimSettingsGUI(player, clan));
+        });
     }
-    public void open(){
-        open(player);
+
+    private ItemStack buildClaimListItem() {
+        ItemStack claimListItem = new ItemStack(Material.GRASS_BLOCK);
+        ItemMeta meta = claimListItem.getItemMeta();
+        meta.displayName(Component.text("Claim List", NamedTextColor.GOLD));
+        meta.lore(List.of(
+                Component.text("Modify all claims", NamedTextColor.GRAY),
+                Component.text("inside your clan", NamedTextColor.GRAY)
+        ));
+        claimListItem.setItemMeta(UnItalic.removeItalicFromMeta(meta));
+        return claimListItem;
+    }
+
+    private void buildMemberList() {
+        ItemStack memberList = buildMemberListIem();
+        setItemWithClickAction(13, memberList, (p, click) -> {
+            openNext(p, new MemberListGUI(player));
+        });
+    }
+
+    private ItemStack buildMemberListIem() {
+        ItemStack memberListItem = new ItemStack(Material.PLAYER_HEAD);
+        ItemMeta meta = memberListItem.getItemMeta();
+        meta.displayName(Component.text("Member List", NamedTextColor.GOLD));
+        meta.lore(List.of(
+                Component.text("Open a list of all", NamedTextColor.GRAY),
+                Component.text("members in your clan", NamedTextColor.GRAY)
+        ));
+        memberListItem.setItemMeta(UnItalic.removeItalicFromMeta(meta));
+        return memberListItem;
     }
 
+    private void buildSettings() {
+        ItemStack settings = buildSettingsItem();
+        setItemWithClickAction(11, settings, (p, click) -> {
+            openNext(p, new ClanSettingsGUI(player, clan.getSettings()));
+        });
+    }
+
+    private ItemStack buildSettingsItem() {
+        ItemStack settingsItem = new ItemStack(Material.REDSTONE_TORCH);
+        ItemMeta meta = settingsItem.getItemMeta();
+        meta.displayName(Component.text("Settings", NamedTextColor.GOLD));
+        meta.lore(List.of(
+                Component.text("Configure the settings", NamedTextColor.GRAY),
+                Component.text("of your Clan", NamedTextColor.GRAY)
+        ));
+        settingsItem.setItemMeta(UnItalic.removeItalicFromMeta(meta));
+        return settingsItem;
+    }
+
+    private void buildAdminList() {
+        if(player.hasPermission("clan.admin")) {
+            ItemStack admin = buildAdminItem();
+            setItemWithClickAction(35, admin, (p, click) -> {
+                openNext(p, new AdminMenuGUI(player));
+            });
+        }
+    }
+
+    private ItemStack buildAdminItem() {
+        ItemStack admin = new ItemStack(Material.COMMAND_BLOCK);
+        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")
+        ));
+        admin.setItemMeta(UnItalic.removeItalicFromMeta(meta));
+        return admin;
+    }
+
+
     @Override
     public void update() {
 

+ 88 - 0
src/main/java/me/lethunderhawk/clans/gui/ClanSettingsGUI.java

@@ -0,0 +1,88 @@
+package me.lethunderhawk.clans.gui;
+
+import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
+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 org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ClanSettingsGUI extends InventoryGUI {
+    private final Player player;
+    private final ClanSettings settings;
+
+    public ClanSettingsGUI(Player player, ClanSettings settings) {
+        super("Clan Settings", 36);
+        this.player = player;
+        this.settings = settings;
+
+        buildGUI();
+    }
+
+    private void buildGUI() {
+        fillGlassPaneBackground();
+        setBackButton(30);
+        setCloseButton(31);
+
+        buildItems();
+    }
+
+    private void buildItems() {
+        AtomicInteger slot = new AtomicInteger(10);
+        settings.asMap().forEach((setting, value) -> {
+            ItemStack settingsItem;
+            if(value == true){
+                settingsItem = new ItemStack(Material.LIME_STAINED_GLASS_PANE);
+            }else{
+                settingsItem = new ItemStack(Material.RED_STAINED_GLASS_PANE);
+            }
+            ItemMeta meta = settingsItem.getItemMeta();
+            meta.displayName(getReadableNameFromSetting(setting));
+            settingsItem.setItemMeta(UnItalic.removeItalicFromMeta(meta));
+            setItemWithClickAction(slot.get(), settingsItem, (p, type) -> {
+                settings.toggleSetting(setting);
+                update();
+            });
+            slot.getAndIncrement();
+        });
+    }
+
+    private Component getReadableNameFromSetting(ClanSetting setting) {
+        switch (setting){
+            case ClanSetting.BLOCK_BREAK -> {
+                return Component.text("Breaking Blocks");
+            }
+            case ClanSetting.BLOCK_PLACE -> {
+                return Component.text("Placing Blocks");
+            }
+            case ClanSetting.INTERACT_IGNITION -> {
+                return Component.text("Igniting Blocks");
+            }
+            case ClanSetting.INTERACT_BLOCK -> {
+                return Component.text("Interacting with Blocks");
+            }
+            case ClanSetting.INTERACT_ENTITY -> {
+                return Component.text("Interacting with Entities");
+            }
+            case ClanSetting.OPEN_CONTAINER -> {
+                return Component.text("Opening Containers");
+            }
+            case ClanSetting.USE_ANVIL -> {
+                return Component.text("Using Anvil");
+            }
+            default -> {
+                return Component.text(setting.name());
+            }
+        }
+    }
+
+    @Override
+    public void update() {
+        buildItems();
+    }
+}

+ 41 - 0
src/main/java/me/lethunderhawk/clans/gui/ConfirmationMenu.java

@@ -0,0 +1,41 @@
+package me.lethunderhawk.clans.gui;
+
+import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.function.Consumer;
+
+public class ConfirmationMenu extends InventoryGUI {
+    private final Consumer<Player> callback;
+
+    public ConfirmationMenu(String title, Consumer<Player> callback ) {
+        super(title, 27);
+
+        this.callback = callback;
+        setupItems();
+    }
+
+    private void setupItems() {
+        fillGlassPaneBackground();
+
+        ItemStack IAmSure = new ItemStack(Material.LIME_STAINED_GLASS_PANE);
+
+        setItemWithClickAction(11, IAmSure, (p, type)->{
+            callback.accept(p);
+            openPrevious(p);
+        });
+
+        ItemStack NoPleaseNot = new ItemStack(Material.BARRIER);
+
+        setItemWithClickAction(15, NoPleaseNot, (p, type)->{
+            openPrevious(p);
+        });
+    }
+
+    @Override
+    public void update() {
+
+    }
+}

+ 25 - 0
src/main/java/me/lethunderhawk/clans/gui/MemberListGUI.java

@@ -0,0 +1,25 @@
+package me.lethunderhawk.clans.gui;
+
+import me.lethunderhawk.bazaarflux.util.gui.InventoryGUI;
+import org.bukkit.entity.Player;
+
+public class MemberListGUI extends InventoryGUI {
+    private final Player player;
+
+    public MemberListGUI(Player player) {
+        super("Member List", 36);
+        this.player = player;
+        buildGUI();
+    }
+
+    private void buildGUI() {
+        fillGlassPaneBackground();
+        setBackButton(30);
+        setCloseButton(31);
+    }
+
+    @Override
+    public void update() {
+        
+    }
+}

+ 0 - 23
src/main/java/me/lethunderhawk/clans/rules/Rule.java

@@ -1,23 +0,0 @@
-package me.lethunderhawk.clans.rules;
-
-public class Rule {
-    private String name, description;
-
-    public Rule(String name, String description){
-
-    }
-    public String toTabComplete() {
-        return name.toLowerCase().trim();
-    }
-
-    public String getName() {
-        return name;
-    }
-    @Override
-    public String toString(){
-        return name;
-    }
-    public static Rule fromString(String s) {
-        return new Rule("custom-name", s);
-    }
-}

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

@@ -0,0 +1,13 @@
+package me.lethunderhawk.clans.settings;
+
+public enum ClanSetting {
+
+    BLOCK_BREAK,
+    BLOCK_PLACE,
+
+    OPEN_CONTAINER,   // chests, barrels, shulker boxes, hoppers
+    INTERACT_BLOCK,   // buttons, levers, doors, trapdoors
+    INTERACT_ENTITY,  // item frames, armor stands, villagers
+    INTERACT_IGNITION,
+    USE_ANVIL;
+}

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

@@ -0,0 +1,29 @@
+package me.lethunderhawk.clans.settings;
+
+import java.util.EnumMap;
+import java.util.Map;
+
+public final class ClanSettings {
+    private final boolean enableAllByDefault = false;
+    private final EnumMap<ClanSetting, Boolean> settings = new EnumMap<>(ClanSetting.class);
+
+    public ClanSettings() {
+        for (ClanSetting setting : ClanSetting.values()) {
+            settings.put(setting, enableAllByDefault);
+        }
+    }
+    public void toggleSetting(ClanSetting setting){
+        settings.put(setting, !settings.get(setting));
+    }
+    public boolean isAllowed(ClanSetting setting) {
+        return settings.getOrDefault(setting, enableAllByDefault);
+    }
+
+    public void set(ClanSetting setting, boolean value) {
+        settings.put(setting, value);
+    }
+
+    public Map<ClanSetting, Boolean> asMap() {
+        return settings;
+    }
+}

+ 11 - 6
src/main/java/me/lethunderhawk/economy/command/EcoCommand.java

@@ -31,7 +31,7 @@ public class EcoCommand implements CommandExecutor, TabCompleter {
     }
 
     private void setupDefaultCommands() {
-        registerCommand("help", "Get a list of available commands", this::getBalance);
+        registerCommand("help", "Get a list of available commands", this::sendHelp);
         CommandNode set = registerCommand("set", "Set the balance of a player", this::setEco);
         set.setTabCompleter(this::completeAllEcoCommands);
 
@@ -58,8 +58,6 @@ public class EcoCommand implements CommandExecutor, TabCompleter {
      * @return The completion in following format: /eco [action] [List of players] [amount]
      */
     private List<String> completeAllEcoCommands(CommandSender sender, String[] args){
-        // /eco <action> <player>
-        System.out.println(args.length);
         if (args.length == 2) {
             return completePlayers(sender, args);
         }
@@ -87,10 +85,17 @@ public class EcoCommand implements CommandExecutor, TabCompleter {
     }
 
     private void addEco(CommandSender commandSender, String[] strings) {
-
+        if(!commandSender.isOp()) return;
+        Player target = Bukkit.getPlayer(strings[0]);
+        if (target == null) {
+            EconomyModule.sendText(commandSender, Component.text("Spieler nicht gefunden.",  NamedTextColor.RED));
+        }else{
+            getAPI().addMoney(target.getUniqueId(), Integer.parseInt(strings[1]));
+        }
     }
 
     private void setEco(CommandSender commandSender, String[] strings) {
+        if(!commandSender.isOp()) return;
         Player target = Bukkit.getPlayer(strings[0]);
         if (target == null) {
             EconomyModule.sendText(commandSender, Component.text("Spieler nicht gefunden.",  NamedTextColor.RED));
@@ -109,7 +114,7 @@ public class EcoCommand implements CommandExecutor, TabCompleter {
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
         if (args.length == 0) {
-            sendHelp(sender);
+            sendHelp(sender, args);
             return true;
         }
 
@@ -154,7 +159,7 @@ public class EcoCommand implements CommandExecutor, TabCompleter {
         targetNode.getExecutor().accept(sender, remainingArgs);
         return true;
     }
-    private void sendHelp(CommandSender sender) {
+    private void sendHelp(CommandSender sender, String[] strings) {
         sender.sendMessage("§6=== Eco Commands ===");
         for (CommandNode cmd : rootCommand.getSubCommands()) {
             sender.sendMessage("§e/eco " + cmd.getName() + " §7- " + cmd.getDescription());

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

@@ -30,10 +30,8 @@ public class MinionMenu extends InventoryGUI implements InventoryGUI.AutoCloseHa
     }
 
     private void buildContents() {
-        // Fill background with stained glass panes
-        fillBackground(Material.GRAY_STAINED_GLASS_PANE, " ");
+        fillGlassPaneBackground();
 
-        // Minion head/icon in the center (slot 13)
         ItemStack minionItem = minion.getHelmetItem().clone();
         ItemMeta minionMeta = minionItem.getItemMeta();
         minionMeta.displayName(UnItalic.text(minion.getType().getName() + " " + minion.getRomanLevel()).color(NamedTextColor.BLUE));
@@ -65,7 +63,6 @@ public class MinionMenu extends InventoryGUI implements InventoryGUI.AutoCloseHa
             if(newMinion != null) {
                 MinionManager.stopAndUnregister(minion);
                 MinionManager.startAndRegister(newMinion, plugin);
-                InventoryManager.close(p.getUniqueId());
                 InventoryManager.openFor(p, new MinionMenu(newMinion));
             }else{
                 p.sendMessage("§cAlready at max tier.");