Просмотр исходного кода

Small rework of Sacks, additional Sacks, loading from config; Implemented Shop with customizable Selling/Buying of items; fixed Display issue for custom item abilities with multiple Triggers, now only showing the first trigger for each ability

Jan 1 месяц назад
Родитель
Сommit
7c6faf25df
46 измененных файлов с 1288 добавлено и 694 удалено
  1. 3 10
      pom.xml
  2. 3 24
      src/main/java/me/lethunderhawk/clans/Clan.java
  3. 6 7
      src/main/java/me/lethunderhawk/clans/ClanManager.java
  4. 6 9
      src/main/java/me/lethunderhawk/clans/ClanModule.java
  5. 43 5
      src/main/java/me/lethunderhawk/clans/claim/Claim.java
  6. 40 25
      src/main/java/me/lethunderhawk/clans/claim/ClaimListener.java
  7. 3 2
      src/main/java/me/lethunderhawk/clans/claim/ClaimManager.java
  8. 2 0
      src/main/java/me/lethunderhawk/clans/command/ClanCommand.java
  9. 89 0
      src/main/java/me/lethunderhawk/clans/gui/ClaimListGUI.java
  10. 98 45
      src/main/java/me/lethunderhawk/clans/gui/ClaimSettingsGUI.java
  11. 19 5
      src/main/java/me/lethunderhawk/clans/gui/ClanMenu.java
  12. 0 180
      src/main/java/me/lethunderhawk/clans/gui/ClanSettingsGUI.java
  13. 1 2
      src/main/java/me/lethunderhawk/clans/gui/MemberListGUI.java
  14. 4 4
      src/main/java/me/lethunderhawk/clans/settings/ClaimSetting.java
  15. 15 13
      src/main/java/me/lethunderhawk/clans/settings/ClaimSettings.java
  16. 5 0
      src/main/java/me/lethunderhawk/custom/item/CustomItemModule.java
  17. 2 0
      src/main/java/me/lethunderhawk/custom/item/abstraction/ability/AbilityContext.java
  18. 3 4
      src/main/java/me/lethunderhawk/custom/item/abstraction/ability/AbilityDefinition.java
  19. 1 1
      src/main/java/me/lethunderhawk/custom/item/abstraction/definition/ItemDefinitionLoader.java
  20. 1 1
      src/main/java/me/lethunderhawk/custom/item/abstraction/runtime/AbilityDispatchService.java
  21. 1 1
      src/main/java/me/lethunderhawk/custom/item/concrete/ability/RollingDiceAbility.java
  22. 6 5
      src/main/java/me/lethunderhawk/custom/item/concrete/ability/SackAbility.java
  23. 35 0
      src/main/java/me/lethunderhawk/custom/item/concrete/ability/SnowBallShooterAbility.java
  24. 5 1
      src/main/java/me/lethunderhawk/custom/item/listener/CustomItemListener.java
  25. 0 40
      src/main/java/me/lethunderhawk/custom/recipes/CustomRecipeModule.java
  26. 15 15
      src/main/java/me/lethunderhawk/custom/recipes/enchantedVariant/recipe/EnchantedItemRecipe.java
  27. 13 13
      src/main/java/me/lethunderhawk/custom/recipes/enchantedVariant/recipe/StackSizeIngredient.java
  28. 20 8
      src/main/java/me/lethunderhawk/economy/EconomyModule.java
  29. 8 5
      src/main/java/me/lethunderhawk/economy/api/EconomyAPI.java
  30. 11 2
      src/main/java/me/lethunderhawk/economy/command/EcoCommand.java
  31. 17 11
      src/main/java/me/lethunderhawk/economy/currency/EconomyManager.java
  32. 133 0
      src/main/java/me/lethunderhawk/economy/shop/BuyingItemsEditGUI.java
  33. 49 0
      src/main/java/me/lethunderhawk/economy/shop/ItemValues.java
  34. 132 0
      src/main/java/me/lethunderhawk/economy/shop/SellingItemsEditGUI.java
  35. 47 0
      src/main/java/me/lethunderhawk/economy/shop/ShopEditGUI.java
  36. 112 0
      src/main/java/me/lethunderhawk/economy/shop/ShopGUI.java
  37. 4 5
      src/main/java/me/lethunderhawk/main/BazaarFlux.java
  38. 28 50
      src/main/java/me/lethunderhawk/profile/ProfileModule.java
  39. 23 38
      src/main/java/me/lethunderhawk/profile/data/sacks/Sack.java
  40. 48 0
      src/main/java/me/lethunderhawk/profile/data/sacks/SackConfigLoader.java
  41. 31 47
      src/main/java/me/lethunderhawk/profile/data/sacks/SackContent.java
  42. 30 0
      src/main/java/me/lethunderhawk/profile/data/sacks/SackRegistry.java
  43. 4 1
      src/main/java/me/lethunderhawk/profile/data/sacks/SackType.java
  44. 32 113
      src/main/java/me/lethunderhawk/profile/data/sacks/gui/SackGUI.java
  45. 9 2
      src/main/java/me/lethunderhawk/profile/gui/StatsGUI.java
  46. 131 0
      src/main/resources/config.yml

+ 3 - 10
pom.xml

@@ -6,7 +6,7 @@
 
     <groupId>me.lethunderhawk</groupId>
     <artifactId>BazaarFlux</artifactId>
-    <version>1.2-SNAPSHOT</version>
+    <version>1.2.5-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <name>BazaarFlux</name>
@@ -80,14 +80,7 @@
         <dependency>
             <groupId>io.papermc.paper</groupId>
             <artifactId>paper-api</artifactId>
-            <version>1.21.10-R0.1-SNAPSHOT</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.spigotmc</groupId>
-            <artifactId>spigot</artifactId>
-            <version>1.21.10-R0.1-SNAPSHOT</version>
-            <classifier>remapped-mojang</classifier>
+            <version>1.21.11-R0.1-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -105,7 +98,7 @@
         <dependency>
             <groupId>me.lethunderhawk</groupId>
             <artifactId>FluxAPI</artifactId>
-            <version>1.2.4</version>
+            <version>1.2.5</version>
             <scope>provided</scope>
         </dependency>
     </dependencies>

+ 3 - 24
src/main/java/me/lethunderhawk/clans/Clan.java

@@ -1,9 +1,7 @@
 package me.lethunderhawk.clans;
 
-import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.clans.claim.Claim;
-import me.lethunderhawk.clans.settings.ClanSetting;
-import me.lethunderhawk.clans.settings.ClanSettings;
+import me.lethunderhawk.fluxapi.FluxService;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.event.ClickEvent;
 import net.kyori.adventure.text.format.NamedTextColor;
@@ -18,7 +16,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;
+
     private final List<Claim> claims = new ArrayList<>();
     private final UUID id;
 
