瀏覽代碼

Start of custom world generation, renaming of entrypoint for plugin

Jan 1 月之前
父節點
當前提交
ac81fa6f42
共有 37 個文件被更改,包括 549 次插入150 次删除
  1. 2 2
      pom.xml
  2. 7 7
      src/main/java/me/lethunderhawk/clans/ClanModule.java
  3. 2 2
      src/main/java/me/lethunderhawk/clans/gui/ClaimSettingsGUI.java
  4. 2 2
      src/main/java/me/lethunderhawk/clans/settings/ClanSettings.java
  5. 2 2
      src/main/java/me/lethunderhawk/custom/block/registry/BlockRegistry.java
  6. 7 7
      src/main/java/me/lethunderhawk/custom/item/CustomItemModule.java
  7. 3 3
      src/main/java/me/lethunderhawk/custom/item/abstraction/definition/ItemDefinitionLoader.java
  8. 5 5
      src/main/java/me/lethunderhawk/custom/item/abstraction/instance/ItemPersistentData.java
  9. 2 2
      src/main/java/me/lethunderhawk/custom/item/abstraction/registry/CustomItemRegistry.java
  10. 2 2
      src/main/java/me/lethunderhawk/custom/item/concrete/ability/ClaimToolAbility.java
  11. 4 4
      src/main/java/me/lethunderhawk/dungeon/DungeonModule.java
  12. 2 2
      src/main/java/me/lethunderhawk/dungeon/command/DungeonCommand.java
  13. 6 6
      src/main/java/me/lethunderhawk/dungeon/generation/DungeonGridGenerator.java
  14. 2 2
      src/main/java/me/lethunderhawk/dungeon/generation/DungeonWorld.java
  15. 1 1
      src/main/java/me/lethunderhawk/economy/EconomyModule.java
  16. 1 1
      src/main/java/me/lethunderhawk/economy/listener/PlayerJoinListener.java
  17. 2 2
      src/main/java/me/lethunderhawk/main/BazaarFlux.java
  18. 2 2
      src/main/java/me/lethunderhawk/minion/MinionModule.java
  19. 2 2
      src/main/java/me/lethunderhawk/minion/api/MinionLevel.java
  20. 2 2
      src/main/java/me/lethunderhawk/minion/enchantedVariant/item/abstraction/EnchantedItem.java
  21. 2 2
      src/main/java/me/lethunderhawk/minion/enchantedVariant/recipe/EnchantedItemRecipe.java
  22. 2 2
      src/main/java/me/lethunderhawk/minion/item/MinionItem.java
  23. 2 2
      src/main/java/me/lethunderhawk/minion/ui/MinionMenu.java
  24. 1 1
      src/main/java/me/lethunderhawk/scoreboard/ScoreboardManager.java
  25. 2 1
      src/main/java/me/lethunderhawk/scoreboard/ScoreboardTemplate.java
  26. 2 2
      src/main/java/me/lethunderhawk/tradeplugin/listener/TradeInventoryListener.java
  27. 2 2
      src/main/java/me/lethunderhawk/tradeplugin/trade/TradeRequestManager.java
  28. 4 4
      src/main/java/me/lethunderhawk/tradeplugin/trade/TradeSession.java
  29. 26 23
      src/main/java/me/lethunderhawk/world/WorldModule.java
  30. 26 0
      src/main/java/me/lethunderhawk/world/abstraction/WorldStorageManager.java
  31. 29 10
      src/main/java/me/lethunderhawk/world/command/WorldCommand.java
  32. 36 24
      src/main/java/me/lethunderhawk/world/island/IslandBootstrapListener.java
  33. 2 2
      src/main/java/me/lethunderhawk/world/island/IslandWorld.java
  34. 270 0
      src/main/java/me/lethunderhawk/world/manager/NestedWorldStorageManager.java
  35. 38 0
      src/main/java/me/lethunderhawk/world/util/DirectoryUtils.java
  36. 40 3
      src/main/java/me/lethunderhawk/world/util/WorldManager.java
  37. 7 14
      src/main/resources/plugin.yml

+ 2 - 2
pom.xml

@@ -5,7 +5,7 @@
     <modelVersion>4.0.0</modelVersion>
 
     <groupId>me.lethunderhawk</groupId>
-    <artifactId>bazaar-flux</artifactId>
+    <artifactId>BazaarFlux</artifactId>
     <version>1.2-SNAPSHOT</version>
     <packaging>jar</packaging>
 
@@ -110,7 +110,7 @@
         <dependency>
             <groupId>me.lethunderhawk</groupId>
             <artifactId>FluxAPI</artifactId>
-            <version>1.0-SNAPSHOT</version>
+            <version>1.2.0</version>
             <scope>provided</scope>
         </dependency>
     </dependencies>

+ 7 - 7
src/main/java/me/lethunderhawk/clans/ClanModule.java

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

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

@@ -7,7 +7,7 @@ import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.gui.ConfirmationMenu;
 import me.lethunderhawk.fluxapi.util.gui.InventoryGUI;
 import me.lethunderhawk.fluxapi.util.gui.input.SignMenuFactory;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import me.lethunderhawk.fluxapi.util.UnItalic;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.format.NamedTextColor;
@@ -65,7 +65,7 @@ public class ClaimSettingsGUI extends InventoryGUI {
     }
 
     private void renameClaim(Claim claim) {
-        SignMenuFactory.Menu menu = new SignMenuFactory(FluxService.get(Main.class)).newMenu(List.of("", "^^^^^^^^^^^^", "Enter the new", "name of the claim"))
+        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);

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

@@ -1,7 +1,7 @@
 package me.lethunderhawk.clans.settings;
 
 import me.lethunderhawk.fluxapi.FluxService;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 
 import java.util.EnumMap;
 import java.util.HashMap;
@@ -45,7 +45,7 @@ public final class ClanSettings {
                 ClanSetting key = ClanSetting.valueOf(entry.getKey());
                 s.set(key, (Boolean) entry.getValue());
             } catch (IllegalArgumentException e) {
-                FluxService.get(Main.class).getLogger().warning("Unknown ClanSetting: " + entry.getKey());
+                FluxService.get(BazaarFlux.class).getLogger().warning("Unknown ClanSetting: " + entry.getKey());
             }
         }
         return s;

+ 2 - 2
src/main/java/me/lethunderhawk/custom/block/registry/BlockRegistry.java

@@ -1,7 +1,7 @@
 package me.lethunderhawk.custom.block.registry;
 
 import me.lethunderhawk.fluxapi.FluxService;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import org.bukkit.Bukkit;
 import org.bukkit.World;
 import org.bukkit.block.Block;
@@ -97,7 +97,7 @@ public class BlockRegistry implements Listener {
             onDestroyLogic();
 
             regenTask = Bukkit.getScheduler().runTaskLater(
-                    FluxService.get(Main.class),
+                    FluxService.get(BazaarFlux.class),
                     this::regenerate,
                     regenTimeSeconds * 20L
             );

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

@@ -13,7 +13,7 @@ import me.lethunderhawk.custom.item.concrete.ability.*;
 import me.lethunderhawk.custom.item.listener.CustomItemListener;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.interfaces.BazaarFluxModule;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import org.bukkit.command.CommandSender;
 import org.bukkit.event.HandlerList;
 import org.bukkit.plugin.java.JavaPlugin;
@@ -50,8 +50,8 @@ public class CustomItemModule extends BazaarFluxModule {
         ItemDefinitionValidator validator = new DefaultItemDefinitionValidator();
         ItemDefinitionLoader loader = new ItemDefinitionLoader(validator);
 
-        Main main = FluxService.get(Main.class);
-        File itemsDir = new File(main.getDataFolder(), "custom/items");
+        BazaarFlux bazaarFlux = FluxService.get(BazaarFlux.class);
+        File itemsDir = new File(bazaarFlux.getDataFolder(), "custom/items");
 
         // --- Load definitions from disk ---
         Map<String, ItemDefinition> definitions = loader.loadAll(itemsDir);
@@ -65,7 +65,7 @@ public class CustomItemModule extends BazaarFluxModule {
                 new AbilityDispatchService(itemRegistry, abilityRegistry)
         );
 
-        main.getServer().getPluginManager().registerEvents(listener, main);
+        bazaarFlux.getServer().getPluginManager().registerEvents(listener, bazaarFlux);
 
         // --- FluxService ---
         FluxService.register(CustomItemRegistry.class, itemRegistry);
@@ -73,15 +73,15 @@ public class CustomItemModule extends BazaarFluxModule {
         FluxService.register(ItemDefinitionValidator.class, validator);
         FluxService.register(AbilityRegistry.class, abilityRegistry);
         BlockRegistry blockRegistry = new BlockRegistry();
-        main.getServer().getPluginManager().registerEvents(blockRegistry, main);
+        bazaarFlux.getServer().getPluginManager().registerEvents(blockRegistry, bazaarFlux);
         FluxService.register(BlockRegistry.class, blockRegistry);
         registerCommands();
     }
 
     private void registerCommands() {
         CustomItemCommand customItemCommand = new CustomItemCommand(this);
-        FluxService.get(Main.class).getCommand("customItems").setExecutor(customItemCommand);
-        FluxService.get(Main.class).getCommand("customItems").setTabCompleter(customItemCommand);
+        FluxService.get(BazaarFlux.class).getCommand("customItems").setExecutor(customItemCommand);
+        FluxService.get(BazaarFlux.class).getCommand("customItems").setTabCompleter(customItemCommand);
     }
 
     @Override

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

@@ -4,7 +4,7 @@ import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.itemdesign.LoreDesigner;
 import me.lethunderhawk.custom.item.abstraction.ability.AbilityDefinition;
 import me.lethunderhawk.custom.item.abstraction.ability.AbilityTrigger;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import net.kyori.adventure.text.Component;
 import org.bukkit.Material;
 import org.bukkit.configuration.ConfigurationSection;
@@ -160,12 +160,12 @@ public final class ItemDefinitionLoader {
                 }
 
                 if (abilityName == null) {
-                    FluxService.get(Main.class).getLogger().info("Missing ability Name in item " + id + ". Is this wanted? Using handler ID: " + handler_id + " as default.");
+                    FluxService.get(BazaarFlux.class).getLogger().info("Missing ability Name in item " + id + ". Is this wanted? Using handler ID: " + handler_id + " as default.");
                     abilityName = handler_id;
                 }
 
                 if (abilityDescription == null) {
-                    FluxService.get(Main.class).getLogger().info("Missing ability Description in item " + id + ". Is this wanted?");
+                    FluxService.get(BazaarFlux.class).getLogger().info("Missing ability Description in item " + id + ". Is this wanted?");
                 }
 
                 Map<String, String> params = new HashMap<>();

+ 5 - 5
src/main/java/me/lethunderhawk/custom/item/abstraction/instance/ItemPersistentData.java

@@ -2,22 +2,22 @@ package me.lethunderhawk.custom.item.abstraction.instance;
 
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.custom.item.abstraction.util.JsonUtil;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import org.bukkit.NamespacedKey;
 import org.bukkit.inventory.meta.ItemMeta;
 import org.bukkit.persistence.PersistentDataContainer;
 import org.bukkit.persistence.PersistentDataType;
 
 public final class ItemPersistentData {
-    private static final Main main = FluxService.get(Main.class);
+    private static final BazaarFlux bazaarFlux = FluxService.get(BazaarFlux.class);
     static final NamespacedKey ITEM_ID =
-            new NamespacedKey(main, "item_id");
+            new NamespacedKey(bazaarFlux, "item_id");
 
     static final NamespacedKey VERSION =
-            new NamespacedKey(main, "item_version");
+            new NamespacedKey(bazaarFlux, "item_version");
 
     static final NamespacedKey INSTANCE_DATA =
-            new NamespacedKey(main, "item_data");
+            new NamespacedKey(bazaarFlux, "item_data");
 
     private ItemPersistentData() {}
 

+ 2 - 2
src/main/java/me/lethunderhawk/custom/item/abstraction/registry/CustomItemRegistry.java

@@ -2,7 +2,7 @@ package me.lethunderhawk.custom.item.abstraction.registry;
 
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.custom.item.abstraction.definition.ItemDefinition;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -23,7 +23,7 @@ public class CustomItemRegistry {
 
     public ItemDefinition get(String itemId) {
         ItemDefinition definition = definitions.get(itemId);
-        if(definition == null) FluxService.get(Main.class).getLogger().warning("Item " + itemId + " not found");
+        if(definition == null) FluxService.get(BazaarFlux.class).getLogger().warning("Item " + itemId + " not found");
         return definition;
     }
 

+ 2 - 2
src/main/java/me/lethunderhawk/custom/item/concrete/ability/ClaimToolAbility.java

@@ -9,7 +9,7 @@ import me.lethunderhawk.clans.claim.ClaimManager;
 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.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.format.NamedTextColor;
 import org.bukkit.Location;
@@ -37,7 +37,7 @@ public class ClaimToolAbility implements AbilityHandler {
     }
 
     private boolean hasEnoughClaimSpace(Player player, Clan clan, Claim claim) {
-        int maxBlocks = FluxService.get(Main.class).getConfig().getInt("claims.max-blocks");
+        int maxBlocks = FluxService.get(BazaarFlux.class).getConfig().getInt("claims.max-blocks");
         int usedAfterClaim = clan.getUsedBlocks() + claim.getVolume();
 
         if (usedAfterClaim > maxBlocks) {

+ 4 - 4
src/main/java/me/lethunderhawk/dungeon/DungeonModule.java

@@ -4,7 +4,7 @@ import me.lethunderhawk.dungeon.command.DungeonCommand;
 import me.lethunderhawk.dungeon.manager.DungeonManager;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.interfaces.BazaarFluxModule;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import org.bukkit.plugin.java.JavaPlugin;
 
 public class DungeonModule extends BazaarFluxModule {
@@ -21,11 +21,11 @@ public class DungeonModule extends BazaarFluxModule {
     @Override
     public void onEnable() {
 
-        Main mainPlugin = FluxService.get(Main.class);
+        BazaarFlux bazaarFlux = FluxService.get(BazaarFlux.class);
         FluxService.register(DungeonManager.class, new DungeonManager());
 
-        mainPlugin.getCommand("dungeon").setExecutor(new DungeonCommand());
-        mainPlugin.getCommand("dungeon").setTabCompleter(new DungeonCommand());
+        bazaarFlux.getCommand("dungeon").setExecutor(new DungeonCommand());
+        bazaarFlux.getCommand("dungeon").setTabCompleter(new DungeonCommand());
     }
 
     @Override

+ 2 - 2
src/main/java/me/lethunderhawk/dungeon/command/DungeonCommand.java

@@ -6,7 +6,7 @@ import me.lethunderhawk.dungeon.manager.DungeonManager;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.command.CommandNode;
 import me.lethunderhawk.fluxapi.util.command.CustomCommand;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import org.bukkit.Bukkit;
 import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
@@ -69,7 +69,7 @@ public class DungeonCommand extends CustomCommand {
 
         // Optional: auto-delete dungeon if empty
         Bukkit.getScheduler().runTaskLater(
-                FluxService.get(Main.class),
+                FluxService.get(BazaarFlux.class),
                 () -> {
                     if (player.getWorld().getPlayers().isEmpty()) {
                         manager.deleteDungeon(dungeon.getUUID());

+ 6 - 6
src/main/java/me/lethunderhawk/dungeon/generation/DungeonGridGenerator.java

@@ -3,7 +3,7 @@ package me.lethunderhawk.dungeon.generation;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.world.util.schematic.Rotation;
 import me.lethunderhawk.dungeon.placement.SchematicRoomPlacer;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import org.bukkit.Location;
 import org.bukkit.Material;
 import org.bukkit.World;
@@ -804,15 +804,15 @@ public class DungeonGridGenerator {
         String strType = type.toString();
         int randomInt = random.nextInt(4);
         if(connectionType == ConnectionType.SINGLE){
-            return new File(FluxService.get(Main.class).getDataFolder(), "rooms/single_entrance/" + strType + randomInt +".schem");
+            return new File(FluxService.get(BazaarFlux.class).getDataFolder(), "rooms/single_entrance/" + strType + randomInt +".schem");
         }else if(connectionType == ConnectionType.STRAIGHT){
-            return new File(FluxService.get(Main.class).getDataFolder(), "rooms/straight/" + strType + randomInt +".schem");
+            return new File(FluxService.get(BazaarFlux.class).getDataFolder(), "rooms/straight/" + strType + randomInt +".schem");
         }else if(connectionType == ConnectionType.T){
-            return new File(FluxService.get(Main.class).getDataFolder(), "rooms/T_connection/" + strType + randomInt +".schem");
+            return new File(FluxService.get(BazaarFlux.class).getDataFolder(), "rooms/T_connection/" + strType + randomInt +".schem");
         }else if(connectionType == ConnectionType.TURN_LEFT){
-            return new File(FluxService.get(Main.class).getDataFolder(), "rooms/turn_left/" + strType + randomInt +".schem");
+            return new File(FluxService.get(BazaarFlux.class).getDataFolder(), "rooms/turn_left/" + strType + randomInt +".schem");
         }else if(connectionType == ConnectionType.HUB){
-            return new File(FluxService.get(Main.class).getDataFolder(), "rooms/hubs/" + strType + randomInt +".schem");
+            return new File(FluxService.get(BazaarFlux.class).getDataFolder(), "rooms/hubs/" + strType + randomInt +".schem");
         }
         return null;
     }

+ 2 - 2
src/main/java/me/lethunderhawk/dungeon/generation/DungeonWorld.java

@@ -2,7 +2,7 @@ package me.lethunderhawk.dungeon.generation;
 
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.dungeon.manager.DungeonManager;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import org.bukkit.*;
 import org.bukkit.entity.Player;
 import org.bukkit.event.EventHandler;
@@ -23,7 +23,7 @@ public class DungeonWorld implements Listener {
     private final Map<UUID, Location> returnLocations = new HashMap<>();
 
     public DungeonWorld() {
-        this.plugin = FluxService.get(Main.class);
+        this.plugin = FluxService.get(BazaarFlux.class);
         this.uuid  = UUID.randomUUID();
 
         Bukkit.getPluginManager().registerEvents(this, plugin);

+ 1 - 1
src/main/java/me/lethunderhawk/economy/EconomyModule.java

@@ -5,7 +5,7 @@ import me.lethunderhawk.economy.api.EconomyPlaceholder;
 import me.lethunderhawk.economy.command.EcoCommand;
 import me.lethunderhawk.economy.currency.EconomyManager;
 import me.lethunderhawk.economy.listener.PlayerJoinListener;
-import me.lethunderhawk.economy.scoreboard.ScoreboardManager;
+import me.lethunderhawk.scoreboard.ScoreboardManager;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.interfaces.BazaarFluxModule;
 import me.lethunderhawk.tradeplugin.api.TradePlaceholder;

+ 1 - 1
src/main/java/me/lethunderhawk/economy/listener/PlayerJoinListener.java

@@ -1,6 +1,6 @@
 package me.lethunderhawk.economy.listener;
 
-import me.lethunderhawk.economy.scoreboard.ScoreboardManager;
+import me.lethunderhawk.scoreboard.ScoreboardManager;
 import org.bukkit.event.EventHandler;
 import org.bukkit.event.Listener;
 import org.bukkit.event.player.PlayerJoinEvent;

+ 2 - 2
src/main/java/me/lethunderhawk/main/Main.java → src/main/java/me/lethunderhawk/main/BazaarFlux.java

@@ -15,12 +15,12 @@ import org.bukkit.plugin.java.JavaPlugin;
 import java.util.ArrayList;
 import java.util.List;
 
-public class Main extends JavaPlugin{
+public class BazaarFlux extends JavaPlugin{
 
     private final List<BazaarFluxModule> bazaarFluxModules = new ArrayList<>();
     @Override
     public void onEnable() {
-        FluxService.register(Main.class, this);
+        FluxService.register(BazaarFlux.class, this);
 
         InventoryManager.register(this);
         registerAllModules(new CustomItemModule(this), new TradeModule(this), new ClanModule(this), new EconomyModule(this), new MinionModule(this), new DungeonModule(this), new WorldModule(this));

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

@@ -2,7 +2,7 @@ package me.lethunderhawk.minion;
 
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.interfaces.BazaarFluxModule;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import me.lethunderhawk.minion.command.MinionCommand;
 import me.lethunderhawk.minion.enchantedVariant.item.EnchantedCobblestone;
 import me.lethunderhawk.minion.enchantedVariant.item.EnchantedRedstone;
@@ -63,7 +63,7 @@ public class MinionModule extends BazaarFluxModule {
 
     private void customRecipes() {
 
-        this.recipeManager = new RecipeManager(FluxService.get(Main.class));
+        this.recipeManager = new RecipeManager(FluxService.get(BazaarFlux.class));
         plugin.getServer().getPluginManager().registerEvents(new DisableEnchantedItemPlacingListener(), plugin);
 
         registerRecipes();

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

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

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

@@ -1,7 +1,7 @@
 package me.lethunderhawk.minion.enchantedVariant.item.abstraction;
 
 import me.lethunderhawk.fluxapi.FluxService;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import me.lethunderhawk.fluxapi.util.UnItalic;
 import net.kyori.adventure.text.Component;
 import org.bukkit.Material;
@@ -31,7 +31,7 @@ public abstract class EnchantedItem {
         this.lore = lore;
         this.baseMaterial = baseMaterial;
         this.itemId = itemId;
-        this.itemIdKey = new NamespacedKey(FluxService.get(Main.class), itemId);
+        this.itemIdKey = new NamespacedKey(FluxService.get(BazaarFlux.class), itemId);
         this.itemStack = createItem();
     }
 

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

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

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

@@ -3,7 +3,7 @@ package me.lethunderhawk.minion.item;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.CustomHeadCreator;
 import me.lethunderhawk.fluxapi.util.lang.RomanNumbers;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import me.lethunderhawk.fluxapi.util.UnItalic;
 import me.lethunderhawk.minion.api.MinionType;
 import me.lethunderhawk.minion.registry.MinionRegistry;
@@ -23,7 +23,7 @@ public class MinionItem {
     private final NamespacedKey levelKey;
 
     public MinionItem() {
-        Main plugin = FluxService.get(Main.class);
+        BazaarFlux plugin = FluxService.get(BazaarFlux.class);
         this.typeKey = new NamespacedKey(plugin, "minion_type");
         this.levelKey = new NamespacedKey(plugin, "minion_level");
     }

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

@@ -3,7 +3,7 @@ package me.lethunderhawk.minion.ui;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.gui.InventoryGUI;
 import me.lethunderhawk.fluxapi.util.gui.InventoryManager;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import me.lethunderhawk.fluxapi.util.UnItalic;
 import me.lethunderhawk.minion.api.MinionLevelData;
 import me.lethunderhawk.minion.manager.MinionManager;
@@ -58,7 +58,7 @@ public class MinionMenu extends InventoryGUI implements InventoryGUI.AutoCloseHa
         ItemStack upgradeItem = buildQuickUpgradeItem();
         setItemWithClickAction(50, upgradeItem, (p, type) -> {
 
-            JavaPlugin plugin = FluxService.get(Main.class);
+            JavaPlugin plugin = FluxService.get(BazaarFlux.class);
             PlacedMinion newMinion = minion.getUpgrade(plugin);
             if(newMinion != null) {
                 MinionManager.stopAndUnregister(minion);

+ 1 - 1
src/main/java/me/lethunderhawk/economy/scoreboard/ScoreboardManager.java → src/main/java/me/lethunderhawk/scoreboard/ScoreboardManager.java

@@ -1,4 +1,4 @@
-package me.lethunderhawk.economy.scoreboard;
+package me.lethunderhawk.scoreboard;
 
 import me.lethunderhawk.economy.EconomyModule;
 import org.bukkit.Bukkit;

+ 2 - 1
src/main/java/me/lethunderhawk/economy/scoreboard/ScoreboardTemplate.java → src/main/java/me/lethunderhawk/scoreboard/ScoreboardTemplate.java

@@ -1,4 +1,4 @@
-package me.lethunderhawk.economy.scoreboard;
+package me.lethunderhawk.scoreboard;
 
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
@@ -61,6 +61,7 @@ public class ScoreboardTemplate {
     private Component colorize(String s) {
         return LegacyComponentSerializer.legacyAmpersand().deserialize(s);
     }
+
     private String replacePlaceholders(String text, Player p) {
         if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
             return me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(p, text);

+ 2 - 2
src/main/java/me/lethunderhawk/tradeplugin/listener/TradeInventoryListener.java

@@ -4,7 +4,7 @@ import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.gui.input.SignMenuFactory;
 import me.lethunderhawk.economy.api.EconomyAPI;
 import me.lethunderhawk.economy.util.EconomyUtil;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import me.lethunderhawk.tradeplugin.TradeModule;
 import me.lethunderhawk.tradeplugin.trade.TradeInventory;
 import me.lethunderhawk.tradeplugin.trade.TradeManager;
@@ -107,7 +107,7 @@ public class TradeInventoryListener implements Listener {
     }
 
     private void openSignMenu(Player p) {
-        SignMenuFactory.Menu signInput = new SignMenuFactory(FluxService.get(Main.class)).newMenu(List.of("", "^^^^^^^^^^^^", "Input the amount", "to trade"))
+        SignMenuFactory.Menu signInput = new SignMenuFactory(FluxService.get(BazaarFlux.class)).newMenu(List.of("", "^^^^^^^^^^^^", "Input the amount", "to trade"))
                 .reopenIfFail(true)
                 .response((player, input) -> {
                     long value = EconomyUtil.longFromString(input[0]);

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

@@ -1,7 +1,7 @@
 package me.lethunderhawk.tradeplugin.trade;
 
 import me.lethunderhawk.fluxapi.FluxService;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import me.lethunderhawk.tradeplugin.TradeModule;
 import net.kyori.adventure.key.Key;
 import net.kyori.adventure.sound.Sound;
@@ -77,7 +77,7 @@ public class TradeRequestManager {
             );
 
             int task = Bukkit.getScheduler().scheduleSyncDelayedTask(
-                    FluxService.get(Main.class),
+                    FluxService.get(BazaarFlux.class),
                     () -> {
                         if (isPending(target, sender)) {
                             requests.remove(target.getUniqueId());

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

@@ -3,7 +3,7 @@ package me.lethunderhawk.tradeplugin.trade;
 import me.clip.placeholderapi.PlaceholderAPI;
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.economy.api.EconomyAPI;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import me.lethunderhawk.fluxapi.util.UnItalic;
 import me.lethunderhawk.tradeplugin.TradeModule;
 import net.kyori.adventure.audience.Audience;
@@ -30,11 +30,11 @@ public class TradeSession {
     private final List<ItemStack> p1Items = new ArrayList<>();
     private final List<ItemStack> p2Items = new ArrayList<>();
     private static final NamespacedKey FLUX_KEY =
-            new NamespacedKey(FluxService.get(Main.class), "flux_item");
+            new NamespacedKey(FluxService.get(BazaarFlux.class), "flux_item");
     private static final NamespacedKey OWNER_KEY =
-            new NamespacedKey(FluxService.get(Main.class), "flux_owner");
+            new NamespacedKey(FluxService.get(BazaarFlux.class), "flux_owner");
     private static final NamespacedKey VALUE_KEY =
-            new NamespacedKey(FluxService.get(Main.class), "flux_value");
+            new NamespacedKey(FluxService.get(BazaarFlux.class), "flux_value");
 
     private TradeState state = TradeState.WAITING;
     private long p1Flux = 0, p2Flux = 0;

+ 26 - 23
src/main/java/me/lethunderhawk/world/WorldModule.java

@@ -2,10 +2,10 @@ package me.lethunderhawk.world;
 
 import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.interfaces.BazaarFluxModule;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import me.lethunderhawk.world.command.WorldCommand;
 import me.lethunderhawk.world.island.IslandBootstrapListener;
-import me.lethunderhawk.world.util.WorldManager;
+import me.lethunderhawk.world.manager.NestedWorldStorageManager;
 import org.bukkit.event.HandlerList;
 import org.bukkit.plugin.java.JavaPlugin;
 
@@ -22,42 +22,45 @@ public class WorldModule extends BazaarFluxModule {
 
     @Override
     public String getPrefix() {
-        return "[World]";
+        return "";
     }
 
     @Override
     public void onEnable() {
-        // Ordner im Server-Verzeichnis erstellen
-        Main main = FluxService.get(Main.class);
-        //dungeonsFolder = new File(main.getServer().getWorldContainer(), "dungeons");
-        //private File dungeonsFolder;
-        File islandsFolder = new File(main.getServer().getWorldContainer(), "islands");
-
-        /*if (!dungeonsFolder.exists()) {
-            dungeonsFolder.mkdirs();
-        }*/
+        BazaarFlux bazaarFlux = FluxService.get(BazaarFlux.class);
+
+        initWorldStorage();
+        /*File islandsFolder = new File(bazaarFlux.getServer().getWorldContainer(), "islands");
 
         if (!islandsFolder.exists()) {
             islandsFolder.mkdirs();
-        }
-        WorldManager worldManager = new WorldManager();
-        FluxService.register(WorldManager.class, worldManager);
+        }*/
+        /*WorldManager worldManager = new WorldManager();
+        FluxService.register(WorldManager.class, worldManager);*/
+
+        bazaarFlux.getLogger().info("World folders initialized!");
+        registerCommands(bazaarFlux);
+
+        registerBootsTrapper(bazaarFlux);
+    }
 
-        main.getLogger().info("World folders initialized!");
-        registerCommands(main);
+    private void initWorldStorage() {
+        NestedWorldStorageManager manager = new NestedWorldStorageManager();
+        FluxService.register(NestedWorldStorageManager.class, manager);
 
-        registerBootsTrapper(main);
+        manager.registerCategory("islands");
+        manager.registerCategory("dungeons");
     }
 
-    private void registerBootsTrapper(Main main) {
-        File file = new File(main.getDataFolder() + "/island", "default_island.schem");
+    private void registerBootsTrapper(BazaarFlux bazaarFlux) {
+        File file = new File(bazaarFlux.getDataFolder() + "/island", "default_island.schem");
         this.bootstrapListener = new IslandBootstrapListener(file);
-        main.getServer().getPluginManager().registerEvents(bootstrapListener, main);
+        bazaarFlux.getServer().getPluginManager().registerEvents(bootstrapListener, bazaarFlux);
     }
 
-    private void registerCommands(Main main) {
+    private void registerCommands(BazaarFlux bazaarFlux) {
         WorldCommand worldCommand = new WorldCommand(this);
-        Objects.requireNonNull(main.getCommand("warp")).setExecutor(worldCommand);
+        Objects.requireNonNull(bazaarFlux.getCommand("world")).setExecutor(worldCommand);
     }
 
     @Override

+ 26 - 0
src/main/java/me/lethunderhawk/world/abstraction/WorldStorageManager.java

@@ -0,0 +1,26 @@
+package me.lethunderhawk.world.abstraction;
+
+import org.bukkit.World;
+import org.bukkit.WorldCreator;
+
+import java.util.List;
+import java.util.function.Consumer;
+
+public interface WorldStorageManager {
+
+    void registerCategory(String folderName);
+
+    List<String> listWorlds(String folderName);
+
+    World createWorld(
+            String folderName,
+            String worldName,
+            Consumer<WorldCreator> creatorCustomizer
+    );
+
+    void unloadWorld(String folderName, String worldName, boolean save);
+
+    void deleteWorld(String folderName, String worldName);
+
+    boolean worldExists(String folderName, String worldName);
+}

+ 29 - 10
src/main/java/me/lethunderhawk/world/command/WorldCommand.java

@@ -4,8 +4,10 @@ import me.lethunderhawk.fluxapi.FluxService;
 import me.lethunderhawk.fluxapi.util.command.CommandNode;
 import me.lethunderhawk.fluxapi.util.command.CustomCommand;
 import me.lethunderhawk.fluxapi.util.interfaces.BazaarFluxModule;
-import me.lethunderhawk.main.Main;
-import me.lethunderhawk.world.util.WorldManager;
+import me.lethunderhawk.main.BazaarFlux;
+import me.lethunderhawk.world.manager.NestedWorldStorageManager;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
 import org.bukkit.Bukkit;
 import org.bukkit.Location;
 import org.bukkit.World;
@@ -20,7 +22,7 @@ public class WorldCommand extends CustomCommand {
     private Map<String, Location> locations = new HashMap<>();
 
     public WorldCommand(BazaarFluxModule module) {
-        super(new CommandNode("warp", "Hop between worlds!", null), module);
+        super(new CommandNode("world", "Hop between worlds!", null), module);
         populateLocationMap();
     }
 
@@ -28,6 +30,7 @@ public class WorldCommand extends CustomCommand {
         locations.clear();
         initMatchingWorldLocationFromSpawn("hub", "world");
     }
+
     private void initMatchingWorldLocationFromSpawn(String... worldNames){
         for(String worldName : worldNames){
             initMatchingWorldLocationFromSpawn(worldName);
@@ -37,7 +40,7 @@ public class WorldCommand extends CustomCommand {
     private void initMatchingWorldLocationFromSpawn(String worldName) {
         World world =  Bukkit.getWorld(worldName);
         if(world == null){
-            FluxService.get(Main.class).getLogger().warning("World not found: " + worldName);
+            FluxService.get(BazaarFlux.class).getLogger().warning("World not found: " + worldName);
             return;
         }
         Location worldLoc = world.getBlockAt(0,100,0).getLocation();
@@ -48,15 +51,20 @@ public class WorldCommand extends CustomCommand {
     @Override
     public void createCommands() {
         registerCommand("island", "Warp to your island", this::warpToIsland);
-        registerCommand("back", "Warp back from the island", this::warpBack);
+        registerCommand("overworld", "Warp to the overworld", this::warpOverworld);
         registerCommand("reload", "Reload this module", this::reload);
         registerCommand("deleteIslands", "delete all worlds in island folder", this::deleteAllIslands);
         registerAllDefaultWorldCommands();
     }
 
     private void deleteAllIslands(CommandSender sender, String[] strings) {
+        NestedWorldStorageManager manager = FluxService.get(NestedWorldStorageManager.class);
+        for(String worldFolder : manager.listWorlds("islands")){
+            manager.deleteWorld("islands", worldFolder);
+        }
     }
 
+
     private void reload(CommandSender sender, String[] strings) {
         module.reload(sender, strings);
     }
@@ -80,13 +88,24 @@ public class WorldCommand extends CustomCommand {
         p.teleport(location);
     }
 
-    private void warpBack(CommandSender sender, String[] strings) {
+    private void warpOverworld(CommandSender sender, String[] strings) {
         if(!(sender instanceof Player player)) return;
-        FluxService.get(WorldManager.class).warpBackFromIsland(player);
+        FluxService.get(NestedWorldStorageManager.class).warpToWorld(player,"world");
     }
 
-    private void warpToIsland(CommandSender sender, String[] strings) {
-        if(!(sender instanceof Player player)) return;
-        FluxService.get(WorldManager.class).warpToIsland(player);
+    private void warpToIsland(CommandSender sender, String[] args) {
+        if (!(sender instanceof Player player)) return;
+
+        NestedWorldStorageManager manager = FluxService.get(NestedWorldStorageManager.class);
+        String worldName = "island_" + player.getName();
+
+        World world = manager.loadIfExists("islands", worldName);
+
+        if (world == null) {
+            module.sendText(player, Component.text("You are new here! Let us create an island first...", NamedTextColor.GREEN));
+            world = manager.createIslandWorld(worldName);
+        }
+        module.sendText(player, Component.text("Warping to island...", NamedTextColor.GREEN));
+        player.teleportAsync(world.getSpawnLocation());
     }
 }

+ 36 - 24
src/main/java/me/lethunderhawk/world/island/IslandBootstrapListener.java

@@ -1,15 +1,9 @@
 package me.lethunderhawk.world.island;
 
-import me.lethunderhawk.world.util.schematic.Rotation;
-import me.lethunderhawk.world.util.schematic.SchematicPlacer;
-import org.bukkit.Location;
 import org.bukkit.NamespacedKey;
-import org.bukkit.World;
 import org.bukkit.event.EventHandler;
 import org.bukkit.event.Listener;
 import org.bukkit.event.world.WorldLoadEvent;
-import org.bukkit.persistence.PersistentDataContainer;
-import org.bukkit.persistence.PersistentDataType;
 
 import java.io.File;
 
@@ -26,23 +20,41 @@ public final class IslandBootstrapListener implements Listener {
 
     @EventHandler
     public void onWorldLoad(WorldLoadEvent event) {
-        System.out.println("loading " + event.getWorld().getName());
-        World world = event.getWorld();
-
-        PersistentDataContainer pdc = world.getPersistentDataContainer();
-        //if (pdc.has(GENERATED_KEY, PersistentDataType.BYTE)) return;
-
-        Location spawn = new Location(world, 0, 100, 0);
-
-        boolean success = SchematicPlacer.place(
-                schematicFile,
-                world,
-                spawn,
-                Rotation.NONE
-        );
-
-        if (success) {
-            pdc.set(GENERATED_KEY, PersistentDataType.BYTE, (byte) 1);
-        }
+        /*World world = event.getWorld();
+        if(world.getWorldFolder().getParent().startsWith("island")){
+            PersistentDataContainer pdc = world.getPersistentDataContainer();
+
+            Location spawn = new Location(world, 0.5, 100, 0.5);
+            world.setSpawnLocation(spawn);
+            boolean success = SchematicPlacer.place(
+                    schematicFile,
+                    world,
+                    spawn,
+                    Rotation.NONE
+            );
+
+            if (success) {
+                pdc.set(GENERATED_KEY, PersistentDataType.BYTE, (byte) 1);
+            }
+            NPCOptions options = new NPCOptions()
+                    .setLocation(spawn)
+                    .setName("Local Guide")
+                    .setLookingAtNearest(true);
+
+            NPC npc = new NPC(options){
+                @Override
+                public void onLeftClick(Player player) {
+                    player.sendMessage("<"+this.getName()+">Im your guide for now!");
+                    player.sendMessage("<"+this.getName()+">Still a lot of work ahead though!");
+                }
+
+                @Override
+                public void onRightClick(Player player) {
+                    onLeftClick(player);
+                }
+            };
+            npc.register();
+
+        }*/
     }
 }

+ 2 - 2
src/main/java/me/lethunderhawk/world/island/IslandWorld.java

@@ -1,7 +1,7 @@
 package me.lethunderhawk.world.island;
 
 import me.lethunderhawk.fluxapi.FluxService;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import org.bukkit.*;
 import org.bukkit.generator.ChunkGenerator;
 
@@ -26,7 +26,7 @@ public final class IslandWorld {
         World world = creator.createWorld();
 
         if (world != null) {
-            FluxService.get(Main.class).getLogger().info("World " + worldName + " created in " + folderName);
+            FluxService.get(BazaarFlux.class).getLogger().info("World " + worldName + " created in " + folderName);
 
             world.setGameRule(GameRule.DO_MOB_SPAWNING, false);
             world.setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false);

+ 270 - 0
src/main/java/me/lethunderhawk/world/manager/NestedWorldStorageManager.java

@@ -0,0 +1,270 @@
+package me.lethunderhawk.world.manager;
+
+import me.lethunderhawk.fluxapi.FluxService;
+import me.lethunderhawk.main.BazaarFlux;
+import me.lethunderhawk.npc.abstraction.NPC;
+import me.lethunderhawk.npc.abstraction.NPCOptions;
+import me.lethunderhawk.world.abstraction.WorldStorageManager;
+import me.lethunderhawk.world.island.IslandWorld;
+import me.lethunderhawk.world.util.schematic.Rotation;
+import me.lethunderhawk.world.util.schematic.SchematicPlacer;
+import org.bukkit.*;
+import org.bukkit.block.Biome;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
+import org.bukkit.persistence.PersistentDataContainer;
+import org.bukkit.persistence.PersistentDataType;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+public final class NestedWorldStorageManager implements WorldStorageManager {
+
+    private final File serverRoot;
+    private final Set<String> categories = new HashSet<>();
+    private static final NamespacedKey GENERATED_KEY =
+            new NamespacedKey("bazaarflux", "island_generated");
+    File islandFile = new File(FluxService.get(BazaarFlux.class).getDataFolder() + "/island", "default_island.schem");
+
+    public NestedWorldStorageManager() {
+        this.serverRoot = Bukkit.getWorldContainer();
+    }
+
+    // -------------------------------------------------
+    // Category Registration
+    // -------------------------------------------------
+
+    @Override
+    public void registerCategory(String folderName) {
+        File folder = new File(serverRoot, folderName);
+
+        if (!folder.exists() && !folder.mkdirs()) {
+            throw new IllegalStateException("Could not create folder: " + folderName);
+        }
+
+        categories.add(folderName);
+    }
+
+    private void validateCategory(String folderName) {
+        if (!categories.contains(folderName)) {
+            throw new IllegalArgumentException("Category not registered: " + folderName);
+        }
+    }
+
+    private String buildPath(String folderName, String worldName) {
+        return folderName + "/" + worldName;
+    }
+
+    // -------------------------------------------------
+    // List Worlds
+    // -------------------------------------------------
+
+    @Override
+    public List<String> listWorlds(String folderName) {
+        validateCategory(folderName);
+
+        File folder = new File(serverRoot, folderName);
+        File[] sub = folder.listFiles(File::isDirectory);
+
+        if (sub == null) return List.of();
+
+        return Arrays.stream(sub)
+                .map(File::getName)
+                .toList();
+    }
+
+    // -------------------------------------------------
+    // Create World
+    // -------------------------------------------------
+
+    @Override
+    public World createWorld(
+            String folderName,
+            String worldName,
+            Consumer<WorldCreator> creatorCustomizer
+    ) {
+        validateCategory(folderName);
+
+        String fullPath = buildPath(folderName, worldName);
+
+        if (Bukkit.getWorld(fullPath) != null) {
+            throw new IllegalStateException("World already loaded: " + fullPath);
+        }
+
+        WorldCreator creator = new WorldCreator(fullPath);
+        creatorCustomizer.accept(creator);
+        creator.seed(0);
+        creator.generateStructures(false);
+        creator.generatorSettings("{}");
+        creator.biomeProvider(Biome.THE_VOID.translationKey());
+
+        World world = creator.createWorld();
+
+        if (world == null) {
+            throw new IllegalStateException("Failed to create world: " + fullPath);
+        }
+        setDefaultSmallOptionsForWorld(world);
+
+        return world;
+    }
+
+    private void setDefaultSmallOptionsForWorld(World world) {
+        world.setAutoSave(false);
+        world.setGameRule(GameRule.DO_MOB_SPAWNING, false);
+        world.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
+        world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
+        world.setGameRule(GameRule.RANDOM_TICK_SPEED, 0);
+        world.setGameRule(GameRule.KEEP_INVENTORY, true);
+        world.setVoidDamageAmount(1000f);
+        world.setVoidDamageMinBuildHeightOffset(64);
+    }
+
+    // -------------------------------------------------
+    // Unload
+    // -------------------------------------------------
+
+    @Override
+    public void unloadWorld(String folderName, String worldName, boolean save) {
+        validateCategory(folderName);
+
+        String fullPath = buildPath(folderName, worldName);
+        World world = Bukkit.getWorld(fullPath);
+
+        if (world == null) return;
+
+        if (!Bukkit.unloadWorld(world, save)) {
+            throw new IllegalStateException("Could not unload world: " + fullPath);
+        }
+    }
+
+    // -------------------------------------------------
+    // Delete
+    // -------------------------------------------------
+
+    @Override
+    public void deleteWorld(String folderName, String worldName) {
+        validateCategory(folderName);
+
+        String fullPath = buildPath(folderName, worldName);
+
+        // Safety: prevent deleting default worlds
+        if (worldName.equalsIgnoreCase("world")
+                || worldName.equalsIgnoreCase("world_nether")
+                || worldName.equalsIgnoreCase("world_the_end")) {
+            throw new IllegalStateException("Refusing to delete default worlds.");
+        }
+
+        unloadWorld(folderName, worldName, false);
+
+        File worldFolder = new File(serverRoot, fullPath);
+
+        if (!worldFolder.exists()) return;
+
+        deleteDirectory(worldFolder.toPath());
+    }
+
+    @Override
+    public boolean worldExists(String folderName, String worldName) {
+        validateCategory(folderName);
+
+        File worldFolder = new File(serverRoot, buildPath(folderName, worldName));
+        return worldFolder.exists();
+    }
+
+    public World createIslandWorld(String playerUUID) {
+        World world = createWorld("islands", playerUUID, creator -> {
+            creator.environment(World.Environment.NORMAL);
+            creator.type(WorldType.NORMAL);
+            creator.generateStructures(false);
+            creator.generator(new IslandWorld.EmptyChunkGenerator());
+        });
+
+        PersistentDataContainer pdc = world.getPersistentDataContainer();
+
+        Location spawn = new Location(world, 0.5, 100, 0.5);
+        world.setSpawnLocation(spawn);
+
+        boolean success = SchematicPlacer.place(
+                islandFile,
+                world,
+                spawn,
+                Rotation.NONE
+        );
+
+        if (success) {
+            pdc.set(GENERATED_KEY, PersistentDataType.BYTE, (byte) 1);
+            FluxService.get(BazaarFlux.class).getLogger().info("Created island in world: " + world.getName());
+        }
+        NPCOptions options = new NPCOptions()
+                .setLocation(spawn)
+                .setName("Local Guide")
+                .setLookingAtNearest(true)
+                .setEntityType(EntityType.VILLAGER)
+                .setLocation(spawn.add(-2, 0, 0));
+
+        NPC npc = new NPC(options){
+            @Override
+            public void onLeftClick(Player player) {
+                player.sendMessage("<"+this.getName()+"> Im your guide for now!");
+                player.sendMessage("<"+this.getName()+"> Still a lot of work ahead though!");
+            }
+
+            @Override
+            public void onRightClick(Player player) {
+                onLeftClick(player);
+            }
+        };
+        npc.register();
+
+        return world;
+    }
+
+    public World getWorld(String folderName, String worldName) {
+        validateCategory(folderName);
+        return Bukkit.getWorld(buildPath(folderName, worldName));
+    }
+
+    public World loadIfExists(String folderName, String worldName) {
+        validateCategory(folderName);
+
+        String fullPath = buildPath(folderName, worldName);
+
+        // Already loaded
+        World loaded = Bukkit.getWorld(fullPath);
+        if (loaded != null) return loaded;
+
+        // Exists on disk?
+        File folder = new File(serverRoot, fullPath);
+        if (!folder.exists()) return null;
+
+        return new WorldCreator(fullPath).createWorld();
+    }
+
+    // -------------------------------------------------
+    // File Utilities
+    // -------------------------------------------------
+
+    private void deleteDirectory(Path path) {
+        try (Stream<Path> walk = Files.walk(path)) {
+            walk.sorted(Comparator.reverseOrder())
+                    .forEach(p -> {
+                        try {
+                            Files.deleteIfExists(p);
+                        } catch (IOException e) {
+                            throw new RuntimeException("Failed deleting: " + p, e);
+                        }
+                    });
+        } catch (IOException e) {
+            throw new RuntimeException("Delete failed: " + path, e);
+        }
+    }
+
+    public void warpToWorld(Player player, String world) {
+        player.teleport(Bukkit.getWorld(world).getSpawnLocation());
+    }
+}

+ 38 - 0
src/main/java/me/lethunderhawk/world/util/DirectoryUtils.java

@@ -0,0 +1,38 @@
+package me.lethunderhawk.world.util;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Stream;
+
+public final class DirectoryUtils {
+
+    private DirectoryUtils() {}
+
+    public static List<Path> getSubDirectories(Path parent) {
+        try (Stream<Path> stream = Files.list(parent)) {
+            return stream
+                    .filter(Files::isDirectory)
+                    .toList();
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to list directories in " + parent, e);
+        }
+    }
+
+    public static void deleteRecursively(Path path) {
+        try (Stream<Path> walk = Files.walk(path)) {
+            walk.sorted(Comparator.reverseOrder())
+                    .forEach(p -> {
+                        try {
+                            Files.deleteIfExists(p);
+                        } catch (IOException e) {
+                            throw new RuntimeException("Failed deleting: " + p, e);
+                        }
+                    });
+        } catch (IOException e) {
+            throw new RuntimeException("Failed walking directory: " + path, e);
+        }
+    }
+}

+ 40 - 3
src/main/java/me/lethunderhawk/world/util/WorldManager.java

@@ -1,7 +1,7 @@
 package me.lethunderhawk.world.util;
 
 import me.lethunderhawk.fluxapi.FluxService;
-import me.lethunderhawk.main.Main;
+import me.lethunderhawk.main.BazaarFlux;
 import me.lethunderhawk.world.wrapper.CustomWorld;
 import org.bukkit.Bukkit;
 import org.bukkit.World;
@@ -9,13 +9,14 @@ import org.bukkit.WorldCreator;
 import org.bukkit.entity.Player;
 
 import java.io.File;
+import java.util.logging.Logger;
 
 public class WorldManager {
 
-    private final Main plugin;
+    private final BazaarFlux plugin;
 
     public WorldManager() {
-        this.plugin = FluxService.get(Main.class);
+        this.plugin = FluxService.get(BazaarFlux.class);
     }
 
     public CustomWorld getOrCreateIslandWorld(Player player) {
@@ -57,6 +58,42 @@ public class WorldManager {
         cWorld.warpBack(player);
     }
 
+    public void cleanWorlds(String worldsFolderName) {
+        File[] subFolders = getSubWorldFolders(worldsFolderName);
+        Logger logger = FluxService.get(BazaarFlux.class).getLogger();
+
+
+
+        for (File folder : subFolders) {
+            logger.info("Deleting world folder: " + folder.getName());
+            World world = Bukkit.getWorld(worldsFolderName + "/" + folder.getName());
+            if (world != null) {
+                Bukkit.unloadWorld(world, false);
+            }
+
+            if(!folder.delete()){
+                logger.info("Error occurred whilst deleting world folder: " + folder.getName());
+            }
+        }
+        logger.info("End of cleaning worlds");
+    }
+
+    public File[] getSubWorldFolders(String worldsFolderName) {
+        File serverRoot = Bukkit.getWorldContainer();
+        File islandsFolder = new File(serverRoot, worldsFolderName);
+        Logger logger = FluxService.get(BazaarFlux.class).getLogger();
+
+        if (!islandsFolder.exists() || !islandsFolder.isDirectory()) {
+            logger.warning("Folder \""+ worldsFolderName +"\" does not exist.");
+            return null;
+        }
+
+        File[] subFolders = islandsFolder.listFiles(File::isDirectory);
+        if (subFolders == null) return null;
+
+        return subFolders;
+    }
+
     /*public List<World> getDungeonWorlds() {
         List<World> dungeons = new ArrayList<>();
         File dungeonsDir = new File(plugin.getServer().getWorldContainer(), "dungeons");

+ 7 - 14
src/main/resources/plugin.yml

@@ -1,6 +1,6 @@
-name: BazaarFlux
-version: '${project.version}'
-main: me.lethunderhawk.main.Main
+name: ${project.artifactId}
+version: ${project.version}
+main: me.lethunderhawk.main.BazaarFlux
 api-version: 1.21.10
 prefix: BazaarFlux
 depend:
@@ -29,25 +29,18 @@ commands:
     description: Dungeons command
     usage: /dungeon
     permission: dungeons.commands
-  warp:
+  world:
     description: Warping between worlds
-    usage: /warp
-    permission: warp.commands
-  npc:
-    description: The base NPC command
-    usage: /npc
-    permission: npc.commands
+    usage: /world
+    permission: world.commands
 
 permissions:
   minion.commands:
     description: Allows use of Minion commands
     default: op
-  warp.commands:
+  world.commands:
     description: Allows use of warping commands
     default: op
-  npc.commands:
-    description: Allows use of npc commands
-    default: op
   customItem.commands:
     description: Allows use of custom Items commands
     default: op