@@ -27,14 +25,6 @@ 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();
@@ -88,6 +78,7 @@ public class Clan {
     public String getName() {
         return name;
     }
+
     public Set<UUID> getAllMemberUUIDs() {
         Set<UUID> allMembers = new HashSet<>(members);
         allMembers.add(owner);
@@ -113,7 +104,6 @@ public class Clan {
         claims.add(claim);
     }
 
-
     public boolean isInsideClaim(Location loc) {
         return claims.stream().anyMatch(c -> c.contains(loc));
     }
@@ -143,17 +133,6 @@ public class Clan {
         return playerList;
     }
 
-    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);

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

@@ -2,7 +2,6 @@ package me.lethunderhawk.clans;
 
 import me.lethunderhawk.clans.claim.Claim;
 import me.lethunderhawk.clans.claim.ClaimManager;
-import me.lethunderhawk.clans.settings.ClanSettings;
 import org.bukkit.Bukkit;
 import org.bukkit.Location;
 import org.bukkit.configuration.ConfigurationSection;
@@ -18,7 +17,6 @@ import java.util.*;
 import java.util.stream.Collectors;
 
 public class ClanManager {
-    private final ClanSettings basicClanSettings = new ClanSettings();
     private final HashMap<UUID, Clan> clans = new HashMap<>();
 
     private final File clansFile;
@@ -77,11 +75,11 @@ public class ClanManager {
                     .map(UUID::fromString)
                     .collect(Collectors.toSet());
 
-            Map<String, Object> settingsMap = Objects.requireNonNull(clansConfig.getConfigurationSection(base + ".settings")).getValues(false);
+            //Map<String, Object> settingsMap = Objects.requireNonNull(clansConfig.getConfigurationSection(base + ".settings")).getValues(false);
 
-            ClanSettings settings = ClanSettings.fromMap(settingsMap);
+            //ClanSettings settings = ClanSettings.fromMap(settingsMap);
 
-            Clan clan = new Clan(name, owner, id, members, settings);
+            Clan clan = new Clan(name, owner, id, members);
 
             // ---- Claims laden ----
             List<Map<?, ?>> claimData = clansConfig.getMapList(base + ".claims");
@@ -118,11 +116,12 @@ public class ClanManager {
                 map.put("maxX", c.getMaxX());
                 map.put("minZ", c.getMinZ());
                 map.put("maxZ", c.getMaxZ());
+                map.put("settings", c.getSettings().toStringMap());
+
                 claimList.add(map);
             }
 
             clansConfig.set(path + ".claims", claimList);
-            clansConfig.set(path + ".settings", clan.getSettings().toStringMap());
         }
 
         try {
@@ -151,7 +150,7 @@ public class ClanManager {
      *
      * @param player The player that creates the Clan / the owner
      * @param name The name of the clan
-     * @return if the clan was succesfully created or not
+     * @return if the clan was successfully created or not
      */
     public boolean createClan(Player player, String name) {
         if(name.isEmpty() || isThisNameTaken(name)) return false;

+ 6 - 9
src/main/java/me/lethunderhawk/clans/ClanModule.java

@@ -6,7 +6,6 @@ import me.lethunderhawk.clans.command.ClanCommand;
 import me.lethunderhawk.clans.placeholder.ClanPlaceHolder;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.interfaces.FluxAPIModule;
-import me.lethunderhawk.main.BazaarFlux;
 import org.bukkit.event.HandlerList;
 import org.bukkit.plugin.java.JavaPlugin;
 
@@ -21,24 +20,22 @@ public class ClanModule extends FluxAPIModule {
     }
 
     public void onEnable(){
-        BazaarFlux bazaarFlux = FluxService.get(BazaarFlux.class);
         ClaimManager claimManager = new ClaimManager();
-        ClanManager clanManager = new ClanManager(bazaarFlux, claimManager);
+        ClanManager clanManager = new ClanManager(plugin, claimManager);
 
         FluxService.register(ClaimManager.class, claimManager);
         FluxService.register(ClanManager.class, clanManager);
 
+        ClaimListener claimListener = new ClaimListener(claimManager);
 
-
-        ClaimListener claimListener = new ClaimListener(claimManager, clanManager);
         FluxService.register(ClaimListener.class, claimListener);
 
-        bazaarFlux.getCommand("clan").setExecutor(new ClanCommand(clanManager));
-        bazaarFlux.getCommand("clan").setTabCompleter(new ClanCommand(clanManager));
+        plugin.getCommand("clan").setExecutor(new ClanCommand(clanManager));
+        plugin.getCommand("clan").setTabCompleter(new ClanCommand(clanManager));
 
-        bazaarFlux.getServer().getPluginManager().registerEvents(claimListener, bazaarFlux);
+        plugin.getServer().getPluginManager().registerEvents(claimListener, plugin);
 
-        if (bazaarFlux.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI")) {
+        if (plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI")) {
             new ClanPlaceHolder().register();
         }
 

+ 43 - 5
src/main/java/me/lethunderhawk/clans/claim/Claim.java

@@ -1,8 +1,12 @@
 package me.lethunderhawk.clans.claim;
 
-import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.clans.Clan;
 import me.lethunderhawk.clans.ClanManager;
+import me.lethunderhawk.clans.settings.ClaimSetting;
+import me.lethunderhawk.clans.settings.ClaimSettings;
+import me.lethunderhawk.fluxapi.FluxService;
+import me.lethunderhawk.fluxapi.profile.AnnotatedProfileCategory;
+import me.lethunderhawk.fluxapi.profile.AnnotatedSerializable;
 import org.bukkit.Chunk;
 import org.bukkit.Location;
 
@@ -11,10 +15,14 @@ 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
+public class Claim extends AnnotatedProfileCategory {
+    @AnnotatedSerializable(prefix = "clanID")
+    private final UUID clanId;
+    @AnnotatedSerializable(prefix = "world")
     private final String world;
+    @AnnotatedSerializable(prefix = "settings")
+    private final ClaimSettings settings;
+
     Set<Long> chunks = new HashSet<>();
 
     private final int minX, maxX;
@@ -30,6 +38,20 @@ public class Claim {
 
         this.minZ = Math.min(z1, z2);
         this.maxZ = Math.max(z1, z2);
+
+        this.settings = new ClaimSettings();
+    }
+    public Claim(UUID clanId, String world, int x1, int x2, int z1, int z2, ClaimSettings settings) {
+        this.clanId = clanId;
+        this.world = world;
+
+        this.minX = Math.min(x1, x2);
+        this.maxX = Math.max(x1, x2);
+
+        this.minZ = Math.min(z1, z2);
+        this.maxZ = Math.max(z1, z2);
+
+        this.settings = settings;
     }
 
     public static Claim fromMap(UUID clanId, Map<?, ?> map) {
@@ -41,7 +63,9 @@ public class Claim {
         int minZ = ((Number) map.get("minZ")).intValue();
         int maxZ = ((Number) map.get("maxZ")).intValue();
 
-        return new Claim(clanId, world, minX, maxX, minZ, maxZ);
+        ClaimSettings settings = ClaimSettings.fromMap((Map<String, Object>) map.get("settings"));
+
+        return new Claim(clanId, world, minX, maxX, minZ, maxZ, settings);
     }
 
     public boolean contains(Location loc) {
@@ -84,6 +108,7 @@ public class Claim {
     public int getMinX() {
         return minX;
     }
+
     public int getMinZ() {
         return minZ;
     }
@@ -95,9 +120,11 @@ public class Claim {
     public int getMaxZ() {
         return maxZ;
     }
+
     public void setName(String name) {
         this.name = name;
     }
+
     public String getName() {
         if(name == null || name.isEmpty()) {
             Clan clan = FluxService.get(ClanManager.class).getClanById(clanId);
@@ -106,4 +133,15 @@ public class Claim {
         }
         return name;
     }
+
+    public boolean allows(ClaimSetting setting) {
+        return settings.isAllowed(setting);
+    }
+    public void toggleSetting(ClaimSetting setting) {
+        settings.toggleSetting(setting);
+    }
+
+    public ClaimSettings getSettings() {
+        return settings;
+    }
 }

+ 40 - 25
src/main/java/me/lethunderhawk/clans/claim/ClaimListener.java

@@ -1,9 +1,9 @@
 package me.lethunderhawk.clans.claim;
 
-import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.clans.Clan;
 import me.lethunderhawk.clans.ClanManager;
-import me.lethunderhawk.clans.settings.ClanSetting;
+import me.lethunderhawk.clans.settings.ClaimSetting;
+import me.lethunderhawk.fluxapi.FluxService;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.format.NamedTextColor;
 import org.bukkit.Location;
@@ -17,23 +17,20 @@ import org.bukkit.entity.LivingEntity;
 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.block.*;
 import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.entity.EntityExplodeEvent;
 import org.bukkit.event.player.PlayerInteractEntityEvent;
 import org.bukkit.event.player.PlayerInteractEvent;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.UUID;
 
 public class ClaimListener implements Listener {
     private final ClaimManager claimManager;
-    private final ClanManager clanManager;
 
-    public ClaimListener(ClaimManager claimManager, ClanManager clanManager) {
+    public ClaimListener(ClaimManager claimManager) {
         this.claimManager = claimManager;
-        this.clanManager = clanManager;
     }
 
     @EventHandler(ignoreCancelled = true)
@@ -48,14 +45,14 @@ public class ClaimListener implements Listener {
 
             // Containers
             if (block.getState() instanceof Container) {
-                if (preventChange(event.getPlayer().getUniqueId(), loc, ClanSetting.OPEN_CONTAINER)) {
+                if (preventChange(event.getPlayer().getUniqueId(), loc, ClaimSetting.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)) {
+                if (preventChange(event.getPlayer().getUniqueId(), loc, ClaimSetting.USE_ANVIL)) {
                     event.setCancelled(true);
                 }
                 return;
@@ -63,7 +60,7 @@ public class ClaimListener implements Listener {
 
             // Doors, fence gates, trapdoors, etc.
             if (data instanceof Openable || data instanceof Powerable) {
-                if (preventChange(event.getPlayer().getUniqueId(), loc, ClanSetting.INTERACT_BLOCK)) {
+                if (preventChange(event.getPlayer().getUniqueId(), loc, ClaimSetting.INTERACT_BLOCK)) {
                     event.setCancelled(true);
                 }
             }
@@ -73,7 +70,7 @@ public class ClaimListener implements Listener {
 
     @EventHandler
     public void onBreak(BlockBreakEvent e) {
-        if(preventChange(e.getPlayer().getUniqueId(), e.getBlock().getLocation(), ClanSetting.BLOCK_BREAK)){
+        if(preventChange(e.getPlayer().getUniqueId(), e.getBlock().getLocation(), ClaimSetting.BLOCK_BREAK)){
             e.setCancelled(true);
             e.getPlayer().sendMessage("§cThis land belongs to another clan!");
         }
@@ -81,7 +78,7 @@ public class ClaimListener implements Listener {
     @EventHandler
     public void onIgnition(BlockIgniteEvent e){
         if(e.getPlayer() == null) return;
-        if(preventChange(e.getPlayer().getUniqueId(), e.getBlock().getLocation(), ClanSetting.INTERACT_IGNITION)){
+        if(preventChange(e.getPlayer().getUniqueId(), e.getBlock().getLocation(), ClaimSetting.INTERACT_IGNITION)){
             e.setCancelled(true);
             e.getPlayer().sendMessage("§cThis land belongs to another clan!");
         }
@@ -89,17 +86,17 @@ public class ClaimListener implements Listener {
     @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)){
+        if(e.getEntity() instanceof Player && preventForAll(e.getEntity().getLocation(), ClaimSetting.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 LivingEntity && preventForAll(e.getEntity().getLocation(), ClanSetting.ALLOW_HITTING_MOBS)){
+        }else if(e.getEntity() instanceof LivingEntity && preventForAll(e.getEntity().getLocation(), ClaimSetting.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)){
+        if(preventChange(e.getPlayer().getUniqueId(), e.getRightClicked().getLocation(), ClaimSetting.INTERACT_ENTITY)){
             e.setCancelled(true);
             e.getPlayer().sendMessage("§cThis land belongs to another clan!");
         }
@@ -107,27 +104,45 @@ public class ClaimListener implements Listener {
 
     @EventHandler
     public void onBlockPlace(BlockPlaceEvent e){
-        if(preventChange(e.getPlayer().getUniqueId(), e.getBlock().getLocation(), ClanSetting.BLOCK_PLACE)){
+        if(preventChange(e.getPlayer().getUniqueId(), e.getBlock().getLocation(), ClaimSetting.BLOCK_PLACE)){
             e.setCancelled(true);
             e.getPlayer().sendMessage("§cThis land belongs to another clan!");
         }
     }
-    private boolean preventForAll(Location location, ClanSetting setting){
+    @EventHandler
+    public void onEntityExplode(EntityExplodeEvent e){
+        if(preventGeneral(e.getLocation(), ClaimSetting.EXPLOSIONS)){
+            e.setCancelled(true);
+        }
+    }
+    @EventHandler
+    public void onExplosion(BlockExplodeEvent e){
+        if(preventGeneral(e.getBlock().getLocation(), ClaimSetting.EXPLOSIONS)){
+            e.setCancelled(true);
+        }
+    }
+
+    private boolean preventGeneral(@NotNull Location location, ClaimSetting claimSetting) {
         Claim claim = claimManager.getClaimAt(location);
         if(claim != null){
-            Clan clan = FluxService.get(ClanManager.class).getClanById(claim.getClanId());
-            if (clan != null) {
-                return !clan.allows(setting);
-            }
+            return !claim.allows(claimSetting);
+        }
+        return false;
+    }
+
+    private boolean preventForAll(Location location, ClaimSetting setting){
+        Claim claim = claimManager.getClaimAt(location);
+        if(claim != null){
+            return !claim.allows(setting);
         }
         return false;
     }
-    private boolean preventChange(UUID playerUUID, Location location, ClanSetting setting){
+    private boolean preventChange(UUID playerUUID, Location location, ClaimSetting setting){
         Claim claim = claimManager.getClaimAt(location);
         if(claim != null){
             Clan clan = FluxService.get(ClanManager.class).getClanById(claim.getClanId());
             if (clan != null && !clan.isInClan(playerUUID)) {
-                return !clan.allows(setting);
+                return !claim.allows(setting);
             }
         }
         return false;

+ 3 - 2
src/main/java/me/lethunderhawk/clans/claim/ClaimManager.java

@@ -1,15 +1,16 @@
 package me.lethunderhawk.clans.claim;
 
-import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.clans.Clan;
 import me.lethunderhawk.clans.ClanManager;
+import me.lethunderhawk.clans.settings.ClaimSettings;
+import me.lethunderhawk.fluxapi.FluxService;
 import org.bukkit.Location;
 import org.bukkit.entity.Player;
 
 import java.util.*;
 
 public final class ClaimManager {
-
+    private final ClaimSettings basicClanSettings = new ClaimSettings();
     // All claims (authoritative list)
     private final List<Claim> allClaims = new ArrayList<>();
 

+ 2 - 0
src/main/java/me/lethunderhawk/clans/command/ClanCommand.java

@@ -48,6 +48,8 @@ public class ClanCommand extends CustomCommand {
         claimNode.registerSubCommand("info", "Get information about your claims", this::infoClaims);
         claimNode.registerSubCommand("removeAll", "Remove all current claims", this::removeAllClaims);
         claimNode.registerSubCommand("tool", "Get the claimTool", this::getClaimTool);
+
+
         CommandNode acceptNode = registerCommand("acceptRequest", "Accept a pending request of a player", this::handleAcceptRequest);
         acceptNode.setTabCompleter(this::completeRequests);
 

+ 89 - 0
src/main/java/me/lethunderhawk/clans/gui/ClaimListGUI.java

@@ -0,0 +1,89 @@
+package me.lethunderhawk.clans.gui;
+
+import me.lethunderhawk.clans.Clan;
+import me.lethunderhawk.clans.claim.Claim;
+import me.lethunderhawk.clans.claim.ClaimManager;
+import me.lethunderhawk.fluxapi.FluxService;
+import me.lethunderhawk.fluxapi.util.UnItalic;
+import me.lethunderhawk.fluxapi.util.gui.ConfirmationMenu;
+import me.lethunderhawk.fluxapi.util.gui.InventoryGUI;
+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;
+
+public class ClaimListGUI extends InventoryGUI {
+
+    private final Player player;
+    private final Clan clan;
+
+    public ClaimListGUI(Player player, Clan clan) {
+        super("Claim List", 36);
+        this.player = player;
+        this.clan = clan;
+    }
+
+    private void buildItems() {
+        final int[] slot = {0};
+        clan.getClaims().forEach(claim -> {
+            setItemWithClickAction(slot[0], buildItemFromClaim(claim), (p, type)->{
+                if(type == ClickType.RIGHT || type == ClickType.SHIFT_RIGHT){
+                    editClaim(claim);
+                }else if(type == ClickType.LEFT || type == ClickType.SHIFT_LEFT){
+                    showRemoveClaimDialog(claim, p);
+                }
+            });
+            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) {
+        FluxService.get(ClaimManager.class).removeClaim(claim);
+    }
+
+    private void editClaim(Claim claim) {
+        ClaimSettingsGUI gui = new ClaimSettingsGUI(player, claim);
+        openNext(player, gui);
+    }
+
+    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 remove", NamedTextColor.YELLOW),
+                Component.text("Right click to edit", NamedTextColor.YELLOW)
+        ));
+        item.setItemMeta(UnItalic.removeItalicFromMeta(meta));
+        return item;
+    }
+
+    @Override
+    public void buildContent() {
+        fillGlassPaneBackground();
+        setBackButton(30);
+        setCloseButton(31);
+        buildItems();
+    }
+
+    @Override
+    public void update() {
+        buildContent();
+    }
+}

+ 98 - 45
src/main/java/me/lethunderhawk/clans/gui/ClaimSettingsGUI.java

@@ -1,66 +1,132 @@
 package me.lethunderhawk.clans.gui;
 
-import me.lethunderhawk.clans.Clan;
 import me.lethunderhawk.clans.claim.Claim;
-import me.lethunderhawk.clans.claim.ClaimManager;
+import me.lethunderhawk.clans.settings.ClaimSetting;
 import me.lethunderhawk.fluxapi.FluxService;
-import me.lethunderhawk.fluxapi.util.gui.ConfirmationMenu;
+import me.lethunderhawk.fluxapi.util.UnItalic;
 import me.lethunderhawk.fluxapi.util.gui.InventoryGUI;
 import me.lethunderhawk.fluxapi.util.gui.input.SignMenuFactory;
+import me.lethunderhawk.fluxapi.util.itemdesign.ItemOptions;
+import me.lethunderhawk.fluxapi.util.itemdesign.LoreDesigner;
 import me.lethunderhawk.main.BazaarFlux;
-import me.lethunderhawk.fluxapi.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.ItemFlag;
 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;
+    private final Claim claim;
 
-    public ClaimSettingsGUI(Player player, Clan clan) {
+    public ClaimSettingsGUI(Player player, Claim claim) {
         super("Claim Settings", 36);
         this.player = player;
-        this.clan = clan;
+        this.claim = claim;
     }
 
     private void buildItems() {
-        final int[] slot = {0};
-        clan.getClaims().forEach(claim -> {
-            setItemWithClickAction(slot[0], buildItemFromClaim(claim), (p, type)->{
-                if(type == ClickType.RIGHT || type == ClickType.SHIFT_RIGHT){
-                    renameClaim(claim);
-                    update();
-                }else if(type == ClickType.LEFT || type == ClickType.SHIFT_LEFT){
-                    showRemoveClaimDialog(claim, p);
-                }
+        AtomicInteger slot = new AtomicInteger(0);
+        claim.getSettings().asMap().forEach((setting, value) -> {
+            setItemWithClickAction(slot.get(), buildDecorationItem(setting, value), (p, type) ->{
+                toggleAndUpdate(p, setting);
             });
-            slot[0]++;
+            slot.getAndIncrement();
         });
     }
 
-    private void showRemoveClaimDialog(Claim claim, Player p) {
-        ConfirmationMenu confirmationMenu = new ConfirmationMenu("Delete Claim?", (pl) ->{
-            removeClaim(claim);
-        });
-        openNext(p, confirmationMenu);
+    private void toggleAndUpdate(Player p, ClaimSetting setting) {
+        claim.getSettings().toggleSetting(setting);
+        update();
+    }
+
+    private ItemStack buildDecorationItem(ClaimSetting setting, boolean enabled) {
+        String state = "<br><br>Current state: " + (enabled ? "<green>ENABLED" : "<red>DISABLED");
+        switch (setting){
+            case ClaimSetting.BLOCK_BREAK -> {
+                return buildItemFromParams(Material.DIAMOND_PICKAXE, Component.text("Breaking blocks"),
+                        LoreDesigner.createLore("<br>Enable / Disable the ability of other Players not in your clan to break all kinds of blocks!"
+                                + state));
+            }
+            case ClaimSetting.EXPLOSIONS -> {
+                return buildItemFromParams(Material.TNT, Component.text("Explosions"),
+                        LoreDesigner.createLore("<br>Enable / Disable the usage of Explosives to damage your builds inside this claim! <br>This applies to any explosions like creepers, tnt and tnt minecarts!"
+                                + state));
+            }
+            case ClaimSetting.BLOCK_PLACE -> {
+                return buildItemFromParams(Material.OAK_PLANKS, Component.text("Placing Blocks"),
+                        LoreDesigner.createLore("<br>Enable / Disable the ability of other Players not in your clan to place blocks inside your territory!"
+                                + state));
+            }
+            case ClaimSetting.INTERACT_IGNITION -> {
+                return buildItemFromParams(Material.FLINT_AND_STEEL, Component.text("Igniting blocks"),
+                        LoreDesigner.createLore("<br>Allow or prevent outsiders from using flint and steel to ignite blocks within your clan land! <br><red>WARNING: This doesn't prevent others from igniting TNT!"
+                                + state));
+            }
+            case ClaimSetting.INTERACT_BLOCK -> {
+                return buildItemFromParams(Material.LEVER, Component.text("Interacting with blocks"),
+                        LoreDesigner.createLore("<br>Controls whether non-clan players can interact with mechanisms like buttons, levers, and doors!"
+                                + state));
+            }
+            case ClaimSetting.INTERACT_ENTITY -> {
+                return buildItemFromParams(Material.VILLAGER_SPAWN_EGG, Component.text("Interacting with entities"),
+                        LoreDesigner.createLore("<br>Determines if outsiders may right-click or otherwise interact with animals and NPC entities!"
+                                + state));
+            }
+            case ClaimSetting.OPEN_CONTAINER -> {
+                return buildItemFromParams(Material.CHEST, Component.text("Opening Containers"),
+                        LoreDesigner.createLore("<br>Determines if outsiders are allowed to open Containers like chests, barrels, shulkers!"
+                                + state));
+            }
+            case ClaimSetting.USE_ANVIL -> {
+                return buildItemFromParams(Material.ANVIL, Component.text("Using Anvils"),
+                        LoreDesigner.createLore("<br>Control if outsiders can use anvils inside your territory to repair or rename items!"
+                                + state));
+            }
+            case ClaimSetting.ALLOW_HITTING_MOBS -> {
+                return buildItemFromParams(Material.ZOMBIE_HEAD, Component.text("Hitting mobs"),
+                        LoreDesigner.createLore("<br>Determines whether players inside your claims may attack hostile or passive mobs in your land!"
+                                + state));
+            }
+            case ClaimSetting.ALLOW_HITTING_PLAYERS -> {
+                return buildItemFromParams(Material.PLAYER_HEAD, Component.text("PvP"),
+                        LoreDesigner.createLore("<br>Toggle whether players can hurt each other physically inside this claim (PvP)"
+                                + state));
+            }
+            default -> {
+                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;
     }
 
-    private void removeClaim(Claim claim) {
-        FluxService.get(ClaimManager.class).removeClaim(claim);
+    private void setRenameButton() {
+        setItemWithClickAction(35, new ItemOptions(Material.OAK_SIGN)
+                .setName(Component.text("Rename Claim", NamedTextColor.YELLOW))
+                .setLore(LoreDesigner.createLore("<dark_gray>Click to rename this claim into anything your heart desires!"))
+                .buildItemStack(), this::showRename);
     }
 
-    private void renameClaim(Claim claim) {
+    private void showRename(Player player, ClickType type) {
         SignMenuFactory.Menu menu = new SignMenuFactory(FluxService.get(BazaarFlux.class)).newMenu(List.of("", "^^^^^^^^^^^^", "Enter the new", "name of the claim"))
                 .reopenIfFail(true)
                 .response((p, strings) -> {
-                    rename(strings[0], claim);
+                    rename(strings[0]);
                     update();
                     open(p);
                     return true;
@@ -68,36 +134,23 @@ public class ClaimSettingsGUI extends InventoryGUI {
         menu.open(player);
     }
 
-    private void rename(String input, Claim claim) {
+    private void rename(String input) {
         claim.setName(input);
     }
 
-    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 remove", NamedTextColor.YELLOW),
-                Component.text("Right click to rename", NamedTextColor.YELLOW)
-        ));
-        item.setItemMeta(UnItalic.removeItalicFromMeta(meta));
-        return item;
-    }
-
     @Override
     public void buildContent() {
         fillGlassPaneBackground();
         setBackButton(30);
         setCloseButton(31);
+        setRenameButton();
         buildItems();
     }
 
+
+
     @Override
     public void update() {
-        buildContent();
+        buildItems();
     }
 }

+ 19 - 5
src/main/java/me/lethunderhawk/clans/gui/ClanMenu.java

@@ -1,8 +1,11 @@
 package me.lethunderhawk.clans.gui;
 
 import me.lethunderhawk.clans.Clan;
+import me.lethunderhawk.clans.ClanManager;
+import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.gui.InventoryGUI;
 import me.lethunderhawk.fluxapi.util.UnItalic;
+import me.lethunderhawk.fluxapi.util.gui.PlayerHeadListGUI;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.format.NamedTextColor;
 import org.bukkit.Material;
@@ -28,7 +31,7 @@ public class ClanMenu extends InventoryGUI {
     private void buildClaimList() {
         ItemStack claimList = buildClaimListItem();
         setItemWithClickAction(15, claimList, (p, click) -> {
-            openNext(p, new ClaimSettingsGUI(player, clan));
+            openNext(p, new ClaimListGUI(player, clan));
         });
     }
 
@@ -47,10 +50,21 @@ public class ClanMenu extends InventoryGUI {
     private void buildMemberList() {
         ItemStack memberList = buildMemberListIem();
         setItemWithClickAction(13, memberList, (p, click) -> {
-            openNext(p, new MemberListGUI(player));
+            PlayerHeadListGUI playerList = new PlayerHeadListGUI("Members", 36, FluxService.get(ClanManager.class).getMyClan(p.getUniqueId()).getAllMembers(), this::handleClanMemberClick);
+            playerList.setBackButton(30);
+            playerList.setCloseButton(31);
+            openNext(p, playerList);
         });
     }
 
+    private void handleClanMemberClick(Player player, Player target) {
+        ClanManager manager = FluxService.get(ClanManager.class);
+
+        //if(!manager.getMyClan(player.getUniqueId()).getOwnerUUID().equals(player.getUniqueId())) return;
+        //if(player.getUniqueId().equals(target.getUniqueId())) return;
+        manager.leaveClan(target.getUniqueId());
+    }
+
     private ItemStack buildMemberListIem() {
         ItemStack memberListItem = new ItemStack(Material.PLAYER_HEAD);
         ItemMeta meta = memberListItem.getItemMeta();
@@ -65,9 +79,9 @@ public class ClanMenu extends InventoryGUI {
 
     private void buildSettings() {
         ItemStack settings = buildSettingsItem();
-        setItemWithClickAction(11, settings, (p, click) -> {
-            openNext(p, new ClanSettingsGUI(player, clan.getSettings()));
-        });
+        /*setItemWithClickAction(11, settings, (p, click) -> {
+            openNext(p, new ClaimSettingsToggleGUI(player, clan.getSettings()));
+        });*/
     }
 
     private ItemStack buildSettingsItem() {

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

@@ -1,180 +0,0 @@
-package me.lethunderhawk.clans.gui;
-
-import me.lethunderhawk.fluxapi.util.gui.InventoryGUI;
-import me.lethunderhawk.clans.settings.ClanSetting;
-import me.lethunderhawk.clans.settings.ClanSettings;
-import me.lethunderhawk.fluxapi.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 {
-    private final Player player;
-    private final ClanSettings settings;
-
-    public ClanSettingsGUI(Player player, ClanSettings settings) {
-        super("Clan Settings", 36);
-        this.player = player;
-        this.settings = settings;
-    }
-
-    private void buildItems() {
-        AtomicInteger slot = new AtomicInteger(9);
-        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(
-                    value ? Component.text("Enabled", NamedTextColor.GREEN) : Component.text("Disabled", NamedTextColor.RED)
-            );
-            settingsItem.setItemMeta(UnItalic.removeItalicFromMeta(meta));
-
-            setItemWithClickAction(slot.get() -9, buildDecorationItem(setting), (p, type) ->{
-                toggleAndUpdate(p, setting);
-            });
-            setItemWithClickAction(slot.get(), settingsItem, (p, type) ->{
-                toggleAndUpdate(p, setting);
-            });
-
-            slot.getAndIncrement();
-        });
-    }
-
-    private void toggleAndUpdate(Player p, ClanSetting setting) {
-        settings.toggleSetting(setting);
-        update();
-    }
-
-    private ItemStack buildDecorationItem(ClanSetting setting) {
-        switch (setting){
-            case ClanSetting.BLOCK_BREAK -> {
-                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 -> {
-                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 -> {
-                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 -> {
-                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 -> {
-                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 -> {
-                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 -> {
-                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 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 buildContent() {
-        fillGlassPaneBackground();
-        setBackButton(30);
-        setCloseButton(31);
-        buildItems();
-    }
-
-    @Override
-    public void update() {
-        buildItems();
-    }
-}

+ 1 - 2
src/main/java/me/lethunderhawk/clans/gui/MemberListGUI.java

@@ -7,7 +7,7 @@ public class MemberListGUI extends InventoryGUI {
     private final Player player;
 
     public MemberListGUI(Player player) {
-        super("Member List", 36);
+        super("Members", 36);
         this.player = player;
     }
 
@@ -18,7 +18,6 @@ public class MemberListGUI extends InventoryGUI {
         setCloseButton(31);
     }
 
-    @Override
     public void update() {
         
     }

+ 4 - 4
src/main/java/me/lethunderhawk/clans/settings/ClanSetting.java → src/main/java/me/lethunderhawk/clans/settings/ClaimSetting.java

@@ -1,7 +1,6 @@
 package me.lethunderhawk.clans.settings;
 
-public enum ClanSetting {
-
+public enum ClaimSetting {
     BLOCK_BREAK,
     BLOCK_PLACE,
 
@@ -11,5 +10,6 @@ public enum ClanSetting {
     ALLOW_HITTING_PLAYERS,
     ALLOW_HITTING_MOBS,
     INTERACT_IGNITION,
-    USE_ANVIL;
-}
+    USE_ANVIL,
+    EXPLOSIONS;
+}

+ 15 - 13
src/main/java/me/lethunderhawk/clans/settings/ClanSettings.java → src/main/java/me/lethunderhawk/clans/settings/ClaimSettings.java

@@ -7,42 +7,44 @@ import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.Map;
 
-public final class ClanSettings {
+public class ClaimSettings {
     private final boolean enableAllByDefault = false;
-    private final EnumMap<ClanSetting, Boolean> settings = new EnumMap<>(ClanSetting.class);
+    private final EnumMap<ClaimSetting, Boolean> settings = new EnumMap<>(ClaimSetting.class);
 
-    public ClanSettings() {
-        for (ClanSetting setting : ClanSetting.values()) {
+    public ClaimSettings() {
+        for (ClaimSetting setting : ClaimSetting.values()) {
             settings.put(setting, enableAllByDefault);
         }
     }
-    public void toggleSetting(ClanSetting setting){
+    public void toggleSetting(ClaimSetting setting){
         settings.put(setting, !settings.get(setting));
     }
-    public boolean isAllowed(ClanSetting setting) {
+    public boolean isAllowed(ClaimSetting setting) {
         return settings.getOrDefault(setting, enableAllByDefault);
     }
 
-    public void set(ClanSetting setting, boolean value) {
+    public void set(ClaimSetting setting, boolean value) {
         settings.put(setting, value);
     }
 
-    public Map<ClanSetting, Boolean> asMap() {
+    public Map<ClaimSetting, Boolean> asMap() {
         return settings;
     }
+
     public Map<String, Object> toStringMap() {
         Map<String, Object> map = new HashMap<>();
-        for (Map.Entry<ClanSetting, Boolean> entry : settings.entrySet()) {
+        for (Map.Entry<ClaimSetting, 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();
+
+    public static ClaimSettings fromMap(Map<String, Object> map) {
+        ClaimSettings s = new ClaimSettings();
 
         for (Map.Entry<String, Object> entry : map.entrySet()) {
             try {
-                ClanSetting key = ClanSetting.valueOf(entry.getKey());
+                ClaimSetting key = ClaimSetting.valueOf(entry.getKey());
                 s.set(key, (Boolean) entry.getValue());
             } catch (IllegalArgumentException e) {
                 FluxService.get(BazaarFlux.class).getLogger().warning("Unknown ClanSetting: " + entry.getKey());
@@ -50,4 +52,4 @@ public final class ClanSettings {
         }
         return s;
     }
-}
+}

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

@@ -12,7 +12,9 @@ import me.lethunderhawk.custom.item.command.CustomItemCommand;
 import me.lethunderhawk.custom.item.concrete.ability.*;
 import me.lethunderhawk.custom.item.listener.CustomItemListener;
 import me.lethunderhawk.fluxapi.FluxService;
+import me.lethunderhawk.fluxapi.main.FluxAPI;
 import me.lethunderhawk.fluxapi.util.interfaces.FluxAPIModule;
+import me.lethunderhawk.fluxapi.util.itemdesign.ItemData;
 import me.lethunderhawk.main.BazaarFlux;
 import org.bukkit.command.CommandSender;
 import org.bukkit.event.HandlerList;
@@ -36,6 +38,7 @@ public class CustomItemModule extends FluxAPIModule {
         abilityRegistry.register("hyperion", new HyperionAbility());
         abilityRegistry.register("regenerating_block", new RegeneratingBlockAbility());
         abilityRegistry.register("sack", new SackAbility());
+        abilityRegistry.register("snowball", new SnowBallShooterAbility());
     }
 
     @Override
@@ -48,6 +51,8 @@ public class CustomItemModule extends FluxAPIModule {
         AbilityRegistry abilityRegistry = new AbilityRegistry();
         registerAbilities(abilityRegistry);
 
+        ItemData.init(FluxService.get(FluxAPI.class));
+
         ItemDefinitionValidator validator = new DefaultItemDefinitionValidator();
         ItemDefinitionLoader loader = new ItemDefinitionLoader(validator);
 

+ 2 - 0
src/main/java/me/lethunderhawk/custom/item/abstraction/ability/AbilityContext.java

@@ -3,10 +3,12 @@ package me.lethunderhawk.custom.item.abstraction.ability;
 import me.lethunderhawk.custom.item.abstraction.instance.ItemInstance;
 import org.bukkit.entity.Player;
 import org.bukkit.event.Event;
+import org.bukkit.inventory.ItemStack;
 
 public record AbilityContext(
         Player player,
         ItemInstance itemInstance,
+        ItemStack itemStack,
         Event event,
         AbilityTrigger trigger
 ) {}

+ 3 - 4
src/main/java/me/lethunderhawk/custom/item/abstraction/ability/AbilityDefinition.java

@@ -8,18 +8,17 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 public class AbilityDefinition implements Serializable {
 
-    private final Set<AbilityTrigger> triggers;
+    private final List<AbilityTrigger> triggers;
     private final String handlerId;
     private final Map<String, String> params;
     private final String name;
     private final String description;
 
     public AbilityDefinition(
-            Set<AbilityTrigger> triggers,
+            List<AbilityTrigger> triggers,
             String handlerId,
             String name,
             String description,
@@ -77,7 +76,7 @@ public class AbilityDefinition implements Serializable {
 
     public List<Component> renderLore() {
         List<Component> lore = new ArrayList<>();
-        String abilityName = "Ability: " + getName() + " [" + ((AbilityTrigger) triggers.toArray()[0]).getDisplayName() + "]";
+        String abilityName = "Ability: " + getName() + " [" + (triggers.getFirst()).getDisplayName() + "]";
         lore.add(Component.text(abilityName, NamedTextColor.GOLD));
         lore.addAll(getLore(abilityName));
 

+ 1 - 1
src/main/java/me/lethunderhawk/custom/item/abstraction/definition/ItemDefinitionLoader.java

@@ -127,7 +127,7 @@ public final class ItemDefinitionLoader {
                     );
                 }
 
-                Set<AbilityTrigger> triggers = new HashSet<>();
+                List<AbilityTrigger> triggers = new ArrayList<>();
                 List<String> triggerList = abilityCfg.getStringList("triggers");
 
                 if (!triggerList.isEmpty()) {

+ 1 - 1
src/main/java/me/lethunderhawk/custom/item/abstraction/runtime/AbilityDispatchService.java

@@ -54,7 +54,7 @@ public final class AbilityDispatchService {
 
                 AbilityHandler handler = abilityRegistry.get(ability.handlerId());
                 handler.execute(
-                        new AbilityContext(player, instance, event, trigger),
+                        new AbilityContext(player, instance, stack, event, trigger),
                         ResolvedParams.resolve(ability, def, instance)
                 );
 

+ 1 - 1
src/main/java/me/lethunderhawk/custom/item/concrete/ability/RollingDiceAbility.java

@@ -42,7 +42,7 @@ public class RollingDiceAbility implements AbilityHandler {
         EconomyAPI economy = FluxService.get(EconomyAPI.class);
         UUID uuid = player.getUniqueId();
 
-        long balance = economy.getMoney(uuid);
+        double balance = economy.getMoney(uuid);
         if (balance < abilityCost) return false;
 
         economy.removeMoney(uuid, abilityCost);

+ 6 - 5
src/main/java/me/lethunderhawk/custom/item/concrete/ability/SackAbility.java

@@ -7,6 +7,7 @@ import me.lethunderhawk.custom.item.abstraction.handling.ResolvedParams;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.profile.ProfileManager;
 import me.lethunderhawk.profile.data.sacks.Sack;
+import me.lethunderhawk.profile.data.sacks.SackRegistry;
 import me.lethunderhawk.profile.data.sacks.SackType;
 import me.lethunderhawk.profile.data.sacks.gui.SackGUI;
 import org.bukkit.Sound;
@@ -45,18 +46,18 @@ public class SackAbility implements AbilityHandler {
             if(pickupEvent.isCancelled()) return;
             ItemStack stack = pickupEvent.getItem().getItemStack();
 
-            if (!Sack.getRegisteredTypes()
-                    .get(type)
-                    .containsKey(stack.getType())) {
-
+            if (!SackRegistry.getRegisteredType(type)
+                    .containsKey(stack.getType())
+                    || !sack.isAutoPickUpEnabled()) {
                 return;
             }
 
-            pickupEvent.setCancelled(true);
+
 
             int remaining = sack.addItemStack(stack);
             player.playSound(player.getLocation(), Sound.ITEM_BUNDLE_INSERT, 1f, 1f);
             if (remaining <= 0) {
+                pickupEvent.setCancelled(true);
                 pickupEvent.getItem().remove();
             } else {
                 stack.setAmount(remaining);

+ 35 - 0
src/main/java/me/lethunderhawk/custom/item/concrete/ability/SnowBallShooterAbility.java

@@ -0,0 +1,35 @@
+package me.lethunderhawk.custom.item.concrete.ability;
+
+import me.lethunderhawk.custom.item.abstraction.ability.AbilityContext;
+import me.lethunderhawk.custom.item.abstraction.handling.AbilityHandler;
+import me.lethunderhawk.custom.item.abstraction.handling.ResolvedParams;
+import me.lethunderhawk.fluxapi.util.itemdesign.ItemData;
+import org.bukkit.event.Cancellable;
+import org.bukkit.inventory.ItemStack;
+
+public class SnowBallShooterAbility implements AbilityHandler {
+
+    @Override
+    public void execute(AbilityContext context, ResolvedParams params) {
+        if(context.event() instanceof Cancellable cancellable){
+            cancellable.setCancelled(true);
+        }
+        ItemStack item = context.itemStack();
+
+        ItemData.setInt(item, "maxSnowballs", 100);
+
+        int snowballs = ItemData.getInt(item, "snowballs", 0);
+
+        if (snowballs <= 0) {
+            snowballs = 10;
+        } else {
+            snowballs--;
+        }
+
+        ItemData.setInt(item, "snowballs", snowballs);
+
+        System.out.println("Snowballs: " + ItemData.getInt(item, "snowballs", 0));
+
+        context.player().updateInventory();
+    }
+}

+ 5 - 1
src/main/java/me/lethunderhawk/custom/item/listener/CustomItemListener.java

@@ -1,5 +1,6 @@
 package me.lethunderhawk.custom.item.listener;
 
+import io.papermc.paper.event.player.PlayerPickBlockEvent;
 import me.lethunderhawk.custom.item.abstraction.ability.AbilityTrigger;
 import me.lethunderhawk.custom.item.abstraction.migration.MigrationService;
 import me.lethunderhawk.custom.item.abstraction.runtime.AbilityDispatchService;
@@ -38,7 +39,10 @@ public class CustomItemListener implements Listener {
             );
         }
     }
-
+    @EventHandler
+    public void onMiddleClick(PlayerPickBlockEvent event) {
+        //event.get
+    }
     @EventHandler
     public void onAction(PlayerInteractEvent event) {
         AbilityTrigger triggered = switch (event.getAction()) {

+ 0 - 40
src/main/java/me/lethunderhawk/custom/recipes/CustomRecipeModule.java

@@ -5,11 +5,8 @@ import me.lethunderhawk.custom.recipes.enchantedVariant.EnchantedVariantRecipeMa
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.config.ConfigLoader;
 import me.lethunderhawk.fluxapi.util.interfaces.FluxAPIModule;
-import org.bukkit.Material;
-import org.bukkit.NamespacedKey;
 import org.bukkit.configuration.serialization.ConfigurationSerialization;
 import org.bukkit.event.HandlerList;
-import org.bukkit.inventory.ItemStack;
 import org.bukkit.plugin.java.JavaPlugin;
 
 public class CustomRecipeModule extends FluxAPIModule {
@@ -35,9 +32,6 @@ public class CustomRecipeModule extends FluxAPIModule {
 
         recipeManager.loadRecipes(FluxService.get(ConfigLoader.class));
 
-        //addTestRecipes();
-        //registerEnchantedVariantCrafts();
-
         plugin.getServer().getPluginManager().registerEvents(recipeManager, plugin);
 
         RecipeEditorCommand command = new RecipeEditorCommand(this);
@@ -45,40 +39,6 @@ public class CustomRecipeModule extends FluxAPIModule {
         plugin.getCommand("customrecipe").setExecutor(command);
     }
 
-    private void registerEnchantedVariantCrafts() {
-        ItemStack[] matrix = new ItemStack[9];
-        ItemStack baseMaterial = new ItemStack(Material.COBBLESTONE);
-        baseMaterial.setAmount(32);
-        matrix[0] = baseMaterial;
-        matrix[1] = baseMaterial;
-        matrix[2] = baseMaterial;
-        matrix[3] = baseMaterial;
-        matrix[4] = baseMaterial;
-
-        recipeManager.registerRecipe(
-                new CraftingTableRecipe(new NamespacedKey(plugin, "enchanted_cobblestone"),
-                        matrix, new ItemStack(Material.RED_CONCRETE))
-        );
-    }
-
-    private void addTestRecipes() {
-        ItemStack[] matrix = new ItemStack[9];
-        matrix[0] = new ItemStack(Material.WHITE_CONCRETE);
-        matrix[1] = new ItemStack(Material.WHITE_CONCRETE);
-        matrix[2] = new ItemStack(Material.WHITE_CONCRETE);
-        matrix[3] = new ItemStack(Material.WHITE_CONCRETE);
-        matrix[4] = new ItemStack(Material.WHITE_CONCRETE);
-        matrix[5] = new ItemStack(Material.WHITE_CONCRETE);
-        matrix[6] = new ItemStack(Material.WHITE_CONCRETE);
-        matrix[7] = new ItemStack(Material.WHITE_CONCRETE);
-        matrix[8] = new ItemStack(Material.WHITE_CONCRETE);
-
-        recipeManager.registerRecipe(
-                new CraftingTableRecipe(new NamespacedKey(plugin, "test_recipe"),
-                        matrix, new ItemStack(Material.GREEN_CONCRETE))
-        );
-    }
-
     @Override
     public void onDisable() {
 

+ 15 - 15
src/main/java/me/lethunderhawk/custom/recipes/enchantedVariant/recipe/EnchantedItemRecipe.java

@@ -34,11 +34,11 @@ public class EnchantedItemRecipe implements Recipe {
 
     private void setupIngredients() {
         // Set up the first 5 slots with full stack requirement
-        ingredients.put('A', new StackSizeIngredient(ingredient, 64));
-        ingredients.put('B', new StackSizeIngredient(ingredient, 64));
-        ingredients.put('C', new StackSizeIngredient(ingredient, 64));
-        ingredients.put('D', new StackSizeIngredient(ingredient, 64));
-        ingredients.put('E', new StackSizeIngredient(ingredient, 64));
+        ingredients.put('A', new StackSizeIngredient(ingredient, 64).getChoice());
+        ingredients.put('B', new StackSizeIngredient(ingredient, 64).getChoice());
+        ingredients.put('C', new StackSizeIngredient(ingredient, 64).getChoice());
+        ingredients.put('D', new StackSizeIngredient(ingredient, 64).getChoice());
+        ingredients.put('E', new StackSizeIngredient(ingredient, 64).getChoice());
 
         // Empty slots (space character)
         //ingredients.put(' ', new RecipeChoice.MaterialChoice(Material.AIR));
@@ -128,11 +128,11 @@ public class EnchantedItemRecipe implements Recipe {
                 "   ");
 
         // Full stack requirements (64)
-        fullRecipe.setIngredient('A', new StackSizeIngredient(ingredient, 64));
-        fullRecipe.setIngredient('B', new StackSizeIngredient(ingredient, 64));
-        fullRecipe.setIngredient('C', new StackSizeIngredient(ingredient, 64));
-        fullRecipe.setIngredient('D', new StackSizeIngredient(ingredient, 64));
-        fullRecipe.setIngredient('E', new StackSizeIngredient(ingredient, 64));
+        fullRecipe.setIngredient('A', new StackSizeIngredient(ingredient, 64).getChoice());
+        fullRecipe.setIngredient('B', new StackSizeIngredient(ingredient, 64).getChoice());
+        fullRecipe.setIngredient('C', new StackSizeIngredient(ingredient, 64).getChoice());
+        fullRecipe.setIngredient('D', new StackSizeIngredient(ingredient, 64).getChoice());
+        fullRecipe.setIngredient('E', new StackSizeIngredient(ingredient, 64).getChoice());
 
         Bukkit.addRecipe(fullRecipe);
     }
@@ -148,11 +148,11 @@ public class EnchantedItemRecipe implements Recipe {
         halfRecipe.shape("ABC", "DE ", "   ");
 
         // Half stack requirements (32)
-        halfRecipe.setIngredient('A', new StackSizeIngredient(ingredient, 32));
-        halfRecipe.setIngredient('B', new StackSizeIngredient(ingredient, 32));
-        halfRecipe.setIngredient('C', new StackSizeIngredient(ingredient, 32));
-        halfRecipe.setIngredient('D', new StackSizeIngredient(ingredient, 32));
-        halfRecipe.setIngredient('E', new StackSizeIngredient(ingredient, 32));
+        halfRecipe.setIngredient('A', new StackSizeIngredient(ingredient, 32).getChoice());
+        halfRecipe.setIngredient('B', new StackSizeIngredient(ingredient, 32).getChoice());
+        halfRecipe.setIngredient('C', new StackSizeIngredient(ingredient, 32).getChoice());
+        halfRecipe.setIngredient('D', new StackSizeIngredient(ingredient, 32).getChoice());
+        halfRecipe.setIngredient('E', new StackSizeIngredient(ingredient, 32).getChoice());
 
         Bukkit.addRecipe(halfRecipe);
     }

+ 13 - 13
src/main/java/me/lethunderhawk/custom/recipes/enchantedVariant/recipe/StackSizeIngredient.java

@@ -4,34 +4,34 @@ import org.bukkit.Material;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.RecipeChoice;
 
-public class StackSizeIngredient extends RecipeChoice.MaterialChoice {
-    private final int requiredAmount;
+public class StackSizeIngredient {
+
     private final Material material;
+    private final int requiredAmount;
+    private final RecipeChoice choice;
 
     public StackSizeIngredient(Material material, int requiredAmount) {
-        super(material);
         this.material = material;
         this.requiredAmount = requiredAmount;
+
+        this.choice = new RecipeChoice.MaterialChoice(material);
     }
 
-    @Override
     public boolean test(ItemStack item) {
-        return super.test(item) && item.getAmount() >= requiredAmount;
+        return choice.test(item) && item.getAmount() >= requiredAmount;
     }
 
-    @Override
-    public ItemStack getItemStack() {
-        ItemStack item = super.getItemStack();
-        item.setAmount(requiredAmount);
-        return item;
+    public RecipeChoice getChoice() {
+        return choice;
     }
 
     public int getRequiredAmount() {
         return requiredAmount;
     }
 
-    @Override
-    public StackSizeIngredient clone() {
-        return new StackSizeIngredient(material, requiredAmount);
+    public ItemStack getDisplayStack() {
+        ItemStack stack = new ItemStack(material);
+        stack.setAmount(requiredAmount);
+        return stack;
     }
 }

+ 20 - 8
src/main/java/me/lethunderhawk/economy/EconomyModule.java

@@ -5,19 +5,24 @@ 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.scoreboard.ScoreboardManager;
+import me.lethunderhawk.economy.shop.ItemValues;
 import me.lethunderhawk.fluxapi.FluxService;
+import me.lethunderhawk.fluxapi.util.config.ConfigLoader;
 import me.lethunderhawk.fluxapi.util.interfaces.FluxAPIModule;
+import me.lethunderhawk.scoreboard.ScoreboardManager;
 import me.lethunderhawk.tradeplugin.api.TradePlaceholder;
+import org.bukkit.configuration.serialization.ConfigurationSerialization;
 import org.bukkit.plugin.java.JavaPlugin;
 
 public class EconomyModule extends FluxAPIModule {
 
     private EconomyAPI economyAPI;
+    private EconomyManager economyManager;
     private ScoreboardManager scoreboardManager;
-
+    private final ConfigLoader loader;
     public EconomyModule(JavaPlugin plugin) {
         super(plugin);
+        this.loader = new ConfigLoader(plugin);
     }
 
     @Override
@@ -26,14 +31,24 @@ public class EconomyModule extends FluxAPIModule {
     }
 
     public void onEnable() {
-
+        ConfigurationSerialization.registerClass(ItemValues.class, "ItemValues");
         plugin.saveDefaultConfig();
         plugin.saveResource("scoreboards/default.yml", false);
 
-        EconomyManager economyManager = new EconomyManager();
+        economyManager = new EconomyManager();
 
         economyAPI = new EconomyAPI(economyManager);
         FluxService.register(EconomyAPI.class, economyAPI);
+        loader.getFile("economy/itemValues");
+
+
+        ItemValues values = loader.loadObject("economy/itemValues", "Item_values", ItemValues.class);
+        if(values == null) {
+            values = new ItemValues();
+            System.out.println("Why null??");
+        }
+        economyManager.setItemValues(values);
+
         scoreboardManager = new ScoreboardManager(this);
 
         plugin.getCommand("eco").setExecutor(new EcoCommand(this));
@@ -49,10 +64,7 @@ public class EconomyModule extends FluxAPIModule {
 
     @Override
     public void onDisable() {
-
-    }
-    public void reload(){
-        scoreboardManager.reload();
+        loader.saveObject("economy/itemValues", "Item_values", economyManager.getItemValues());
     }
 
     public EconomyAPI getEconomyAPI() {

+ 8 - 5
src/main/java/me/lethunderhawk/economy/api/EconomyAPI.java

@@ -13,23 +13,23 @@ public class EconomyAPI {
         this.eco = eco;
     }
 
-    public void pay(UUID sender, UUID receiver, long amount){
+    public void pay(UUID sender, UUID receiver, double amount){
         eco.pay(sender, receiver, amount);
     }
 
-    public long getMoney(UUID uuid) {
+    public double getMoney(UUID uuid) {
         return eco.getMoney(uuid);
     }
 
-    public void setMoney(UUID uuid, long amount) {
+    public void setMoney(UUID uuid, double amount) {
         eco.setMoney(uuid, amount);
     }
 
-    public void addMoney(UUID uuid, long amount) {
+    public void addMoney(UUID uuid, double amount) {
         eco.addMoney(uuid, amount);
     }
 
-    public void removeMoney(UUID uuid, long amount) {
+    public void removeMoney(UUID uuid, double amount) {
         eco.removeMoney(uuid, amount);
     }
 
@@ -37,4 +37,7 @@ public class EconomyAPI {
         return DayTime.formatMcTime(eco.getTime());
     }
 
+    public EconomyManager getManager() {
+        return eco;
+    }
 }

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

@@ -2,8 +2,10 @@ package me.lethunderhawk.economy.command;
 
 import me.lethunderhawk.economy.EconomyModule;
 import me.lethunderhawk.economy.api.EconomyAPI;
+import me.lethunderhawk.economy.shop.ShopGUI;
 import me.lethunderhawk.fluxapi.util.command.CommandNode;
 import me.lethunderhawk.fluxapi.util.command.CustomCommand;
+import me.lethunderhawk.fluxapi.util.gui.InventoryManager;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.format.NamedTextColor;
 import org.bukkit.Bukkit;
@@ -41,6 +43,13 @@ public class EcoCommand extends CustomCommand {
 
         CommandNode get = registerCommand("get", "Get the balance of a player", this::getBalance);
         get.setTabCompleter(this::completePlayers);
+
+        //CommandNode shop = registerCommand("shop", "Open the main Shop", this::openShop);
+    }
+
+    private void openShop(CommandSender sender, String[] strings) {
+        if(!(sender instanceof Player p)) return;
+        InventoryManager.openFor(p, new ShopGUI(p));
     }
 
     private List<String> completePlayers(CommandSender sender, String[] args){
@@ -89,7 +98,7 @@ public class EcoCommand extends CustomCommand {
         if (target == null) {
             module.sendText(commandSender, Component.text("Spieler nicht gefunden.",  NamedTextColor.RED));
         }else{
-            getAPI().addMoney(target.getUniqueId(), Long.parseLong(strings[1]));
+            getAPI().addMoney(target.getUniqueId(), Double.parseDouble(strings[1]));
         }
     }
 
@@ -99,7 +108,7 @@ public class EcoCommand extends CustomCommand {
         if (target == null) {
             module.sendText(commandSender, Component.text("Spieler nicht gefunden.",  NamedTextColor.RED));
         }else{
-            getAPI().setMoney(target.getUniqueId(), Long.parseLong(strings[1]));
+            getAPI().setMoney(target.getUniqueId(), Double.parseDouble(strings[1]));
         }
     }
     private EconomyAPI getAPI(){

+ 17 - 11
src/main/java/me/lethunderhawk/economy/currency/EconomyManager.java

@@ -1,5 +1,6 @@
 package me.lethunderhawk.economy.currency;
 
+import me.lethunderhawk.economy.shop.ItemValues;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.economy.EconomyModule;
 import org.bukkit.configuration.file.FileConfiguration;
@@ -10,22 +11,23 @@ public class EconomyManager {
 
     private final EconomyModule module;
     private final FileConfiguration config;
+    private ItemValues itemValues;
 
     public EconomyManager() {
         this.module = FluxService.get(EconomyModule.class);
         this.config = module.getPlugin().getConfig();
     }
 
-    public long getMoney(UUID uuid) {
-        return config.getLong("players." + uuid + ".money", 0);
+    public double getMoney(UUID uuid) {
+        return config.getDouble("players." + uuid + ".money", 0);
     }
 
-    public void setMoney(UUID uuid, long amount) {
+    public void setMoney(UUID uuid, double amount) {
         config.set("players." + uuid + ".money", amount);
         module.getPlugin().saveConfig();
     }
 
-    public void addMoney(UUID uuid, long amount) {
+    public void addMoney(UUID uuid, double amount) {
         /*Player player = Bukkit.getPlayer(uuid);
         if(player != null) {
             player.sendMessage("§c" +EconomyUtil.stringFromNumber(amount) + "§e has been transferred into your account!");
@@ -33,12 +35,12 @@ public class EconomyManager {
         setMoney(uuid, getMoney(uuid) + amount);
     }
 
-    public boolean removeMoney(UUID uuid, long amount) {
+    public boolean removeMoney(UUID uuid, double amount) {
         /*Player player = Bukkit.getPlayer(uuid);
         if(player != null) {
             player.sendMessage("§c" +EconomyUtil.stringFromNumber(amount) + "§e has been taken from your account!");
         }*/
-        long newAmount = getMoney(uuid) - amount;
+        double newAmount = getMoney(uuid) - amount;
         if(newAmount < 0){
             return false;
         }
@@ -50,14 +52,18 @@ public class EconomyManager {
         return module.getPlugin().getServer().getWorld("world").getTime();
     }
 
-    public String getRegion() {
-        return "Bummsbach";
-    }
-
-    public void pay(UUID sender, UUID receiver, long amount) {
+    public void pay(UUID sender, UUID receiver, double amount) {
         if(amount > 0 && getMoney(sender) >= amount){
             removeMoney(sender, amount);
             addMoney(receiver, amount);
         }
     }
+
+    public void setItemValues(ItemValues values) {
+        this.itemValues = values;
+    }
+
+    public ItemValues getItemValues() {
+        return itemValues;
+    }
 }

+ 133 - 0
src/main/java/me/lethunderhawk/economy/shop/BuyingItemsEditGUI.java

@@ -0,0 +1,133 @@
+package me.lethunderhawk.economy.shop;
+
+import me.lethunderhawk.economy.api.EconomyAPI;
+import me.lethunderhawk.economy.currency.EconomyManager;
+import me.lethunderhawk.fluxapi.FluxService;
+import me.lethunderhawk.fluxapi.util.gui.ConfirmationMenu;
+import me.lethunderhawk.fluxapi.util.gui.PaginatedInventoryGUI;
+import me.lethunderhawk.fluxapi.util.gui.input.SignMenuFactory;
+import me.lethunderhawk.fluxapi.util.itemdesign.ItemOptions;
+import me.lethunderhawk.fluxapi.util.itemdesign.LoreDesigner;
+import me.lethunderhawk.main.BazaarFlux;
+import me.lethunderhawk.util.StringUtil;
+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 java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+public class BuyingItemsEditGUI extends PaginatedInventoryGUI<Map.Entry<Material, Double>> {
+    private final EconomyManager manager;
+    public BuyingItemsEditGUI(Player p) {
+        super("Edit Buying Items", 45, p);
+        this.manager = FluxService.get(EconomyAPI.class).getManager();
+    }
+
+    @Override
+    public void buildContent() {
+        fillGlassPaneBackground();
+        List<Integer> slots = computeRectangleSlots(10, 23);
+
+        setupPagination(manager.getItemValues().getBuyingItems().entrySet(), slots);
+
+        sortElements(Comparator.comparing(e -> e.getKey().name()));
+
+        renderPage();
+        addNavigationButtons();
+        setAddItemButton();
+        setBackButton(39);
+        setCloseButton(40);
+    }
+
+    private void setAddItemButton() {
+        setItemWithClickAction(8, new ItemOptions(Material.GREEN_DYE)
+                .setName(Component.text("Create new buy offer"))
+                .setLore(LoreDesigner.createLore("Adds a new Item to the buying List of the Shop GUI"))
+                .buildItemStack(), this::showAddMaterialSign);
+    }
+
+    private void showAddMaterialSign(Player player, ClickType type) {
+        new SignMenuFactory(FluxService.get(BazaarFlux.class)).newMenu(List.of(
+                "",
+                "",
+                "l1: Material Name",
+                "l2: The Price"
+        )).reopenIfFail(true).response((pl, str) -> {
+            try{
+                manager.getItemValues().addBuyingItem(Material.valueOf(str[0]), Double.parseDouble(str[1]));
+                openWithListener(player);
+                update();
+            }catch (Exception e){
+                return false;
+            }
+            return true;
+        }).open(player);
+    }
+
+    @Override
+    public void update() {
+        List<Integer> slots = computeRectangleSlots(10, 23);
+
+        setupPagination(manager.getItemValues().getSellingItems().entrySet(), slots);
+
+        sortElements(Comparator.comparing(e -> e.getKey().name()));
+
+        renderPage();
+    }
+    @Override
+    protected void onClick(Map.Entry<Material, Double> element, Player player, ClickType type) {
+        if(type == ClickType.LEFT) {
+            showEditSign(player, element);
+        }else if(type == ClickType.RIGHT) {
+            showDeletionConfirmation(player, element);
+        }
+    }
+
+    private void showDeletionConfirmation(Player player, Map.Entry<Material, Double> element) {
+        ConfirmationMenu menu = new ConfirmationMenu("Stop buying " + element.getKey().name() + "?", (p) -> {
+            deleteBuyingItem(element);
+            openPrevious(player);
+            update();
+        });
+        openNext(player, menu);
+    }
+
+    private void deleteBuyingItem(Map.Entry<Material, Double> element) {
+        manager.getItemValues().removeBuyingItem(element.getKey());
+    }
+
+    private void showEditSign(Player player, Map.Entry<Material, Double> element) {
+        new SignMenuFactory(FluxService.get(BazaarFlux.class)).newMenu(List.of(
+                "",
+                "^^^^^^^^^^",
+                "Enter the new",
+                "price here"
+        )).reopenIfFail(true).response((pl, str) -> {
+            editPrice(element, Double.parseDouble(str[0]));
+            return true;
+        }).open(player);
+    }
+
+    private void editPrice(Map.Entry<Material, Double> entry, double newPrice) {
+        manager.getItemValues().addBuyingItem(entry.getKey(), newPrice);
+    }
+
+    @Override
+    protected ItemStack createItem(Map.Entry<Material, Double> entry) {
+        Material material = entry.getKey();
+        double price = entry.getValue();
+        String defaultWidth = LoreDesigner.defaultWidthReference;
+        return new ItemOptions(material)
+                .setName(Component.text(StringUtil.toCamelCase(material.name()), NamedTextColor.GREEN))
+                .setLore(LoreDesigner.createLore("<yellow>Buying Price: " + price + " coins" +
+                        "<br><br><gray>Left click to edit" +
+                        "<br>Right click to delete", defaultWidth)
+                )
+                .buildItemStack();
+    }
+}

+ 49 - 0
src/main/java/me/lethunderhawk/economy/shop/ItemValues.java

@@ -0,0 +1,49 @@
+package me.lethunderhawk.economy.shop;
+
+import me.lethunderhawk.fluxapi.profile.AnnotatedProfileCategory;
+import me.lethunderhawk.fluxapi.profile.AnnotatedSerializable;
+import org.bukkit.Material;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ItemValues extends AnnotatedProfileCategory {
+
+    @AnnotatedSerializable(prefix = "buying_items")
+    private Map<Material, Double> buyingItems = new HashMap<>();
+
+    @AnnotatedSerializable(prefix = "selling_items")
+    private Map<Material, Double> sellingItems = new HashMap<>();
+
+    public ItemValues() {
+        sellingItems.put(Material.STONE, 1.0);
+        buyingItems.put(Material.STONE, 1.0);
+    }
+    public void addSellingItem(Material material, double price) {
+        sellingItems.put(material, price);
+    }
+
+    public void removeSellingItem(Material material) {
+        sellingItems.remove(material);
+    }
+
+    public void addBuyingItem(Material material, double value) {
+        buyingItems.put(material, value);
+    }
+
+    public void removeBuyingItem(Material material) {
+        buyingItems.remove(material);
+    }
+
+    public Map<Material, Double> getSellingItems() {
+        return new HashMap<>(sellingItems);
+    }
+
+    public Map<Material, Double> getBuyingItems() {
+        return new HashMap<>(buyingItems);
+    }
+
+    public static ItemValues deserialize(Map<String, Object> map) {
+        return AnnotatedProfileCategory.deserializeFields(ItemValues.class, map);
+    }
+}

+ 132 - 0
src/main/java/me/lethunderhawk/economy/shop/SellingItemsEditGUI.java

@@ -0,0 +1,132 @@
+package me.lethunderhawk.economy.shop;
+
+import me.lethunderhawk.economy.api.EconomyAPI;
+import me.lethunderhawk.economy.currency.EconomyManager;
+import me.lethunderhawk.fluxapi.FluxService;
+import me.lethunderhawk.fluxapi.util.gui.ConfirmationMenu;
+import me.lethunderhawk.fluxapi.util.gui.PaginatedInventoryGUI;
+import me.lethunderhawk.fluxapi.util.gui.input.SignMenuFactory;
+import me.lethunderhawk.fluxapi.util.itemdesign.ItemOptions;
+import me.lethunderhawk.fluxapi.util.itemdesign.LoreDesigner;
+import me.lethunderhawk.main.BazaarFlux;
+import me.lethunderhawk.util.StringUtil;
+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 java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+public class SellingItemsEditGUI extends PaginatedInventoryGUI<Map.Entry<Material, Double>> {
+    private final EconomyManager manager;
+    public SellingItemsEditGUI(Player p) {
+        super("Edit Selling Items", 45, p);
+        this.manager = FluxService.get(EconomyAPI.class).getManager();
+    }
+
+    @Override
+    public void buildContent() {
+        fillGlassPaneBackground();
+        List<Integer> slots = computeRectangleSlots(10, 23);
+
+        setupPagination(manager.getItemValues().getSellingItems().entrySet(), slots);
+
+        sortElements(Comparator.comparing(e -> e.getKey().name()));
+
+        renderPage();
+        addNavigationButtons();
+        setAddItemButton();
+        setBackButton(39);
+        setCloseButton(40);
+    }
+
+    private void setAddItemButton() {
+        setItemWithClickAction(8, new ItemOptions(Material.GREEN_DYE)
+                .setName(Component.text("Create new Sell offer"))
+                .setLore(LoreDesigner.createLore("Adds a new Item to the selling List of the Shop GUI"))
+                .buildItemStack(), this::showAddMaterialSign);
+    }
+
+    private void showAddMaterialSign(Player player, ClickType type) {
+
+        new SignMenuFactory(FluxService.get(BazaarFlux.class)).newMenu(List.of(
+                "",
+                "",
+                "l1: Material Name",
+                "l2: The Price"
+        )).reopenIfFail(true).response((pl, str) -> {
+            try{
+                manager.getItemValues().addSellingItem(Material.valueOf(str[0]), Double.parseDouble(str[1]));
+                openWithListener(player);
+                update();
+            }catch (Exception e){
+                return false;
+            }
+            return true;
+        }).open(player);
+    }
+
+    @Override
+    public void update() {
+        List<Integer> slots = computeRectangleSlots(10, 23);
+
+        setupPagination(manager.getItemValues().getSellingItems().entrySet(), slots);
+
+        sortElements(Comparator.comparing(e -> e.getKey().name()));
+
+        renderPage();
+    }
+    @Override
+    protected void onClick(Map.Entry<Material, Double> element, Player player, ClickType type) {
+        if(type == ClickType.LEFT) {
+            showEditSign(player, element);
+        }else if(type == ClickType.RIGHT) {
+            showDeletionConfirmation(player, element);
+        }
+    }
+
+    private void showDeletionConfirmation(Player player, Map.Entry<Material, Double> element) {
+        ConfirmationMenu menu = new ConfirmationMenu("Stop " + element.getKey().name() + " from selling?", (p) -> {
+            deleteSellingItem(element);
+        });
+        openNext(player, menu);
+    }
+
+    private void deleteSellingItem(Map.Entry<Material, Double> element) {
+        manager.getItemValues().removeSellingItem(element.getKey());
+    }
+
+    private void showEditSign(Player player, Map.Entry<Material, Double> element) {
+        new SignMenuFactory(FluxService.get(BazaarFlux.class)).newMenu(List.of(
+                "",
+                "^^^^^^^^^^",
+                "Enter the new",
+                "price here"
+        )).reopenIfFail(true).response((pl, str) -> {
+            editPrice(element, Double.parseDouble(str[0]));
+            return true;
+        }).open(player);
+    }
+
+    private void editPrice(Map.Entry<Material, Double> entry, double newPrice) {
+        manager.getItemValues().addSellingItem(entry.getKey(), newPrice);
+    }
+
+    @Override
+    protected ItemStack createItem(Map.Entry<Material, Double> entry) {
+        Material material = entry.getKey();
+        double price = entry.getValue();
+        String defaultWidth = LoreDesigner.defaultWidthReference;
+        return new ItemOptions(material)
+                .setName(Component.text(StringUtil.toCamelCase(material.name()), NamedTextColor.GREEN))
+                .setLore(LoreDesigner.createLore("<yellow>Sell Price: " + price + " coins" +
+                                "<br><br><gray>Left click to edit" +
+                                "<br>Right click to delete", defaultWidth)
+                )
+                .buildItemStack();
+    }
+}

+ 47 - 0
src/main/java/me/lethunderhawk/economy/shop/ShopEditGUI.java

@@ -0,0 +1,47 @@
+package me.lethunderhawk.economy.shop;
+
+import me.lethunderhawk.fluxapi.util.gui.InventoryGUI;
+import me.lethunderhawk.fluxapi.util.itemdesign.ItemOptions;
+import me.lethunderhawk.fluxapi.util.itemdesign.LoreDesigner;
+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;
+
+public class ShopEditGUI extends InventoryGUI {
+
+    public ShopEditGUI() {
+        super("Shop editor", 45);
+    }
+
+    @Override
+    public void buildContent() {
+        fillGlassPaneBackground();
+
+        setItemWithClickAction(20, new ItemOptions(Material.HOPPER)
+                .setName(Component.text("Edit Buying Items", NamedTextColor.YELLOW))
+                .setLore(LoreDesigner.createLore("<dark_gray>Edit what the Shop menu will be buying and for what prices"))
+                .buildItemStack(), this::showBuyingItemsGUI);
+        setItemWithClickAction(24, new ItemOptions(Material.BARREL)
+                .setName(Component.text("Edit Selling Items", NamedTextColor.YELLOW))
+                .setLore(LoreDesigner.createLore("<dark_gray>Edit what the Shop menu will be selling and for what prices"))
+                .buildItemStack(), this::showSellingItemsGUI);
+
+        setBackButton(39);
+        setCloseButton(40);
+    }
+
+    private void showSellingItemsGUI(Player player, ClickType type) {
+        openNext(player, new SellingItemsEditGUI(player));
+    }
+
+    private void showBuyingItemsGUI(Player player, ClickType type) {
+        openNext(player, new BuyingItemsEditGUI(player));
+    }
+
+    @Override
+    public void update() {
+
+    }
+}

+ 112 - 0
src/main/java/me/lethunderhawk/economy/shop/ShopGUI.java

@@ -0,0 +1,112 @@
+package me.lethunderhawk.economy.shop;
+
+import me.lethunderhawk.economy.api.EconomyAPI;
+import me.lethunderhawk.economy.currency.EconomyManager;
+import me.lethunderhawk.fluxapi.FluxService;
+import me.lethunderhawk.fluxapi.util.gui.PaginatedInventoryGUI;
+import me.lethunderhawk.fluxapi.util.itemdesign.ItemOptions;
+import me.lethunderhawk.fluxapi.util.itemdesign.LoreDesigner;
+import me.lethunderhawk.util.StringUtil;
+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 java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+public class ShopGUI extends PaginatedInventoryGUI<Map.Entry<Material, Double>> {
+    private final Player player;
+    private final Map<Material, Double> prices;
+    private final EconomyManager manager;
+    public ShopGUI(Player p) {
+        super("Shop", 45, p);
+        this.player = p;
+        this.prices = FluxService.get(EconomyAPI.class).getManager().getItemValues().getSellingItems();
+        this.manager = FluxService.get(EconomyAPI.class).getManager();
+    }
+
+    @Override
+    public void performAdditionalComputationOnPlayer(Player p) {
+
+    }
+
+    @Override
+    public void buildContent() {
+        fillGlassPaneBackground();
+
+        List<Integer> slots = computeRectangleSlots(10, 23);
+
+        setupPagination(prices.entrySet(), slots);
+
+        sortElements(Comparator.comparing(e -> e.getKey().name()));
+
+        renderPage();
+
+        addNavigationButtons();
+
+        setCloseButton(40);
+
+        setItemWithClickAction(41,
+                new ItemOptions(Material.HOPPER)
+                        .setName(Component.text("Sell Items", NamedTextColor.YELLOW))
+                        .setLore(LoreDesigner.createLore("<dark_gray>Drag and drop items into this hopper to sell them!"))
+                        .buildItemStack(),
+                this::sellItem);
+
+        if(player.isOp()){
+            setEditShopButton();
+        }
+        if(hasPreviousGUI()){
+            setBackButton(39);
+        }
+    }
+
+    private void setEditShopButton() {
+        setItemWithClickAction(44, new ItemOptions(Material.BOOK).setName(Component.text("Edit the shop", NamedTextColor.RED)).buildItemStack(), this::openEditGUI);
+    }
+
+    private void openEditGUI(Player player, ClickType type) {
+        openNext(player, new ShopEditGUI());
+    }
+
+    @Override
+    protected void onClick(Map.Entry<Material, Double> element, Player player, ClickType type) {
+        if(manager.removeMoney(player.getUniqueId(), element.getValue())){
+            player.getInventory().addItem(new ItemStack(element.getKey()));
+        }
+    }
+
+    private void sellItem(Player player, ClickType type) {
+        ItemValues values = manager.getItemValues();
+        if(values.getBuyingItems().containsKey(player.getItemOnCursor().getType()) ){
+            ItemStack cursor = player.getItemOnCursor();
+
+            long amount = values.getBuyingItems().get(cursor.getType()).longValue() * cursor.getAmount();
+            manager.addMoney(player.getUniqueId(), amount);
+            cursor.setAmount(0);
+        }
+    }
+
+    @Override
+    public void update() {
+
+    }
+
+    @Override
+    protected ItemStack createItem(Map.Entry<Material, Double> entry) {
+
+        Material material = entry.getKey();
+        double price = entry.getValue();
+
+        return new ItemOptions(material)
+                .setName(Component.text(StringUtil.toCamelCase(material.name()), NamedTextColor.GREEN))
+                .setLore(List.of(
+                        Component.text("Sell Price: $" + price, NamedTextColor.YELLOW)
+                ))
+                .buildItemStack();
+    }
+}

+ 4 - 5
src/main/java/me/lethunderhawk/main/BazaarFlux.java

@@ -7,10 +7,8 @@ import me.lethunderhawk.economy.EconomyModule;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.gui.InventoryManager;
 import me.lethunderhawk.fluxapi.util.interfaces.FluxAPIModule;
-import me.lethunderhawk.npc.NPCRegistrator;
 import me.lethunderhawk.profile.ProfileModule;
 import me.lethunderhawk.tradeplugin.TradeModule;
-import me.lethunderhawk.world.WorldModule;
 import org.bukkit.plugin.java.JavaPlugin;
 
 import java.util.ArrayList;
@@ -32,9 +30,10 @@ public class BazaarFlux extends JavaPlugin{
                 new CustomRecipeModule(this),
                 //new MinionModule(this),
                 //new DungeonModule(this),
-                new WorldModule(this),
-                new ProfileModule(this),
-                new NPCRegistrator(this));
+                //new WorldModule(this),
+                new ProfileModule(this)
+                //new NPCRegistrator(this)
+        );
     }
     private void registerAllModules(FluxAPIModule... modules){
         for(FluxAPIModule module : modules){

+ 28 - 50
src/main/java/me/lethunderhawk/profile/ProfileModule.java

@@ -3,10 +3,7 @@ package me.lethunderhawk.profile;
 import me.lethunderhawk.fluxapi.profile.representation.FluxProfile;
 import me.lethunderhawk.fluxapi.util.interfaces.FluxAPIModule;
 import me.lethunderhawk.profile.command.ProfileCommand;
-import me.lethunderhawk.profile.data.sacks.Sack;
-import me.lethunderhawk.profile.data.sacks.SackContent;
-import me.lethunderhawk.profile.data.sacks.SackType;
-import org.bukkit.Material;
+import me.lethunderhawk.profile.data.sacks.*;
 import org.bukkit.configuration.serialization.ConfigurationSerialization;
 import org.bukkit.plugin.java.JavaPlugin;
 
@@ -22,9 +19,9 @@ public class ProfileModule extends FluxAPIModule {
 
     @Override
     public void onEnable() {
-        ConfigurationSerialization.registerClass(SackContent.class);
-        registerMiningSackTypes();
-        registerForagingSackTypes();
+        registerSerialization();
+        loadConfig();
+
 
         FluxProfile.registerSubProfile(
                 "mining_sack",
@@ -38,58 +35,39 @@ public class ProfileModule extends FluxAPIModule {
                 uuid -> new Sack(SackType.FORAGING)
         );
 
+        FluxProfile.registerSubProfile(
+                "combat_sack",
+                Sack.class,
+                uuid -> new Sack(SackType.COMBAT)
+        );
+
+        FluxProfile.registerSubProfile(
+                "fishing_sack",
+                Sack.class,
+                uuid -> new Sack(SackType.FISHING)
+        );
+        FluxProfile.registerSubProfile(
+                "farming_sack",
+                Sack.class,
+                uuid -> new Sack(SackType.FARMING)
+        );
+
         ProfileCommand command = new ProfileCommand(this);
         plugin.getCommand("profile").setExecutor(command);
         plugin.getCommand("profile").setTabCompleter(command);
     }
 
-    private void registerForagingSackTypes() {
-        registerLogs();
-        registerLeaves();
-        Sack.registerType(SackType.FORAGING, Material.STICK, 1024);
+    private void loadConfig() {
+        SackRegistry.unregisterAll();
+        plugin.reloadConfig();
+        SackConfigLoader.load(plugin.getConfig());
     }
 
-    private void registerLeaves() {
-        Sack.registerType(SackType.FORAGING, Material.OAK_LEAVES);
-        Sack.registerType(SackType.FORAGING, Material.SPRUCE_LEAVES);
-        Sack.registerType(SackType.FORAGING, Material.BIRCH_LOG);
-        Sack.registerType(SackType.FORAGING, Material.JUNGLE_LEAVES);
-        Sack.registerType(SackType.FORAGING, Material.ACACIA_LEAVES);
-        Sack.registerType(SackType.FORAGING, Material.DARK_OAK_LEAVES);
-        Sack.registerType(SackType.FORAGING, Material.MANGROVE_LEAVES);
-        Sack.registerType(SackType.FORAGING, Material.CHERRY_LEAVES);
-        Sack.registerType(SackType.FORAGING, Material.PALE_OAK_LEAVES);
+    private void registerSerialization() {
+        ConfigurationSerialization.registerClass(Sack.class, "Sack");
+        ConfigurationSerialization.registerClass(SackContent.class, "SackContent");
     }
 
-    private void registerLogs() {
-        Sack.registerType(SackType.FORAGING, Material.OAK_LOG);
-        Sack.registerType(SackType.FORAGING, Material.SPRUCE_LOG);
-        Sack.registerType(SackType.FORAGING, Material.BIRCH_LOG);
-        Sack.registerType(SackType.FORAGING, Material.JUNGLE_LOG);
-        Sack.registerType(SackType.FORAGING, Material.ACACIA_LOG);
-        Sack.registerType(SackType.FORAGING, Material.DARK_OAK_LOG);
-        Sack.registerType(SackType.FORAGING, Material.MANGROVE_LOG);
-        Sack.registerType(SackType.FORAGING, Material.CHERRY_LOG);
-        Sack.registerType(SackType.FORAGING, Material.PALE_OAK_LOG);
-        Sack.registerType(SackType.FORAGING, Material.CRIMSON_STEM);
-        Sack.registerType(SackType.FORAGING, Material.WARPED_STEM);
-    }
-
-    private void registerMiningSackTypes() {
-        Sack.registerType(SackType.MINING, Material.COBBLESTONE, 1024);
-        Sack.registerType(SackType.MINING, Material.STONE, 1024);
-        Sack.registerType(SackType.MINING, Material.SANDSTONE);
-        Sack.registerType(SackType.MINING, Material.RED_SANDSTONE);
-        Sack.registerType(SackType.MINING, Material.BLACKSTONE);
-        Sack.registerType(SackType.MINING, Material.REDSTONE);
-        Sack.registerType(SackType.MINING, Material.RAW_COPPER);
-        Sack.registerType(SackType.MINING, Material.RAW_GOLD);
-        Sack.registerType(SackType.MINING, Material.RAW_IRON);
-        Sack.registerType(SackType.MINING, Material.EMERALD);
-        Sack.registerType(SackType.MINING, Material.DIAMOND, 128);
-        Sack.registerType(SackType.MINING, Material.QUARTZ);
-        Sack.registerType(SackType.MINING, Material.ANCIENT_DEBRIS, 16);
-    }
 
     @Override
     public void onDisable() {

+ 23 - 38
src/main/java/me/lethunderhawk/profile/data/sacks/Sack.java

@@ -10,46 +10,30 @@ import java.util.Map;
 
 public class Sack extends AnnotatedProfileCategory {
     @AnnotatedSerializable(prefix = "sackType")
-    private final SackType sackType;
+    private SackType sackType;
 
     @AnnotatedSerializable(prefix = "items")
     private Map<Material, SackContent> items = new HashMap<>();
 
-    private static final Map<SackType, Map<Material, SackContent>> registeredMap = new HashMap<>();
+    @AnnotatedSerializable(prefix = "autoPickUp")
+    private Boolean autoPickupEnabled = false;
 
-    public static void registerType(SackType type, Material material){
-        if (!registeredMap.containsKey(type)) {
-            registeredMap.put(type, new HashMap<>());
-        }
-        if(!registeredMap.get(type).containsKey(material)){
-            registeredMap.get(type).put(material, createDefaultCapacitySackItem(material));
-        }
-    }
+    public Sack(){}
+    public Sack(SackType type){
+        this.sackType = type;
 
-    public static void registerType(SackType type, Material material, int maxAmount){
-        if (!registeredMap.containsKey(type)) {
-            registeredMap.put(type, new HashMap<>());
-        }
-        if(!registeredMap.get(type).containsKey(material)){
-            registeredMap.get(type).put(material, createSackContent(material, maxAmount));
+        for(Material mat : SackRegistry.getRegisteredType(type).keySet()){
+            items.put(mat, new SackContent(mat));
         }
     }
 
-    public static Map<Material, SackContent> getRegisteredType(SackType sackType){
-        return registeredMap.getOrDefault(sackType, null);
+    public Map<Material, Integer> getAssociatedSackMap(){
+        return SackRegistry.getRegisteredType(sackType);
     }
 
-    public static Map<SackType, Map<Material, SackContent>> getRegisteredTypes() {
-        return new HashMap<>(registeredMap);
-    }
-
-    public Map<Material, SackContent> getAssociatedSackMap(){
-        return getRegisteredType(sackType);
-    }
 
-    public Sack(SackType type){
-        this.sackType = type;
-        items.putAll(registeredMap.get(type));
+    public static Sack deserialize(Map<String, Object> map) {
+        return AnnotatedProfileCategory.deserializeFields(Sack.class, map);
     }
 
     public SackType getType(){
@@ -71,8 +55,8 @@ public class Sack extends AnnotatedProfileCategory {
         if(getAssociatedSackMap() == null || !getAssociatedSackMap().containsKey(material)){
             return amount;
         }
-        items.putIfAbsent(material, createDefaultCapacitySackItem(material));
-        return items.get(material).addAmount(amount);
+        items.putIfAbsent(material, new SackContent(material));
+        return items.get(material).addAmount(sackType, amount);
     }
 
     public int takeOutItem(Material material) {
@@ -83,29 +67,30 @@ public class Sack extends AnnotatedProfileCategory {
         if(getAssociatedSackMap() == null || !getAssociatedSackMap().containsKey(material)){
             return amount;
         }
-        items.putIfAbsent(material, createDefaultCapacitySackItem(material));
+        items.putIfAbsent(material, new SackContent(material));
         return items.get(material).removeAmount(amount);
     }
 
     public int getMaxMaterialAmount(Material material) {
         if(getAssociatedSackMap() == null) return 0;
         if (!getAssociatedSackMap().containsKey(material)) {
-            getAssociatedSackMap().putIfAbsent(material, createDefaultCapacitySackItem(material));
+            getAssociatedSackMap().putIfAbsent(material, SackRegistry.getMaxAmount(sackType, material));
         }
-        return getAssociatedSackMap().get(material).getMaxAmount();
+        return getAssociatedSackMap().get(material);
     }
 
     public int getMaterialAmount(Material material) {
         if (!items.containsKey(material)) {
-            items.put(material, createDefaultCapacitySackItem(material));
+            items.put(material, new SackContent(material));
         }
         return items.get(material).getAmount();
     }
-    private static SackContent createSackContent(Material material, int maxAmount) {
-        return new SackContent(material, 0, maxAmount);
+
+    public boolean isAutoPickUpEnabled() {
+        return autoPickupEnabled;
     }
 
-    private static SackContent createDefaultCapacitySackItem(Material material){
-        return new SackContent(material, 0, 512);
+    public void toggleAutoPickUp() {
+        autoPickupEnabled = !autoPickupEnabled;
     }
 }

+ 48 - 0
src/main/java/me/lethunderhawk/profile/data/sacks/SackConfigLoader.java

@@ -0,0 +1,48 @@
+package me.lethunderhawk.profile.data.sacks;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+
+public class SackConfigLoader {
+    private static final String configName = "registeredSackItems";
+    private SackConfigLoader() {}
+    public static void load(FileConfiguration config) {
+
+        ConfigurationSection root = config.getConfigurationSection(configName);
+
+        if (root == null) {
+            config.createSection(configName);
+            return;
+        }
+
+        for (String typeKey : root.getKeys(false)) {
+
+
+            SackType type;
+            try {
+                type = SackType.valueOf(typeKey);
+            } catch (IllegalArgumentException e) {
+                Bukkit.getLogger().warning("Invalid SackType: " + typeKey);
+                continue;
+            }
+
+            ConfigurationSection materials = root.getConfigurationSection(typeKey);
+            if (materials == null) continue;
+
+            for (String materialKey : materials.getKeys(false)) {
+
+
+                Material material = Material.matchMaterial(materialKey);
+                if (material == null) {
+                    Bukkit.getLogger().warning("Invalid material: " + materialKey);
+                    continue;
+                }
+
+                int maxAmount = materials.getInt(materialKey, 512);
+                SackRegistry.registerType(type, material, maxAmount);
+            }
+        }
+    }
+}

+ 31 - 47
src/main/java/me/lethunderhawk/profile/data/sacks/SackContent.java

@@ -8,66 +8,50 @@ import java.util.Map;
 
 public class SackContent extends AnnotatedProfileCategory {
     @AnnotatedSerializable(prefix = "material")
-    private final String material;
-    @AnnotatedSerializable(prefix = "amount")
-    private int amount;
-    @AnnotatedSerializable(prefix = "maxAmount")
-    private int maxAmount;
-
-    /**
-     *
-     * @param addAmount The amount to add to the SackItem
-     * @return The Leftover / overflow not being able to put into the SackItem
-     */
-    public int addAmount(int addAmount) {
+    private String material;
 
-        int spaceLeft = maxAmount - this.amount;
+    @AnnotatedSerializable(prefix = "amount")
+    private Integer amount = 0;
 
-        if (addAmount > spaceLeft) {
-            this.amount = maxAmount;
-            return addAmount - spaceLeft; // leftover
-        }
+    public SackContent() {}
 
-        this.amount += addAmount;
-        return 0; // no leftover
+    public SackContent(Material material) {
+        this.material = material.name();
     }
 
-    /**
-     *
-     * @param removeAmount The amount to remove from the SackItem
-     * @return The amount actually removed
-     */
-    public int removeAmount(int removeAmount) {
-
-        if (removeAmount >= this.amount) {
-            int removed = this.amount;
-            this.amount = 0;
-            return removed;
-        }
-
-        this.amount -= removeAmount;
-        return removeAmount;
+    public int getMaxAmount(SackType type) {
+        return SackRegistry.getMaxAmount(type, Material.valueOf(material));
     }
 
+    public int addAmount(SackType type, int add) {
 
-    public SackContent(Material material, int amount, int maxAmount) {
-        this.material = material.name();
-        this.amount = amount;
-        this.maxAmount = maxAmount;
-    }
+        int max = getMaxAmount(type);
+        if(amount + add <= max){
+            amount += add;
+            return 0;
+        }else{
+            int newAmount = Math.min(amount + add, max);
+            int leftover = (amount + add) - newAmount;
 
-    public SackContent(Map<String, Object> map) {
-        this.material = (String) map.get("material");
-        this.amount = (int) map.get("amount");
-        this.maxAmount = (int) map.get("maxAmount");
+            amount = newAmount;
+
+            return leftover;
+        }
     }
 
-    public Material getMaterial() {
-        return Material.valueOf(this.material);
+    public static SackContent deserialize(Map<String, Object> map) {
+        return AnnotatedProfileCategory.deserializeFields(SackContent.class, map);
     }
 
-    public int getMaxAmount() {
-        return maxAmount;
+    public int removeAmount(int takeoutAmount) {
+        if(amount >= takeoutAmount){
+            amount -= takeoutAmount;
+            return takeoutAmount;
+        }else{
+            int leftOver = amount;
+            amount = 0;
+            return leftOver;
+        }
     }
 
     public int getAmount() {

+ 30 - 0
src/main/java/me/lethunderhawk/profile/data/sacks/SackRegistry.java

@@ -0,0 +1,30 @@
+package me.lethunderhawk.profile.data.sacks;
+
+import org.bukkit.Material;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SackRegistry {
+
+    private static final Map<SackType, Map<Material, Integer>> registeredMap = new HashMap<>();
+
+    public static void registerType(SackType type, Material material, int maxAmount) {
+        registeredMap.computeIfAbsent(type, k -> new HashMap<>())
+                .put(material, maxAmount);
+    }
+
+    public static Map<Material, Integer> getRegisteredType(SackType type) {
+        return registeredMap.getOrDefault(type, Map.of());
+    }
+
+    public static int getMaxAmount(SackType type, Material material) {
+        return registeredMap
+                .getOrDefault(type, Map.of())
+                .getOrDefault(material, 0);
+    }
+
+    public static void unregisterAll() {
+        registeredMap.clear();
+    }
+}

+ 4 - 1
src/main/java/me/lethunderhawk/profile/data/sacks/SackType.java

@@ -2,5 +2,8 @@ package me.lethunderhawk.profile.data.sacks;
 
 public enum SackType {
     MINING,
-    FORAGING
+    COMBAT,
+    FORAGING,
+    FARMING,
+    FISHING,
 }

+ 32 - 113
src/main/java/me/lethunderhawk/profile/data/sacks/gui/SackGUI.java

@@ -1,6 +1,6 @@
 package me.lethunderhawk.profile.data.sacks.gui;
 
-import me.lethunderhawk.fluxapi.util.gui.InventoryGUI;
+import me.lethunderhawk.fluxapi.util.gui.PaginatedInventoryGUI;
 import me.lethunderhawk.fluxapi.util.itemdesign.ItemOptions;
 import me.lethunderhawk.fluxapi.util.itemdesign.LoreDesigner;
 import me.lethunderhawk.profile.data.sacks.Sack;
@@ -13,14 +13,14 @@ import org.bukkit.entity.Player;
 import org.bukkit.event.inventory.ClickType;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.PlayerInventory;
-import org.bukkit.inventory.meta.ItemMeta;
 import org.jetbrains.annotations.NotNull;
 
-import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
-public class SackGUI extends InventoryGUI {
+public class SackGUI extends PaginatedInventoryGUI<Map.Entry<Material, Integer>> {
 
     private final Sack sack;
     private Player player;
@@ -32,9 +32,8 @@ public class SackGUI extends InventoryGUI {
     private List<Integer> contentSlots;
 
     public SackGUI(@NotNull Player p, @NotNull Sack sack) {
-        super("Your " + sack.getType().name().toLowerCase() + " Sack", 36, p);
+        super("Your " + sack.getType().name().toLowerCase() + " Sack", 54, p);
         this.sack = sack;
-
     }
 
     @Override
@@ -44,60 +43,33 @@ public class SackGUI extends InventoryGUI {
 
     @Override
     public void buildContent() {
+        List<Integer> slots = computeRectangleSlots(10, 43);
 
-        fillGlassPaneBackground();
-
-        materials = new ArrayList<>(sack.getAssociatedSackMap().keySet());
+        setupPagination(sack.getAssociatedSackMap().entrySet(), slots);
 
-        contentSlots = computeContentSlots();
-        int itemsPerPage = contentSlots.size();
-        maxPage = (materials.size() - 1) / itemsPerPage;
+        sortElements(Comparator.comparing(e -> e.getKey().name()));
 
-        renderPage();
-        addNavigationButtons();
-        setCloseButton(getInventory().getSize() - 5);
-        setAddAllItemsItem();
+        update();
     }
-
-    /**
-     * Computes all interior slots dynamically (1 slot border).
-     */
-    private List<Integer> computeContentSlots() {
-
-        List<Integer> slots = new ArrayList<>();
-
-        int rows = getInventory().getSize() / 9;
-
-        for (int row = 1; row < rows - 1; row++) {
-            for (int col = 1; col < 8; col++) {
-
-                int slot = row * 9 + col;
-                slots.add(slot);
-
-            }
-        }
-
-        return slots;
+    @Override
+    protected void onClick(Map.Entry<Material, Integer> element, Player player, ClickType type) {
+        doSackAction(type, element.getKey());
     }
 
-    private void renderPage() {
-
-        int itemsPerPage = contentSlots.size();
-        int start = currentPage * itemsPerPage;
-
-        for (int i = 0; i < itemsPerPage; i++) {
-
-            int materialIndex = start + i;
-
-            if (materialIndex >= materials.size()) continue;
-
-            Material material = materials.get(materialIndex);
-
-            addSackItem(material, contentSlots.get(i));
-        }
+    private void setTogglePickUpItem(int slot) {
+        setItemWithClickAction(slot, new ItemOptions(sack.isAutoPickUpEnabled() ? Material.GREEN_STAINED_GLASS : Material.RED_STAINED_GLASS)
+                .setName(Component.text("Auto-Pickup", NamedTextColor.YELLOW))
+                .setLore(LoreDesigner.createLore("Current Status: " + (sack.isAutoPickUpEnabled() ? "<green>ENABLED" : "<red>DISABLED")))
+                .buildItemStack(), this::toggleAutoPickup);
     }
 
-    private void addSackItem(Material material, int slot) {
+    private void toggleAutoPickup(Player player, ClickType type) {
+        sack.toggleAutoPickUp();
+        update();
+    }
+    @Override
+    protected ItemStack createItem(Map.Entry<Material, Integer> materialDoubleEntry) {
+        Material material = materialDoubleEntry.getKey();
 
         String materialName = StringUtil.toCamelCase(material.name());
 
@@ -113,64 +85,11 @@ public class SackGUI extends InventoryGUI {
                 "This is an example width reference",
                 NamedTextColor.GRAY
         );
+        return new ItemOptions(material)
+                .setName(Component.text(materialName, NamedTextColor.GREEN))
+                .setLore(lore)
+                .buildItemStack();
 
-        setItemWithClickAction(slot,
-                new ItemOptions(material)
-                        .setName(Component.text(materialName, NamedTextColor.GREEN))
-                        .setLore(lore)
-                        .buildItemStack(),
-                (p, type) -> doSackAction(type, material)
-        );
-    }
-
-    private void addNavigationButtons() {
-        if (currentPage > 0) {
-            setItemWithClickAction(getInventory().getSize() - 9,
-                    new ItemOptions(Material.ARROW)
-                            .setName(Component.text("Previous Page", NamedTextColor.YELLOW))
-                            .setLore(List.of(Component.text("Current Page: " + (currentPage + 1) + "/" + (maxPage + 1), NamedTextColor.GRAY)))
-                            .buildItemStack(),
-                    (p, type) -> {
-                        previousPage();
-                    });
-        }else{
-            setItem(getInventory().getSize() - 9, getGlassPaneStack());
-        }
-
-        if (currentPage < maxPage) {
-            setItemWithClickAction(getInventory().getSize() -1,
-                    new ItemOptions(Material.ARROW)
-                            .setName(Component.text("Next Page", NamedTextColor.YELLOW))
-                            .setLore(List.of(Component.text("Current Page " + (currentPage + 1) + "/" + (maxPage + 1), NamedTextColor.GRAY)))
-                            .buildItemStack(),
-                    (p, type) -> {
-                        nextPage();
-                    });
-        }else{
-            setItem(getInventory().getSize() -1, getGlassPaneStack());
-        }
-    }
-    private ItemStack getGlassPaneStack(){
-        ItemStack background = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
-        ItemMeta meta = background.getItemMeta();
-        meta.displayName(Component.text(" "));
-        meta.setHideTooltip(true);
-        background.setItemMeta(meta);
-        return background;
-    }
-
-    private void previousPage() {
-        if(currentPage > 0) {
-            currentPage--;
-            update();
-        }
-    }
-
-    private void nextPage() {
-        if(currentPage < maxPage) {
-            currentPage++;
-            update();
-        }
     }
 
     private void doSackAction(ClickType type, Material material) {
@@ -203,9 +122,8 @@ public class SackGUI extends InventoryGUI {
         update();
     }
 
-    private void setAddAllItemsItem() {
-
-        setItemWithClickAction(getInventory().getSize() - 4,
+    private void setAddAllItemsItem(int slot) {
+        setItemWithClickAction(slot,
                 new ItemOptions(Material.CAULDRON)
                         .setName(Component.text("Add all items into the Sack", NamedTextColor.GREEN))
                         .setLore(LoreDesigner.createLore(
@@ -246,8 +164,9 @@ public class SackGUI extends InventoryGUI {
         fillGlassPaneBackground();
         renderPage();
         addNavigationButtons();
+        setTogglePickUpItem(8);
         setCloseButton(getInventory().getSize() - 5);
-        setAddAllItemsItem();
+        setAddAllItemsItem(getInventory().getSize() - 4);
     }
 
     private void clearInventory() {

+ 9 - 2
src/main/java/me/lethunderhawk/profile/gui/StatsGUI.java

@@ -1,5 +1,6 @@
 package me.lethunderhawk.profile.gui;
 
+import me.lethunderhawk.economy.shop.ShopGUI;
 import me.lethunderhawk.fluxapi.util.CustomHeadCreator;
 import me.lethunderhawk.fluxapi.util.gui.InventoryGUI;
 import me.lethunderhawk.fluxapi.util.itemdesign.ItemOptions;
@@ -41,9 +42,15 @@ public class StatsGUI extends InventoryGUI {
     @Override
     public void buildContent() {
         fillGlassPaneBackground();
-        ItemStack item = createPlayerHead();
+        setItemWithClickAction(4, createPlayerHead(), this::displayEasterEgg);
+        setItemWithClickAction(22, new ItemOptions(Material.DIAMOND)
+                .setName(Component.text("Shop", NamedTextColor.GOLD))
+                .setLore(LoreDesigner.createLore("<dark_gray>Open the shop to trade your goods for coins!"))
+                .buildItemStack(), this::openShop);
+    }
 
-        setItemWithClickAction(4, item, this::displayEasterEgg);
+    private void openShop(Player player, ClickType type) {
+        openNext(player, new ShopGUI(player));
     }
 
     @Override

+ 131 - 0
src/main/resources/config.yml

@@ -6,3 +6,134 @@ bazaarflux:
 
 claims:
   max-blocks: 25000
+
+registeredSackItems:
+  MINING:
+    COBBLESTONE: 4096
+    STONE: 4096
+    GRANITE: 2048
+    DIORITE: 2048
+    ANDESITE: 2048
+    DEEPSLATE: 4096
+    COBBLED_DEEPSLATE: 4096
+    BLACKSTONE: 4096
+    TUFF: 4096
+    BASALT: 4096
+    END_STONE: 2048
+    ICE: 4096
+    CALCITE: 2048
+    OBSIDIAN: 2048
+    ANCIENT_DEBRIS: 512
+    COAL: 2048
+    RAW_COPPER: 2048
+    RAW_IRON: 2048
+    RAW_GOLD: 2048
+    EMERALD: 2048
+    LAPIS_LAZULI: 2048
+    DIAMOND: 2048
+    QUARTZ: 2048
+    SAND: 4096
+    SANDSTONE: 2048
+    RED_SAND: 4096
+    RED_SANDSTONE: 2048
+    TERRACOTTA: 4096
+
+  COMBAT:
+    STRING: 1024
+    ENDER_PEARL: 2048
+    ROTTEN_FLESH: 1024
+    SPIDER_EYE: 1024
+    BONE: 1024
+    BONE_MEAL: 1024
+    SLIME_BALL: 1024
+    GHAST_TEAR: 1024
+    BLAZE_ROD: 1024
+    BREEZE_ROD: 1024
+    SHULKER_SHELL: 128
+    GUNPOWDER: 1024
+    MAGMA_CREAM: 1024
+    PHANTOM_MEMBRANE: 256
+    LEATHER: 1024
+    RABBIT_HIDE: 1024
+    RABBIT_FOOT: 1024
+    MUTTON: 1024
+    PORKCHOP: 1024
+    CHICKEN: 1024
+    RABBIT: 1024
+    BEEF: 1024
+
+  FARMING:
+    DIRT: 4096
+    GRAVEL: 4096
+    MOSS_BLOCK: 4096
+    PALE_MOSS_BLOCK: 4096
+    CACTUS: 4096
+    BAMBOO: 4096
+    SUGAR_CANE: 4096
+    VINE: 4096
+    WEEPING_VINES: 4096
+    TWISTING_VINES: 4096
+    WHEAT_SEEDS: 4096
+    COCOA_BEANS: 4096
+    WHEAT: 4096
+    BEETROOT: 4096
+    POISONOUS_POTATO: 4096
+    POTATO: 4096
+    CARROT: 4096
+    CHORUS_FRUIT: 4096
+    MELON_SLICE: 4096
+    KELP: 4096
+    NETHER_WART: 4096
+    SWEET_BERRIES: 4096
+    GLOW_BERRIES: 4096
+    BEETROOT_SEEDS: 4096
+    MELON_SEEDS: 4096
+    PUMPKIN_SEEDS: 4096
+    BROWN_MUSHROOM: 4096
+    RED_MUSHROOM: 4096
+
+
+  FISHING:
+    COD: 1024
+    PUFFERFISH: 1024
+    PRISMARINE_CRYSTALS: 1024
+    PRISMARINE_SHARD: 1024
+    CLAY_BALL: 1024
+    TROPICAL_FISH: 1024
+    SALMON: 1024
+    NAUTILUS_SHELL: 1024
+    INK_SAC: 1024
+    NAME_TAG: 5
+    SADDLE: 10
+    LILY_PAD: 1024
+
+
+  FORAGING:
+    OAK_LOG: 2048
+    BIRCH_LOG: 2048
+    SPRUCE_LOG: 2048
+    JUNGLE_LOG: 2048
+    ACACIA_LOG: 2048
+    DARK_OAK_LOG: 2048
+    MANGROVE_LOG: 2048
+    CHERRY_LOG: 2048
+    PALE_OAK_LOG: 2048
+    CRIMSON_STEM: 2048
+    WARPED_STEM: 2048
+    MUSHROOM_STEM: 2048
+    BROWN_MUSHROOM_BLOCK: 2048
+    RED_MUSHROOM_BLOCK: 2048
+    SHROOMLIGHT: 2048
+    OAK_SAPLING: 2048
+    SPRUCE_SAPLING: 2048
+    BIRCH_SAPLING: 2048
+    JUNGLE_SAPLING: 2048
+    ACACIA_SAPLING: 2048
+    DARK_OAK_SAPLING: 2048
+    CHERRY_SAPLING: 2048
+    PALE_OAK_SAPLING: 2048
+    AZALEA: 2048
+    FLOWERING_AZALEA: 2048
+    MANGROVE_PROPAGULE: 2048
+    STICK: 4096
+    APPLE: 1024