From 648316468043dfd2610acc22be18b07b665c7599 Mon Sep 17 00:00:00 2001 From: Martin Sulikowski Date: Fri, 19 Sep 2025 23:20:55 +0200 Subject: [PATCH 1/7] GH-959 Move warp contents from language files. --- ...ove_WarpInventory_to_dedicated_config.java | 21 +++ .../configuration/migrations/Migrations.java | 3 +- .../feature/warp/command/DelWarpCommand.java | 2 +- .../feature/warp/command/SetWarpCommand.java | 2 +- .../feature/warp/command/WarpCommand.java | 2 +- .../warp/{ => inventory}/WarpInventory.java | 160 +++++++++--------- .../warp/inventory/WarpInventoryConfig.java | 97 +++++++++++ .../inventory/WarpInventoryConfigService.java | 66 ++++++++ .../inventory/WarpInventoryRepository.java | 18 ++ .../WarpInventoryRepositoryImpl.java | 78 +++++++++ .../feature/warp/messages/ENWarpMessages.java | 49 ------ .../feature/warp/messages/PLWarpMessages.java | 51 ------ .../feature/warp/messages/WarpMessages.java | 53 ------ 13 files changed, 367 insertions(+), 235 deletions(-) create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0010_Move_WarpInventory_to_dedicated_config.java rename eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/{ => inventory}/WarpInventory.java (60%) create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0010_Move_WarpInventory_to_dedicated_config.java b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0010_Move_WarpInventory_to_dedicated_config.java new file mode 100644 index 000000000..f505bf0b8 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0010_Move_WarpInventory_to_dedicated_config.java @@ -0,0 +1,21 @@ +package com.eternalcode.core.configuration.migrations; + +import static eu.okaeri.configs.migrate.ConfigMigrationDsl.move; + +import eu.okaeri.configs.migrate.builtin.NamedMigration; + +public class Migration_0010_Move_WarpInventory_to_dedicated_config extends NamedMigration { + Migration_0010_Move_WarpInventory_to_dedicated_config() { + super( + "Move WarpInventory items from messages to dedicated warp-inventory.yml config and clean up old fields", + move("warpInventory.title", "warpInventory.display.title"), + move("warpInventory.border.enabled", "warpInventory.border.enabled"), + move("warpInventory.border.material", "warpInventory.border.material"), + move("warpInventory.border.fillType", "warpInventory.border.fillType"), + move("warpInventory.border.name", "warpInventory.border.name"), + move("warpInventory.border.lore", "warpInventory.border.lore"), + move("warpInventory.decorationItems.items", "warpInventory.decorationItems.items"), + move("warpInventory.items", "warpInventory.items") + ); + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java index f9d0748b1..ea54e27d5 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java @@ -11,7 +11,8 @@ public class Migrations { new Migration_0006_Move_alert_to_broadcast_section(), new Migration_0007_Move_clear_to_dedicated_section(), new Migration_0008_Move_repair_to_dedicated_section(), - new Migration_0009_Improve_Homes_Config() + new Migration_0009_Improve_Homes_Config(), + new Migration_0010_Move_WarpInventory_to_dedicated_config() }; } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/DelWarpCommand.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/DelWarpCommand.java index 54aaf7e91..fc2a885c0 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/DelWarpCommand.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/DelWarpCommand.java @@ -2,7 +2,7 @@ import com.eternalcode.annotations.scan.command.DescriptionDocs; import com.eternalcode.core.feature.warp.Warp; -import com.eternalcode.core.feature.warp.WarpInventory; +import com.eternalcode.core.feature.warp.inventory.WarpInventory; import com.eternalcode.core.feature.warp.WarpService; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.notice.NoticeService; diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/SetWarpCommand.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/SetWarpCommand.java index 8698a24ca..9ac1073a2 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/SetWarpCommand.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/SetWarpCommand.java @@ -2,7 +2,7 @@ import com.eternalcode.annotations.scan.command.DescriptionDocs; import com.eternalcode.core.feature.warp.Warp; -import com.eternalcode.core.feature.warp.WarpInventory; +import com.eternalcode.core.feature.warp.inventory.WarpInventory; import com.eternalcode.core.feature.warp.WarpService; import com.eternalcode.core.feature.warp.WarpSettings; import com.eternalcode.core.injector.annotations.Inject; diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/WarpCommand.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/WarpCommand.java index 18a21392a..1e12cb5af 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/WarpCommand.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/WarpCommand.java @@ -3,7 +3,7 @@ import com.eternalcode.annotations.scan.command.DescriptionDocs; import com.eternalcode.core.configuration.implementation.PluginConfiguration; import com.eternalcode.core.feature.warp.Warp; -import com.eternalcode.core.feature.warp.WarpInventory; +import com.eternalcode.core.feature.warp.inventory.WarpInventory; import com.eternalcode.core.feature.warp.WarpService; import com.eternalcode.core.feature.warp.WarpSettings; import com.eternalcode.core.feature.warp.WarpTeleportService; diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpInventory.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java similarity index 60% rename from eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpInventory.java rename to eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java index 8a250463d..6fde89d5f 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpInventory.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java @@ -1,16 +1,16 @@ -package com.eternalcode.core.feature.warp; +package com.eternalcode.core.feature.warp.inventory; import com.eternalcode.commons.adventure.AdventureUtil; +import com.eternalcode.commons.concurrent.FutureHandler; import com.eternalcode.commons.scheduler.Scheduler; -import com.eternalcode.core.configuration.ConfigurationManager; import com.eternalcode.core.configuration.contextual.ConfigItem; -import com.eternalcode.core.feature.warp.messages.WarpMessages; -import com.eternalcode.core.feature.warp.messages.WarpMessages.WarpInventorySection; +import com.eternalcode.core.feature.warp.Warp; +import com.eternalcode.core.feature.warp.WarpInventoryItem; +import com.eternalcode.core.feature.warp.WarpService; +import com.eternalcode.core.feature.warp.WarpSettings; +import com.eternalcode.core.feature.warp.WarpTeleportService; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Service; -import com.eternalcode.core.translation.AbstractTranslation; -import com.eternalcode.core.translation.Translation; -import com.eternalcode.core.translation.TranslationManager; import dev.triumphteam.gui.builder.item.BaseItemBuilder; import dev.triumphteam.gui.builder.item.ItemBuilder; import dev.triumphteam.gui.guis.Gui; @@ -39,75 +39,75 @@ public class WarpInventory { private static final int BORDER_ROW_COUNT = 2; private static final int UGLY_BORDER_ROW_COUNT = 1; - private final TranslationManager translationManager; private final WarpService warpService; private final Server server; private final MiniMessage miniMessage; private final WarpTeleportService warpTeleportService; - private final ConfigurationManager configurationManager; private final WarpSettings warpSettings; private final Scheduler scheduler; + private final WarpInventoryConfigService warpInventoryConfigService; @Inject WarpInventory( - TranslationManager translationManager, WarpService warpService, Server server, MiniMessage miniMessage, WarpTeleportService warpTeleportService, - ConfigurationManager configurationManager, WarpSettings warpSettings, - Scheduler scheduler + Scheduler scheduler, + WarpInventoryConfigService warpInventoryConfigService ) { - this.translationManager = translationManager; this.warpService = warpService; this.server = server; this.miniMessage = miniMessage; this.warpTeleportService = warpTeleportService; - this.configurationManager = configurationManager; this.warpSettings = warpSettings; this.scheduler = scheduler; + this.warpInventoryConfigService = warpInventoryConfigService; } public void openInventory(Player player) { - Gui gui = this.createInventory(player); - this.scheduler.run(() -> gui.open(player)); + this.warpInventoryConfigService.getWarpInventoryData() + .thenAccept(warpData -> { + this.scheduler.run(() -> { + Gui gui = this.createInventory(player, warpData); + gui.open(player); + }); + }) + .exceptionally(FutureHandler::handleException); } - private Gui createInventory(Player player) { - Translation translation = this.translationManager.getMessages(); - WarpMessages.WarpInventorySection warpSection = translation.warp().warpInventory(); - + private Gui createInventory(Player player, WarpInventoryConfigService.WarpInventoryConfigData warpData) { int rowsCount; - int size = warpSection.items().size(); + int size = warpData.items().size(); - if (!warpSection.border().enabled()) { + if (!warpData.border().enabled()) { rowsCount = (size + 1) / GUI_ROW_SIZE_WITHOUT_BORDER + 1; } else { - switch (warpSection.border().fillType()) { + switch (warpData.border().fillType()) { case BORDER, ALL -> rowsCount = (size - 1) / GUI_ROW_SIZE_WITH_BORDER + 1 + BORDER_ROW_COUNT; case TOP, BOTTOM -> rowsCount = (size - 1) / GUI_ROW_SIZE_WITHOUT_BORDER + 1 + UGLY_BORDER_ROW_COUNT; - default -> throw new IllegalStateException("Unexpected value: " + warpSection.border().fillType()); + default -> throw new IllegalStateException("Unexpected value: " + warpData.border().fillType()); } } Gui gui = Gui.gui() - .title(this.miniMessage.deserialize(warpSection.title())) + .title(this.miniMessage.deserialize(warpData.title())) .rows(rowsCount) .disableAllInteractions() .create(); - this.createWarpItems(player, warpSection, gui); - this.createBorder(warpSection, gui); - this.createDecorations(warpSection, gui); + this.createWarpItems(player, warpData, gui); + this.createBorder(warpData, gui); + this.createDecorations(warpData, gui); return gui; } - private void createBorder(WarpInventorySection warpSection, Gui gui) { - if (warpSection.border().enabled()) { - WarpInventorySection.BorderSection borderSection = warpSection.border(); + private void createBorder(WarpInventoryConfigService.WarpInventoryConfigData warpData, Gui gui) { + if (warpData.border().enabled()) { + WarpInventoryConfig.BorderSection borderSection = warpData.border(); ItemBuilder borderItem = ItemBuilder.from(borderSection.material()); @@ -134,8 +134,8 @@ private void createBorder(WarpInventorySection warpSection, Gui gui) { } } - private void createDecorations(WarpInventorySection warpSection, Gui gui) { - for (ConfigItem item : warpSection.decorationItems().items()) { + private void createDecorations(WarpInventoryConfigService.WarpInventoryConfigData warpData, Gui gui) { + for (ConfigItem item : warpData.decorationItems().items()) { BaseItemBuilder baseItemBuilder = this.createItem(item); GuiItem guiItem = baseItemBuilder.asGuiItem(); @@ -157,8 +157,8 @@ private void createDecorations(WarpInventorySection warpSection, Gui gui) { } } - private void createWarpItems(Player player, WarpInventorySection warpSection, Gui gui) { - warpSection.items().values().forEach(item -> { + private void createWarpItems(Player player, WarpInventoryConfigService.WarpInventoryConfigData warpData, Gui gui) { + warpData.items().values().forEach(item -> { Optional warpOptional = this.warpService.findWarp(item.warpName()); if (warpOptional.isEmpty()) { @@ -215,34 +215,35 @@ public void addWarp(Warp warp) { return; } - AbstractTranslation translation = (AbstractTranslation) this.translationManager.getMessages(); - WarpMessages.WarpInventorySection warpSection = translation.warp().warpInventory(); - int slot = getSlot(warpSection); - - warpSection.addItem( - warp.getName(), - WarpInventoryItem.builder() - .withWarpName(warp.getName()) - .withWarpItem(ConfigItem.builder() - .withName(this.warpSettings.itemNamePrefix() + warp.getName()) - .withLore(Collections.singletonList(this.warpSettings.itemLore())) - .withMaterial(this.warpSettings.itemMaterial()) - .withTexture(this.warpSettings.itemTexture()) - .withSlot(slot) - .withGlow(true) - .build()) - .build()); - - this.configurationManager.save(translation); + this.warpInventoryConfigService.getWarpInventoryData() + .thenAccept(warpData -> { + int slot = getSlot(warpData); + + WarpInventoryItem warpInventoryItem = WarpInventoryItem.builder() + .withWarpName(warp.getName()) + .withWarpItem(ConfigItem.builder() + .withName(this.warpSettings.itemNamePrefix() + warp.getName()) + .withLore(Collections.singletonList(this.warpSettings.itemLore())) + .withMaterial(this.warpSettings.itemMaterial()) + .withTexture(this.warpSettings.itemTexture()) + .withSlot(slot) + .withGlow(true) + .build()) + .build(); + + this.warpInventoryConfigService.addWarpItem(warp.getName(), warpInventoryItem) + .exceptionally(FutureHandler::handleException); + }) + .exceptionally(FutureHandler::handleException); } - private int getSlot(WarpMessages.WarpInventorySection warpSection) { - int size = warpSection.items().size(); - if (!warpSection.border().enabled()) { + private int getSlot(WarpInventoryConfigService.WarpInventoryConfigData warpData) { + int size = warpData.items().size(); + if (!warpData.border().enabled()) { return GUI_ITEM_SLOT_WITHOUT_BORDER + size; } - return switch (warpSection.border().fillType()) { + return switch (warpData.border().fillType()) { case BORDER -> GUI_ITEM_SLOT_WITH_BORDER + size + ((size / WarpInventory.GUI_ROW_SIZE_WITH_BORDER) * 2); case ALL -> GUI_ITEM_SLOT_WITH_ALL_BORDER + size + ((size / WarpInventory.GUI_ROW_SIZE_WITH_BORDER) * 2); case TOP -> GUI_ITEM_SLOT_WITH_TOP_BORDER + size; @@ -255,29 +256,32 @@ public void removeWarp(String warpName) { return; } - AbstractTranslation translation = (AbstractTranslation) this.translationManager.getMessages(); - WarpMessages.WarpInventorySection warpSection = translation.warp().warpInventory(); - WarpInventoryItem removed = warpSection.removeItem(warpName); - - if (removed != null) { - this.shiftWarpItems(removed, warpSection); - } - - this.configurationManager.save(translation); + this.warpInventoryConfigService.removeWarpItem(warpName) + .thenAccept(removed -> { + if (removed != null) { + this.shiftWarpItems(removed); + } + }) + .exceptionally(FutureHandler::handleException); } - private void shiftWarpItems(WarpInventoryItem removed, WarpMessages.WarpInventorySection warpSection) { + private void shiftWarpItems(WarpInventoryItem removed) { int removedSlot = removed.warpItem.slot; - List itemsToShift = warpSection.items().values().stream() - .filter(item -> item.warpItem.slot > removedSlot) - .sorted(Comparator.comparingInt(item -> item.warpItem.slot)) - .toList(); - int currentShift = removedSlot; - for (WarpInventoryItem item : itemsToShift) { - int nextShift = item.warpItem.slot; - item.warpItem.slot = currentShift; - currentShift = nextShift; - } + this.warpInventoryConfigService.getWarpItems() + .thenAccept(items -> { + List itemsToShift = items.values().stream() + .filter(item -> item.warpItem.slot > removedSlot) + .sorted(Comparator.comparingInt(item -> item.warpItem.slot)) + .toList(); + + int currentShift = removedSlot; + for (WarpInventoryItem item : itemsToShift) { + int nextShift = item.warpItem.slot; + item.warpItem.slot = currentShift; + currentShift = nextShift; + } + }) + .exceptionally(FutureHandler::handleException); } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java new file mode 100644 index 000000000..73958575e --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java @@ -0,0 +1,97 @@ +package com.eternalcode.core.feature.warp.inventory; + +import com.eternalcode.core.configuration.AbstractConfigurationFile; +import com.eternalcode.core.configuration.contextual.ConfigItem; +import com.eternalcode.core.feature.warp.WarpInventoryItem; +import com.eternalcode.core.injector.annotations.component.ConfigurationFile; +import eu.okaeri.configs.OkaeriConfig; +import eu.okaeri.configs.annotation.Comment; +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import lombok.Getter; +import lombok.experimental.Accessors; +import org.bukkit.Material; + +@Getter +@Accessors(fluent = true) +@ConfigurationFile +public class WarpInventoryConfig extends AbstractConfigurationFile { + + @Comment({" ", + "# Warp inventory configuration", + "# This file contains the GUI layout and item definitions for the warp inventory", + "# Text content (titles, names, lore) should be configured in language files"}) + public DisplaySection display = new DisplaySection(); + + @Comment({" ", + "# Border configuration for the warp inventory"}) + public BorderSection border = new BorderSection(); + + @Comment({" ", + "# Decoration items that can be placed in the inventory"}) + public DecorationItemsSection decorationItems = new DecorationItemsSection(); + + @Comment({" ", + "# Warp items configuration - maps warp names to their inventory representation"}) + public Map items = new HashMap<>(); + + @Override + public File getConfigFile(File dataFolder) { + return new File(dataFolder, "warp-inventory.yml"); + } + + @Getter + @Accessors(fluent = true) + public static class DisplaySection extends OkaeriConfig { + @Comment("# Title of the warp inventory GUI") + public String title = "» Available warps:"; + } + + @Getter + @Accessors(fluent = true) + public static class BorderSection extends OkaeriConfig { + @Comment({" ", + "# Changes of border section may affect the appearance of the GUI inventory, after changes adjust slots of existing items."}) + public boolean enabled = true; + + public Material material = Material.GRAY_STAINED_GLASS_PANE; + + public FillType fillType = FillType.BORDER; + + public String name = ""; + + public List lore = Collections.emptyList(); + } + + @Getter + @Accessors(fluent = true) + public static class DecorationItemsSection extends OkaeriConfig { + public List items = List.of(); + } + + public enum FillType { + BORDER, + ALL, + TOP, + BOTTOM + } + + public void setItems(Map items) { + this.items = items; + } + + public void addItem(String warpName, WarpInventoryItem item) { + this.items.put(warpName, item); + } + + public WarpInventoryItem removeItem(String warpName) { + return this.items.remove(warpName); + } + + public Map getItems() { + return this.items; + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java new file mode 100644 index 000000000..2f4650a76 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java @@ -0,0 +1,66 @@ +package com.eternalcode.core.feature.warp.inventory; + +import com.eternalcode.core.feature.warp.WarpInventoryItem; +import com.eternalcode.core.feature.warp.inventory.WarpInventoryConfig.BorderSection; +import com.eternalcode.core.feature.warp.inventory.WarpInventoryConfig.DecorationItemsSection; +import com.eternalcode.core.injector.annotations.Inject; +import com.eternalcode.core.injector.annotations.component.Service; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +@Service +public class WarpInventoryConfigService { + + private final WarpInventoryRepository warpInventoryRepository; + private final WarpInventoryConfig warpInventoryConfig; + + @Inject + public WarpInventoryConfigService( + WarpInventoryRepository warpInventoryRepository, + WarpInventoryConfig warpInventoryConfig + ) { + this.warpInventoryRepository = warpInventoryRepository; + this.warpInventoryConfig = warpInventoryConfig; + } + + public CompletableFuture getWarpInventoryData() { + return this.warpInventoryRepository.getAllWarpInventoryItems() + .thenApply(items -> { + return new WarpInventoryConfigData( + this.warpInventoryConfig.display().title(), + this.warpInventoryConfig.border(), + this.warpInventoryConfig.decorationItems(), + items + ); + }); + } + + public CompletableFuture addWarpItem(String warpName, WarpInventoryItem item) { + return this.warpInventoryRepository.saveWarpInventoryItem(warpName, item); + } + + public CompletableFuture removeWarpItem(String warpName) { + return this.warpInventoryRepository.getWarpInventoryItem(warpName) + .thenCompose(item -> { + if (item != null) { + return this.warpInventoryRepository.removeWarpInventoryItem(warpName) + .thenApply(v -> item); + } + return CompletableFuture.completedFuture(null); + }); + } + + public CompletableFuture> getWarpItems() { + return this.warpInventoryRepository.getAllWarpInventoryItems(); + } + + + public record WarpInventoryConfigData( + String title, + BorderSection border, + DecorationItemsSection decorationItems, + Map items + ) { + + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java new file mode 100644 index 000000000..6a19cf91e --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java @@ -0,0 +1,18 @@ +package com.eternalcode.core.feature.warp.inventory; + +import com.eternalcode.core.feature.warp.WarpInventoryItem; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +public interface WarpInventoryRepository { + + CompletableFuture saveWarpInventoryItem(String warpName, WarpInventoryItem item); + + CompletableFuture removeWarpInventoryItem(String warpName); + + CompletableFuture getWarpInventoryItem(String warpName); + + CompletableFuture> getAllWarpInventoryItems(); + + WarpInventoryConfig getConfig(); +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java new file mode 100644 index 000000000..f32f57643 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java @@ -0,0 +1,78 @@ +package com.eternalcode.core.feature.warp.inventory; + +import com.eternalcode.commons.scheduler.Scheduler; +import com.eternalcode.core.configuration.ConfigurationManager; +import com.eternalcode.core.feature.warp.WarpInventoryItem; +import com.eternalcode.core.injector.annotations.Inject; +import com.eternalcode.core.injector.annotations.component.Repository; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Function; + +@Repository +class WarpInventoryRepositoryImpl implements WarpInventoryRepository { + + private static final Object READ_WRITE_LOCK = new Object(); + + private final WarpInventoryConfig warpInventoryConfig; + private final ConfigurationManager configurationManager; + private final Scheduler scheduler; + + @Inject + WarpInventoryRepositoryImpl( + ConfigurationManager configurationManager, + WarpInventoryConfig warpInventoryConfig, + Scheduler scheduler + ) { + this.configurationManager = configurationManager; + this.warpInventoryConfig = warpInventoryConfig; + this.scheduler = scheduler; + } + + @Override + public CompletableFuture saveWarpInventoryItem(String warpName, WarpInventoryItem item) { + return this.transactionalRun(items -> items.put(warpName, item)); + } + + @Override + public CompletableFuture removeWarpInventoryItem(String warpName) { + return this.transactionalRun(items -> items.remove(warpName)); + } + + @Override + public CompletableFuture getWarpInventoryItem(String warpName) { + return this.transactionalSupply(items -> Optional.ofNullable(items.get(warpName)).orElse(null)); + } + + @Override + public CompletableFuture> getAllWarpInventoryItems() { + return this.transactionalSupply(items -> new HashMap<>(items)); + } + + @Override + public WarpInventoryConfig getConfig() { + return this.warpInventoryConfig; + } + + private CompletableFuture transactionalRun(Consumer> editor) { + return this.transactionalSupply(items -> { + editor.accept(items); + return null; + }); + } + + private CompletableFuture transactionalSupply(Function, T> editor) { + return this.scheduler.completeAsync(() -> { + synchronized (READ_WRITE_LOCK) { + Map items = new HashMap<>(this.warpInventoryConfig.getItems()); + T result = editor.apply(items); + this.warpInventoryConfig.setItems(items); + this.configurationManager.save(this.warpInventoryConfig); + return result; + } + }); + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/ENWarpMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/ENWarpMessages.java index e28152d22..040b6e5e7 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/ENWarpMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/ENWarpMessages.java @@ -1,17 +1,10 @@ package com.eternalcode.core.feature.warp.messages; -import com.eternalcode.core.configuration.contextual.ConfigItem; -import com.eternalcode.core.feature.warp.WarpInventoryItem; import com.eternalcode.multification.notice.Notice; import eu.okaeri.configs.OkaeriConfig; import eu.okaeri.configs.annotation.Comment; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import lombok.Getter; import lombok.experimental.Accessors; -import org.bukkit.Material; @Getter @Accessors(fluent = true) @@ -40,46 +33,4 @@ public class ENWarpMessages extends OkaeriConfig implements WarpMessages { @Comment({" ", "# {WARPS} - List of warps (separated by commas)"}) public Notice available = Notice.chat("Available warps: {WARPS}"); - - @Comment({" ", "# Settings for warp inventory"}) - public ENWarpInventory warpInventory = new ENWarpInventory(); - - @Getter - @Accessors(fluent = true) - public static class ENWarpInventory extends OkaeriConfig implements WarpInventorySection { - public String title = "» Available warps:"; - - @Comment({" ", - "# Warps located inside GUI inventory can be customized here. More warps will be added on creation with /setwarp command. "}) - public Map items = new HashMap<>(); - - public void setItems(Map items) { - this.items = items; - } - - public ENWarpInventory.ENBorderSection border = new ENWarpInventory.ENBorderSection(); - public ENWarpInventory.ENDecorationItemsSection decorationItems = - new ENWarpInventory.ENDecorationItemsSection(); - - @Getter - public static class ENBorderSection extends OkaeriConfig implements BorderSection { - - @Comment({" ", - "# Changes of border section may affect the appearance of the GUI inventory, after changes adjust slots of existing items."}) - public boolean enabled = true; - - public Material material = Material.GRAY_STAINED_GLASS_PANE; - - public FillType fillType = FillType.BORDER; - - public String name = ""; - - public List lore = Collections.emptyList(); - } - - @Getter - public static class ENDecorationItemsSection extends OkaeriConfig implements DecorationItemsSection { - public List items = List.of(); - } - } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/PLWarpMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/PLWarpMessages.java index 9666e603a..863337e8f 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/PLWarpMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/PLWarpMessages.java @@ -1,17 +1,10 @@ package com.eternalcode.core.feature.warp.messages; -import com.eternalcode.core.configuration.contextual.ConfigItem; -import com.eternalcode.core.feature.warp.WarpInventoryItem; import com.eternalcode.multification.notice.Notice; import eu.okaeri.configs.OkaeriConfig; import eu.okaeri.configs.annotation.Comment; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import lombok.Getter; import lombok.experimental.Accessors; -import org.bukkit.Material; @Getter @Accessors(fluent = true) @@ -38,48 +31,4 @@ public class PLWarpMessages extends OkaeriConfig implements WarpMessages { @Comment({" ", "# {WARPS} - Lista dostępnych warpów"}) public Notice available = Notice.chat("Dostepne warpy: {WARPS}!"); - - @Comment({" ", "# Ustawienia gui listy dostępnych warpów"}) - public PLWarpInventory warpInventory = new PLWarpInventory(); - - @Getter - @Accessors(fluent = true) - public static class PLWarpInventory extends OkaeriConfig implements WarpInventorySection { - public String title = "» Lista dostępnych warpów"; - - @Comment({ - " ", - "# Poniższa lista określa przedmioty w GUI, które są wyświetlane w liście dostępnych warpów.", - "# Możesz edytować przedmioty, a dodawanie kolejnych warpów następuje automatycznie za pomocą komendy /setwarp", - }) - public Map items = new HashMap<>(); - - public void setItems(Map items) { - this.items = items; - } - - public PLWarpInventory.PLBorderSection border = new PLWarpInventory.PLBorderSection(); - public PLWarpInventory.PLDecorationItemsSection decorationItems = - new PLWarpInventory.PLDecorationItemsSection(); - - @Getter - public static class PLBorderSection extends OkaeriConfig implements BorderSection { - @Comment({" ", - "# Zmiany w tej sekcji mogą wpłynąć na wygląd GUI, zwróć uwagę na zmiany slotów przedmiotów w GUI."}) - public boolean enabled = true; - - public Material material = Material.GRAY_STAINED_GLASS_PANE; - - public FillType fillType = FillType.BORDER; - - public String name = ""; - - public List lore = Collections.emptyList(); - } - - @Getter - public static class PLDecorationItemsSection extends OkaeriConfig implements DecorationItemsSection { - public List items = List.of(); - } - } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/WarpMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/WarpMessages.java index 6c5f9f7f5..9eabdfaa0 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/WarpMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/WarpMessages.java @@ -1,12 +1,6 @@ package com.eternalcode.core.feature.warp.messages; -import com.eternalcode.core.configuration.contextual.ConfigItem; -import com.eternalcode.core.feature.warp.WarpInventoryItem; import com.eternalcode.multification.notice.Notice; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.bukkit.Material; public interface WarpMessages { Notice warpAlreadyExists(); @@ -25,51 +19,4 @@ public interface WarpMessages { Notice noPermissionsProvided(); Notice missingWarpArgument(); Notice missingPermissionArgument(); - - WarpInventorySection warpInventory(); - - interface WarpInventorySection { - String title(); - - Map items(); - void setItems(Map items); - - default void addItem(String name, WarpInventoryItem item) { - Map items = new HashMap<>(this.items()); - items.put(name, item); - - this.setItems(items); - } - - default WarpInventoryItem removeItem(String name) { - Map items = new HashMap<>(this.items()); - WarpInventoryItem removed = items.remove(name); - - this.setItems(items); - return removed; - } - - BorderSection border(); - DecorationItemsSection decorationItems(); - - interface BorderSection { - boolean enabled(); - - Material material(); - - FillType fillType(); - - String name(); - - List lore(); - - enum FillType { - TOP, BOTTOM, BORDER, ALL - } - } - - interface DecorationItemsSection { - List items(); - } - } } From d9617b8264d463419285cdfce8bf82cacc7c1cf2 Mon Sep 17 00:00:00 2001 From: Martin Sulikowski Date: Fri, 19 Sep 2025 23:31:31 +0200 Subject: [PATCH 2/7] Fix. --- ...ove_WarpInventory_to_dedicated_config.java | 21 ------------------- .../configuration/migrations/Migrations.java | 3 +-- 2 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0010_Move_WarpInventory_to_dedicated_config.java diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0010_Move_WarpInventory_to_dedicated_config.java b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0010_Move_WarpInventory_to_dedicated_config.java deleted file mode 100644 index f505bf0b8..000000000 --- a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0010_Move_WarpInventory_to_dedicated_config.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.eternalcode.core.configuration.migrations; - -import static eu.okaeri.configs.migrate.ConfigMigrationDsl.move; - -import eu.okaeri.configs.migrate.builtin.NamedMigration; - -public class Migration_0010_Move_WarpInventory_to_dedicated_config extends NamedMigration { - Migration_0010_Move_WarpInventory_to_dedicated_config() { - super( - "Move WarpInventory items from messages to dedicated warp-inventory.yml config and clean up old fields", - move("warpInventory.title", "warpInventory.display.title"), - move("warpInventory.border.enabled", "warpInventory.border.enabled"), - move("warpInventory.border.material", "warpInventory.border.material"), - move("warpInventory.border.fillType", "warpInventory.border.fillType"), - move("warpInventory.border.name", "warpInventory.border.name"), - move("warpInventory.border.lore", "warpInventory.border.lore"), - move("warpInventory.decorationItems.items", "warpInventory.decorationItems.items"), - move("warpInventory.items", "warpInventory.items") - ); - } -} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java index ea54e27d5..f9d0748b1 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java @@ -11,8 +11,7 @@ public class Migrations { new Migration_0006_Move_alert_to_broadcast_section(), new Migration_0007_Move_clear_to_dedicated_section(), new Migration_0008_Move_repair_to_dedicated_section(), - new Migration_0009_Improve_Homes_Config(), - new Migration_0010_Move_WarpInventory_to_dedicated_config() + new Migration_0009_Improve_Homes_Config() }; } From c07228c874d5734de7eb53105f3078bf94fe232a Mon Sep 17 00:00:00 2001 From: Martin Sulikowski Date: Sat, 20 Sep 2025 16:14:49 +0200 Subject: [PATCH 3/7] Improve error handling. use `ReentrantReadWriteLock` --- .../feature/warp/inventory/WarpInventory.java | 202 ++++++++++-------- .../warp/inventory/WarpInventoryConfig.java | 47 ++-- .../inventory/WarpInventoryConfigService.java | 32 ++- .../inventory/WarpInventoryRepository.java | 2 - .../WarpInventoryRepositoryImpl.java | 51 ++++- 5 files changed, 197 insertions(+), 137 deletions(-) diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java index 6fde89d5f..6d2f3ce9c 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java @@ -19,6 +19,7 @@ import java.util.Comparator; import java.util.List; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.Material; @@ -48,7 +49,7 @@ public class WarpInventory { private final WarpInventoryConfigService warpInventoryConfigService; @Inject - WarpInventory( + public WarpInventory( WarpService warpService, Server server, MiniMessage miniMessage, @@ -78,19 +79,7 @@ public void openInventory(Player player) { } private Gui createInventory(Player player, WarpInventoryConfigService.WarpInventoryConfigData warpData) { - int rowsCount; - int size = warpData.items().size(); - - if (!warpData.border().enabled()) { - rowsCount = (size + 1) / GUI_ROW_SIZE_WITHOUT_BORDER + 1; - } - else { - switch (warpData.border().fillType()) { - case BORDER, ALL -> rowsCount = (size - 1) / GUI_ROW_SIZE_WITH_BORDER + 1 + BORDER_ROW_COUNT; - case TOP, BOTTOM -> rowsCount = (size - 1) / GUI_ROW_SIZE_WITHOUT_BORDER + 1 + UGLY_BORDER_ROW_COUNT; - default -> throw new IllegalStateException("Unexpected value: " + warpData.border().fillType()); - } - } + int rowsCount = calculateRowsCount(warpData); Gui gui = Gui.gui() .title(this.miniMessage.deserialize(warpData.title())) @@ -105,33 +94,51 @@ private Gui createInventory(Player player, WarpInventoryConfigService.WarpInvent return gui; } + private int calculateRowsCount(WarpInventoryConfigService.WarpInventoryConfigData warpData) { + int size = warpData.items().size(); + + if (!warpData.border().enabled()) { + return (size + GUI_ROW_SIZE_WITHOUT_BORDER - 1) / GUI_ROW_SIZE_WITHOUT_BORDER; + } + + return switch (warpData.border().fillType()) { + case BORDER, ALL -> (size + GUI_ROW_SIZE_WITH_BORDER - 1) / GUI_ROW_SIZE_WITH_BORDER + BORDER_ROW_COUNT; + case TOP, BOTTOM -> (size + GUI_ROW_SIZE_WITHOUT_BORDER - 1) / GUI_ROW_SIZE_WITHOUT_BORDER + UGLY_BORDER_ROW_COUNT; + }; + } + private void createBorder(WarpInventoryConfigService.WarpInventoryConfigData warpData, Gui gui) { - if (warpData.border().enabled()) { - WarpInventoryConfig.BorderSection borderSection = warpData.border(); + if (!warpData.border().enabled()) { + return; + } - ItemBuilder borderItem = ItemBuilder.from(borderSection.material()); + WarpInventoryConfig.BorderSection borderSection = warpData.border(); + GuiItem guiItem = createBorderItem(borderSection); - if (!borderSection.name().isBlank()) { - borderItem.name(AdventureUtil.resetItalic(this.miniMessage.deserialize(borderSection.name()))); - } + switch (borderSection.fillType()) { + case BORDER -> gui.getFiller().fillBorder(guiItem); + case ALL -> gui.getFiller().fill(guiItem); + case TOP -> gui.getFiller().fillTop(guiItem); + case BOTTOM -> gui.getFiller().fillBottom(guiItem); + } + } - if (!borderSection.lore().isEmpty()) { - borderItem.lore(borderSection.lore() - .stream() - .map(entry -> AdventureUtil.resetItalic(this.miniMessage.deserialize(entry))) - .toList()); - } + private GuiItem createBorderItem(WarpInventoryConfig.BorderSection borderSection) { + ItemBuilder borderItem = ItemBuilder.from(borderSection.material()); - GuiItem guiItem = new GuiItem(borderItem.build()); + if (!borderSection.name().isBlank()) { + borderItem.name(AdventureUtil.resetItalic(this.miniMessage.deserialize(borderSection.name()))); + } - switch (borderSection.fillType()) { - case BORDER -> gui.getFiller().fillBorder(guiItem); - case ALL -> gui.getFiller().fill(guiItem); - case TOP -> gui.getFiller().fillTop(guiItem); - case BOTTOM -> gui.getFiller().fillBottom(guiItem); - default -> throw new IllegalStateException("Unexpected value: " + borderSection.fillType()); - } + if (!borderSection.lore().isEmpty()) { + List loreComponents = borderSection.lore() + .stream() + .map(entry -> AdventureUtil.resetItalic(this.miniMessage.deserialize(entry))) + .toList(); + borderItem.lore(loreComponents); } + + return new GuiItem(borderItem.build()); } private void createDecorations(WarpInventoryConfigService.WarpInventoryConfigData warpData, Gui gui) { @@ -141,22 +148,24 @@ private void createDecorations(WarpInventoryConfigService.WarpInventoryConfigDat guiItem.setAction(event -> { Player player = (Player) event.getWhoClicked(); - - if (item.commands.isEmpty()) { - return; - } - - for (String command : item.commands) { - this.server.dispatchCommand(player, command); - } - - player.closeInventory(); + this.executeDecorationCommands(player, item); }); gui.setItem(item.slot(), guiItem); } } + private void executeDecorationCommands(Player player, ConfigItem item) { + if (item.commands.isEmpty()) { + return; + } + + for (String command : item.commands) { + this.server.dispatchCommand(player, command); + } + player.closeInventory(); + } + private void createWarpItems(Player player, WarpInventoryConfigService.WarpInventoryConfigData warpData, Gui gui) { warpData.items().values().forEach(item -> { Optional warpOptional = this.warpService.findWarp(item.warpName()); @@ -166,26 +175,29 @@ private void createWarpItems(Player player, WarpInventoryConfigService.WarpInven } Warp warp = warpOptional.get(); - ConfigItem warpItem = item.warpItem(); if (!warp.hasPermissions(player)) { return; } - BaseItemBuilder baseItemBuilder = this.createItem(warpItem); - GuiItem guiItem = baseItemBuilder.asGuiItem(); + this.createWarpGuiItem(player, warp, item.warpItem(), gui); + }); + } - guiItem.setAction(event -> { - if (!warp.hasPermissions(player)) { - return; - } + private void createWarpGuiItem(Player player, Warp warp, ConfigItem warpItem, Gui gui) { + BaseItemBuilder baseItemBuilder = this.createItem(warpItem); + GuiItem guiItem = baseItemBuilder.asGuiItem(); - player.closeInventory(); - this.warpTeleportService.teleport(player, warp); - }); + guiItem.setAction(event -> { + if (!warp.hasPermissions(player)) { + return; + } - gui.setItem(warpItem.slot(), guiItem); + player.closeInventory(); + this.warpTeleportService.teleport(player, warp); }); + + gui.setItem(warpItem.slot(), guiItem); } private BaseItemBuilder createItem(ConfigItem item) { @@ -210,33 +222,36 @@ private BaseItemBuilder createItem(ConfigItem item) { .glow(item.glow()); } - public void addWarp(Warp warp) { + public CompletableFuture addWarp(Warp warp) { if (!this.warpService.exists(warp.getName())) { - return; + return CompletableFuture.completedFuture(null); } - this.warpInventoryConfigService.getWarpInventoryData() - .thenAccept(warpData -> { + return this.warpInventoryConfigService.getWarpInventoryData() + .thenCompose(warpData -> { int slot = getSlot(warpData); - WarpInventoryItem warpInventoryItem = WarpInventoryItem.builder() - .withWarpName(warp.getName()) - .withWarpItem(ConfigItem.builder() - .withName(this.warpSettings.itemNamePrefix() + warp.getName()) - .withLore(Collections.singletonList(this.warpSettings.itemLore())) - .withMaterial(this.warpSettings.itemMaterial()) - .withTexture(this.warpSettings.itemTexture()) - .withSlot(slot) - .withGlow(true) - .build()) - .build(); - - this.warpInventoryConfigService.addWarpItem(warp.getName(), warpInventoryItem) - .exceptionally(FutureHandler::handleException); + WarpInventoryItem warpInventoryItem = createWarpInventoryItem(warp, slot); + + return this.warpInventoryConfigService.addWarpItem(warp.getName(), warpInventoryItem); }) .exceptionally(FutureHandler::handleException); } + private WarpInventoryItem createWarpInventoryItem(Warp warp, int slot) { + return WarpInventoryItem.builder() + .withWarpName(warp.getName()) + .withWarpItem(ConfigItem.builder() + .withName(this.warpSettings.itemNamePrefix() + warp.getName()) + .withLore(Collections.singletonList(this.warpSettings.itemLore())) + .withMaterial(this.warpSettings.itemMaterial()) + .withTexture(this.warpSettings.itemTexture()) + .withSlot(slot) + .withGlow(true) + .build()) + .build(); + } + private int getSlot(WarpInventoryConfigService.WarpInventoryConfigData warpData) { int size = warpData.items().size(); if (!warpData.border().enabled()) { @@ -244,44 +259,49 @@ private int getSlot(WarpInventoryConfigService.WarpInventoryConfigData warpData) } return switch (warpData.border().fillType()) { - case BORDER -> GUI_ITEM_SLOT_WITH_BORDER + size + ((size / WarpInventory.GUI_ROW_SIZE_WITH_BORDER) * 2); - case ALL -> GUI_ITEM_SLOT_WITH_ALL_BORDER + size + ((size / WarpInventory.GUI_ROW_SIZE_WITH_BORDER) * 2); + case BORDER -> GUI_ITEM_SLOT_WITH_BORDER + size + ((size / GUI_ROW_SIZE_WITH_BORDER) * 2); + case ALL -> GUI_ITEM_SLOT_WITH_ALL_BORDER + size + ((size / GUI_ROW_SIZE_WITH_BORDER) * 2); case TOP -> GUI_ITEM_SLOT_WITH_TOP_BORDER + size; case BOTTOM -> size; }; } - public void removeWarp(String warpName) { + public CompletableFuture removeWarp(String warpName) { if (!this.warpSettings.autoAddNewWarps()) { - return; + return CompletableFuture.completedFuture(null); } - this.warpInventoryConfigService.removeWarpItem(warpName) - .thenAccept(removed -> { + return this.warpInventoryConfigService.removeWarpItem(warpName) + .thenCompose(removed -> { if (removed != null) { - this.shiftWarpItems(removed); + return this.shiftWarpItems(removed); } + return CompletableFuture.completedFuture(null); }) .exceptionally(FutureHandler::handleException); } - private void shiftWarpItems(WarpInventoryItem removed) { + private CompletableFuture shiftWarpItems(WarpInventoryItem removed) { int removedSlot = removed.warpItem.slot; - this.warpInventoryConfigService.getWarpItems() - .thenAccept(items -> { + return this.warpInventoryConfigService.getWarpItems() + .thenApply(items -> { List itemsToShift = items.values().stream() .filter(item -> item.warpItem.slot > removedSlot) .sorted(Comparator.comparingInt(item -> item.warpItem.slot)) .toList(); - int currentShift = removedSlot; - for (WarpInventoryItem item : itemsToShift) { - int nextShift = item.warpItem.slot; - item.warpItem.slot = currentShift; - currentShift = nextShift; - } - }) - .exceptionally(FutureHandler::handleException); + this.performSlotShift(itemsToShift, removedSlot); + return null; + }); + } + + private void performSlotShift(List itemsToShift, int removedSlot) { + int currentShift = removedSlot; + for (WarpInventoryItem item : itemsToShift) { + int nextShift = item.warpItem.slot; + item.warpItem.slot = currentShift; + currentShift = nextShift; + } } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java index 73958575e..3e2a92d54 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java @@ -43,6 +43,25 @@ public File getConfigFile(File dataFolder) { return new File(dataFolder, "warp-inventory.yml"); } + public Map getItems() { + return new HashMap<>(this.items); + } + + public void setItems(Map items) { + if (items == null) { + this.items = new HashMap<>(); + return; + } + this.items = new HashMap<>(items); + } + + public enum FillType { + BORDER, + ALL, + TOP, + BOTTOM + } + @Getter @Accessors(fluent = true) public static class DisplaySection extends OkaeriConfig { @@ -57,41 +76,23 @@ public static class BorderSection extends OkaeriConfig { "# Changes of border section may affect the appearance of the GUI inventory, after changes adjust slots of existing items."}) public boolean enabled = true; + @Comment("# Material for border items") public Material material = Material.GRAY_STAINED_GLASS_PANE; + @Comment("# How to fill the border") public FillType fillType = FillType.BORDER; + @Comment("# Display name for border items (empty for no name)") public String name = ""; + @Comment("# Lore lines for border items") public List lore = Collections.emptyList(); } @Getter @Accessors(fluent = true) public static class DecorationItemsSection extends OkaeriConfig { + @Comment("# List of decoration items to display in the inventory") public List items = List.of(); } - - public enum FillType { - BORDER, - ALL, - TOP, - BOTTOM - } - - public void setItems(Map items) { - this.items = items; - } - - public void addItem(String warpName, WarpInventoryItem item) { - this.items.put(warpName, item); - } - - public WarpInventoryItem removeItem(String warpName) { - return this.items.remove(warpName); - } - - public Map getItems() { - return this.items; - } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java index 2f4650a76..1b29a8aad 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java @@ -25,21 +25,35 @@ public WarpInventoryConfigService( public CompletableFuture getWarpInventoryData() { return this.warpInventoryRepository.getAllWarpInventoryItems() - .thenApply(items -> { - return new WarpInventoryConfigData( - this.warpInventoryConfig.display().title(), - this.warpInventoryConfig.border(), - this.warpInventoryConfig.decorationItems(), - items - ); - }); + .thenApply(items -> new WarpInventoryConfigData( + this.warpInventoryConfig.display().title(), + this.warpInventoryConfig.border(), + this.warpInventoryConfig.decorationItems(), + items + )); } public CompletableFuture addWarpItem(String warpName, WarpInventoryItem item) { + if (warpName == null || warpName.trim().isEmpty()) { + return CompletableFuture.failedFuture( + new IllegalArgumentException("Warp name cannot be null or empty") + ); + } + + if (item == null) { + return CompletableFuture.failedFuture( + new IllegalArgumentException("WarpInventoryItem cannot be null") + ); + } + return this.warpInventoryRepository.saveWarpInventoryItem(warpName, item); } public CompletableFuture removeWarpItem(String warpName) { + if (warpName == null || warpName.trim().isEmpty()) { + return CompletableFuture.completedFuture(null); + } + return this.warpInventoryRepository.getWarpInventoryItem(warpName) .thenCompose(item -> { if (item != null) { @@ -54,13 +68,11 @@ public CompletableFuture> getWarpItems() { return this.warpInventoryRepository.getAllWarpInventoryItems(); } - public record WarpInventoryConfigData( String title, BorderSection border, DecorationItemsSection decorationItems, Map items ) { - } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java index 6a19cf91e..eafc8c7af 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java @@ -13,6 +13,4 @@ public interface WarpInventoryRepository { CompletableFuture getWarpInventoryItem(String warpName); CompletableFuture> getAllWarpInventoryItems(); - - WarpInventoryConfig getConfig(); } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java index f32f57643..429137d9d 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java @@ -7,44 +7,70 @@ import com.eternalcode.core.injector.annotations.component.Repository; import java.util.HashMap; import java.util.Map; -import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; import java.util.function.Function; +import java.util.logging.Logger; @Repository class WarpInventoryRepositoryImpl implements WarpInventoryRepository { - private static final Object READ_WRITE_LOCK = new Object(); + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final WarpInventoryConfig warpInventoryConfig; private final ConfigurationManager configurationManager; private final Scheduler scheduler; + private final Logger logger; @Inject - WarpInventoryRepositoryImpl( + public WarpInventoryRepositoryImpl( ConfigurationManager configurationManager, WarpInventoryConfig warpInventoryConfig, - Scheduler scheduler + Scheduler scheduler, + Logger logger ) { this.configurationManager = configurationManager; this.warpInventoryConfig = warpInventoryConfig; this.scheduler = scheduler; + this.logger = logger; } @Override public CompletableFuture saveWarpInventoryItem(String warpName, WarpInventoryItem item) { + if (warpName == null || warpName.trim().isEmpty()) { + return CompletableFuture.failedFuture( + new IllegalArgumentException("Warp name cannot be null or empty") + ); + } + + if (item == null) { + return CompletableFuture.failedFuture( + new IllegalArgumentException("WarpInventoryItem cannot be null") + ); + } + return this.transactionalRun(items -> items.put(warpName, item)); } @Override public CompletableFuture removeWarpInventoryItem(String warpName) { + if (warpName == null || warpName.trim().isEmpty()) { + return CompletableFuture.failedFuture( + new IllegalArgumentException("Warp name cannot be null or empty") + ); + } + return this.transactionalRun(items -> items.remove(warpName)); } @Override public CompletableFuture getWarpInventoryItem(String warpName) { - return this.transactionalSupply(items -> Optional.ofNullable(items.get(warpName)).orElse(null)); + if (warpName == null || warpName.trim().isEmpty()) { + return CompletableFuture.completedFuture(null); + } + + return this.transactionalSupply(items -> items.get(warpName)); } @Override @@ -52,11 +78,6 @@ public CompletableFuture> getAllWarpInventoryItem return this.transactionalSupply(items -> new HashMap<>(items)); } - @Override - public WarpInventoryConfig getConfig() { - return this.warpInventoryConfig; - } - private CompletableFuture transactionalRun(Consumer> editor) { return this.transactionalSupply(items -> { editor.accept(items); @@ -66,13 +87,21 @@ private CompletableFuture transactionalRun(Consumer CompletableFuture transactionalSupply(Function, T> editor) { return this.scheduler.completeAsync(() -> { - synchronized (READ_WRITE_LOCK) { + this.readWriteLock.writeLock().lock(); + try { Map items = new HashMap<>(this.warpInventoryConfig.getItems()); T result = editor.apply(items); this.warpInventoryConfig.setItems(items); this.configurationManager.save(this.warpInventoryConfig); return result; } + catch (Exception exception) { + this.logger.severe("Error during transactional operation: " + exception.getMessage()); + throw new RuntimeException("Failed to perform transactional operation", exception); + } + finally { + this.readWriteLock.writeLock().unlock(); + } }); } } From 95291e3314083792e013281ba101906a0f2970eb Mon Sep 17 00:00:00 2001 From: Martin Sulikowski Date: Sat, 18 Oct 2025 00:56:23 +0200 Subject: [PATCH 4/7] Apply review feedback. --- .../feature/warp/command/WarpCommand.java | 2 +- .../feature/warp/inventory/WarpInventory.java | 52 +++++++------- .../warp/inventory/WarpInventoryConfig.java | 39 +++++------ .../WarpInventoryRepositoryImpl.java | 67 +++++-------------- 4 files changed, 57 insertions(+), 103 deletions(-) diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/WarpCommand.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/WarpCommand.java index 1e12cb5af..592313bca 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/WarpCommand.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/command/WarpCommand.java @@ -68,7 +68,7 @@ void warp(@Sender Player player) { return; } - this.warpInventory.openInventory(player); + this.warpInventory.open(player); } @Execute(name = "warp") diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java index 6d2f3ce9c..3cb734e31 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java @@ -18,6 +18,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; import net.kyori.adventure.text.Component; @@ -67,23 +68,23 @@ public WarpInventory( this.warpInventoryConfigService = warpInventoryConfigService; } - public void openInventory(Player player) { + public void open(Player player) { this.warpInventoryConfigService.getWarpInventoryData() .thenAccept(warpData -> { this.scheduler.run(() -> { - Gui gui = this.createInventory(player, warpData); + Gui gui = this.create(player, warpData); gui.open(player); }); }) .exceptionally(FutureHandler::handleException); } - private Gui createInventory(Player player, WarpInventoryConfigService.WarpInventoryConfigData warpData) { - int rowsCount = calculateRowsCount(warpData); + private Gui create(Player player, WarpInventoryConfigService.WarpInventoryConfigData warpData) { + int rows = calculateRowsCount(warpData); Gui gui = Gui.gui() .title(this.miniMessage.deserialize(warpData.title())) - .rows(rowsCount) + .rows(rows) .disableAllInteractions() .create(); @@ -267,41 +268,38 @@ private int getSlot(WarpInventoryConfigService.WarpInventoryConfigData warpData) } public CompletableFuture removeWarp(String warpName) { - if (!this.warpSettings.autoAddNewWarps()) { - return CompletableFuture.completedFuture(null); - } - - return this.warpInventoryConfigService.removeWarpItem(warpName) - .thenCompose(removed -> { - if (removed != null) { - return this.shiftWarpItems(removed); + return this.warpInventoryConfigService.getWarpItems() + .thenCompose(items -> { + if (!items.containsKey(warpName)) { + return CompletableFuture.completedFuture(null); } - return CompletableFuture.completedFuture(null); + + return this.warpInventoryConfigService.removeWarpItem(warpName) + .thenCompose(removed -> { + if (removed != null) { + return this.shiftWarpItems(removed, items); + } + return CompletableFuture.completedFuture(null); + }); }) .exceptionally(FutureHandler::handleException); } - private CompletableFuture shiftWarpItems(WarpInventoryItem removed) { + private CompletableFuture shiftWarpItems(WarpInventoryItem removed, Map items) { int removedSlot = removed.warpItem.slot; - return this.warpInventoryConfigService.getWarpItems() - .thenApply(items -> { - List itemsToShift = items.values().stream() - .filter(item -> item.warpItem.slot > removedSlot) - .sorted(Comparator.comparingInt(item -> item.warpItem.slot)) - .toList(); - - this.performSlotShift(itemsToShift, removedSlot); - return null; - }); - } + List itemsToShift = items.values().stream() + .filter(item -> item.warpItem.slot > removedSlot) + .sorted(Comparator.comparingInt(item -> item.warpItem.slot)) + .toList(); - private void performSlotShift(List itemsToShift, int removedSlot) { int currentShift = removedSlot; for (WarpInventoryItem item : itemsToShift) { int nextShift = item.warpItem.slot; item.warpItem.slot = currentShift; currentShift = nextShift; } + + return CompletableFuture.completedFuture(null); } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java index 3e2a92d54..b0fd3b744 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java @@ -20,22 +20,26 @@ @ConfigurationFile public class WarpInventoryConfig extends AbstractConfigurationFile { - @Comment({" ", - "# Warp inventory configuration", - "# This file contains the GUI layout and item definitions for the warp inventory", - "# Text content (titles, names, lore) should be configured in language files"}) + @Comment({ + "# Warp inventory configuration", + "# This file contains the GUI layout and item definitions for the warp inventory", + "# Text content (titles, names, lore) should be configured in language files" + }) public DisplaySection display = new DisplaySection(); - @Comment({" ", - "# Border configuration for the warp inventory"}) + @Comment({ + "# Border configuration for the warp inventory" + }) public BorderSection border = new BorderSection(); - @Comment({" ", - "# Decoration items that can be placed in the inventory"}) + @Comment({ + "# Decoration items that can be placed in the inventory" + }) public DecorationItemsSection decorationItems = new DecorationItemsSection(); - @Comment({" ", - "# Warp items configuration - maps warp names to their inventory representation"}) + @Comment({ + "# Warp items configuration - maps warp names to their inventory representation" + }) public Map items = new HashMap<>(); @Override @@ -43,18 +47,6 @@ public File getConfigFile(File dataFolder) { return new File(dataFolder, "warp-inventory.yml"); } - public Map getItems() { - return new HashMap<>(this.items); - } - - public void setItems(Map items) { - if (items == null) { - this.items = new HashMap<>(); - return; - } - this.items = new HashMap<>(items); - } - public enum FillType { BORDER, ALL, @@ -72,8 +64,7 @@ public static class DisplaySection extends OkaeriConfig { @Getter @Accessors(fluent = true) public static class BorderSection extends OkaeriConfig { - @Comment({" ", - "# Changes of border section may affect the appearance of the GUI inventory, after changes adjust slots of existing items."}) + @Comment("# Changes of border section may affect the appearance of the GUI inventory, after changes adjust slots of existing items.") public boolean enabled = true; @Comment("# Material for border items") diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java index 429137d9d..9a82e0add 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java @@ -8,60 +8,52 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.logging.Logger; @Repository class WarpInventoryRepositoryImpl implements WarpInventoryRepository { - private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - private final WarpInventoryConfig warpInventoryConfig; private final ConfigurationManager configurationManager; private final Scheduler scheduler; - private final Logger logger; @Inject public WarpInventoryRepositoryImpl( ConfigurationManager configurationManager, WarpInventoryConfig warpInventoryConfig, - Scheduler scheduler, - Logger logger + Scheduler scheduler ) { this.configurationManager = configurationManager; this.warpInventoryConfig = warpInventoryConfig; this.scheduler = scheduler; - this.logger = logger; } @Override public CompletableFuture saveWarpInventoryItem(String warpName, WarpInventoryItem item) { if (warpName == null || warpName.trim().isEmpty()) { - return CompletableFuture.failedFuture( - new IllegalArgumentException("Warp name cannot be null or empty") - ); + throw new IllegalArgumentException("Warp name cannot be null or empty"); } - if (item == null) { - return CompletableFuture.failedFuture( - new IllegalArgumentException("WarpInventoryItem cannot be null") - ); + throw new IllegalArgumentException("WarpInventoryItem cannot be null"); } - return this.transactionalRun(items -> items.put(warpName, item)); + return this.scheduler.completeAsync(() -> { + this.warpInventoryConfig.items().put(warpName, item); + this.configurationManager.save(this.warpInventoryConfig); + return null; + }); } @Override public CompletableFuture removeWarpInventoryItem(String warpName) { if (warpName == null || warpName.trim().isEmpty()) { - return CompletableFuture.failedFuture( - new IllegalArgumentException("Warp name cannot be null or empty") - ); + throw new IllegalArgumentException("Warp name cannot be null or empty"); } - return this.transactionalRun(items -> items.remove(warpName)); + return this.scheduler.completeAsync(() -> { + this.warpInventoryConfig.items().remove(warpName); + this.configurationManager.save(this.warpInventoryConfig); + return null; + }); } @Override @@ -70,38 +62,11 @@ public CompletableFuture getWarpInventoryItem(String warpName return CompletableFuture.completedFuture(null); } - return this.transactionalSupply(items -> items.get(warpName)); + return this.scheduler.completeAsync(() -> this.warpInventoryConfig.items().get(warpName)); } @Override public CompletableFuture> getAllWarpInventoryItems() { - return this.transactionalSupply(items -> new HashMap<>(items)); - } - - private CompletableFuture transactionalRun(Consumer> editor) { - return this.transactionalSupply(items -> { - editor.accept(items); - return null; - }); - } - - private CompletableFuture transactionalSupply(Function, T> editor) { - return this.scheduler.completeAsync(() -> { - this.readWriteLock.writeLock().lock(); - try { - Map items = new HashMap<>(this.warpInventoryConfig.getItems()); - T result = editor.apply(items); - this.warpInventoryConfig.setItems(items); - this.configurationManager.save(this.warpInventoryConfig); - return result; - } - catch (Exception exception) { - this.logger.severe("Error during transactional operation: " + exception.getMessage()); - throw new RuntimeException("Failed to perform transactional operation", exception); - } - finally { - this.readWriteLock.writeLock().unlock(); - } - }); + return this.scheduler.completeAsync(() -> new HashMap<>(this.warpInventoryConfig.items())); } } From 4994bf9ea11a45fac1f113762d69cbebe30679e1 Mon Sep 17 00:00:00 2001 From: Martin Sulikowski Date: Tue, 23 Dec 2025 15:28:58 +0100 Subject: [PATCH 5/7] Refactor WarpInventory and WarpInventoryConfigService for improved async handling and configuration managementRemove `WarpInventoryRepository` and migrate its responsibilities to `WarpInventoryConfigService`. --- .../feature/warp/inventory/WarpInventory.java | 28 ++++---- .../inventory/WarpInventoryConfigService.java | 61 ++++++++++------ .../inventory/WarpInventoryRepository.java | 16 ----- .../WarpInventoryRepositoryImpl.java | 72 ------------------- 4 files changed, 52 insertions(+), 125 deletions(-) delete mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java delete mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java index 3cb734e31..56b7d8412 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java @@ -104,7 +104,8 @@ private int calculateRowsCount(WarpInventoryConfigService.WarpInventoryConfigDat return switch (warpData.border().fillType()) { case BORDER, ALL -> (size + GUI_ROW_SIZE_WITH_BORDER - 1) / GUI_ROW_SIZE_WITH_BORDER + BORDER_ROW_COUNT; - case TOP, BOTTOM -> (size + GUI_ROW_SIZE_WITHOUT_BORDER - 1) / GUI_ROW_SIZE_WITHOUT_BORDER + UGLY_BORDER_ROW_COUNT; + case TOP, BOTTOM -> + (size + GUI_ROW_SIZE_WITHOUT_BORDER - 1) / GUI_ROW_SIZE_WITHOUT_BORDER + UGLY_BORDER_ROW_COUNT; }; } @@ -268,21 +269,18 @@ private int getSlot(WarpInventoryConfigService.WarpInventoryConfigData warpData) } public CompletableFuture removeWarp(String warpName) { - return this.warpInventoryConfigService.getWarpItems() - .thenCompose(items -> { - if (!items.containsKey(warpName)) { - return CompletableFuture.completedFuture(null); - } + Map items = this.warpInventoryConfigService.getWarpItems(); + if (!items.containsKey(warpName)) { + return CompletableFuture.completedFuture(null); + } - return this.warpInventoryConfigService.removeWarpItem(warpName) - .thenCompose(removed -> { - if (removed != null) { - return this.shiftWarpItems(removed, items); - } - return CompletableFuture.completedFuture(null); - }); - }) - .exceptionally(FutureHandler::handleException); + return this.warpInventoryConfigService.removeWarpItem(warpName) + .thenCompose(removed -> { + if (removed != null) { + return this.shiftWarpItems(removed, items); + } + return CompletableFuture.completedFuture(null); + }); } private CompletableFuture shiftWarpItems(WarpInventoryItem removed, Map items) { diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java index 1b29a8aad..9e152a7bd 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java @@ -1,30 +1,37 @@ package com.eternalcode.core.feature.warp.inventory; +import com.eternalcode.commons.scheduler.Scheduler; +import com.eternalcode.core.configuration.ConfigurationManager; import com.eternalcode.core.feature.warp.WarpInventoryItem; import com.eternalcode.core.feature.warp.inventory.WarpInventoryConfig.BorderSection; import com.eternalcode.core.feature.warp.inventory.WarpInventoryConfig.DecorationItemsSection; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Service; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; @Service public class WarpInventoryConfigService { - private final WarpInventoryRepository warpInventoryRepository; private final WarpInventoryConfig warpInventoryConfig; + private final ConfigurationManager configurationManager; + private final Scheduler scheduler; @Inject public WarpInventoryConfigService( - WarpInventoryRepository warpInventoryRepository, - WarpInventoryConfig warpInventoryConfig + ConfigurationManager configurationManager, + WarpInventoryConfig warpInventoryConfig, + Scheduler scheduler ) { - this.warpInventoryRepository = warpInventoryRepository; + this.configurationManager = configurationManager; this.warpInventoryConfig = warpInventoryConfig; + this.scheduler = scheduler; } public CompletableFuture getWarpInventoryData() { - return this.warpInventoryRepository.getAllWarpInventoryItems() + return this.scheduler.>completeAsync(() -> new HashMap<>( + this.warpInventoryConfig.items())) .thenApply(items -> new WarpInventoryConfigData( this.warpInventoryConfig.display().title(), this.warpInventoryConfig.border(), @@ -34,19 +41,11 @@ public CompletableFuture getWarpInventoryData() { } public CompletableFuture addWarpItem(String warpName, WarpInventoryItem item) { - if (warpName == null || warpName.trim().isEmpty()) { - return CompletableFuture.failedFuture( - new IllegalArgumentException("Warp name cannot be null or empty") - ); - } - - if (item == null) { - return CompletableFuture.failedFuture( - new IllegalArgumentException("WarpInventoryItem cannot be null") - ); - } - - return this.warpInventoryRepository.saveWarpInventoryItem(warpName, item); + return this.scheduler.completeAsync(() -> { + this.warpInventoryConfig.items().put(warpName, item); + this.configurationManager.save(this.warpInventoryConfig); + return null; + }); } public CompletableFuture removeWarpItem(String warpName) { @@ -54,18 +53,36 @@ public CompletableFuture removeWarpItem(String warpName) { return CompletableFuture.completedFuture(null); } - return this.warpInventoryRepository.getWarpInventoryItem(warpName) + CompletableFuture result; + if (warpName == null || warpName.trim().isEmpty()) { + result = CompletableFuture.completedFuture(null); + } + else { + result = + this.scheduler.completeAsync(() -> this.warpInventoryConfig.items() + .get(warpName)); + } + + return result .thenCompose(item -> { if (item != null) { - return this.warpInventoryRepository.removeWarpInventoryItem(warpName) + if (warpName == null || warpName.trim().isEmpty()) { + throw new IllegalArgumentException("Warp name cannot be null or empty"); + } + + return this.scheduler.completeAsync(() -> { + this.warpInventoryConfig.items().remove(warpName); + this.configurationManager.save(this.warpInventoryConfig); + return null; + }) .thenApply(v -> item); } return CompletableFuture.completedFuture(null); }); } - public CompletableFuture> getWarpItems() { - return this.warpInventoryRepository.getAllWarpInventoryItems(); + public Map getWarpItems() { + return new HashMap<>(this.warpInventoryConfig.items()); } public record WarpInventoryConfigData( diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java deleted file mode 100644 index eafc8c7af..000000000 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.eternalcode.core.feature.warp.inventory; - -import com.eternalcode.core.feature.warp.WarpInventoryItem; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -public interface WarpInventoryRepository { - - CompletableFuture saveWarpInventoryItem(String warpName, WarpInventoryItem item); - - CompletableFuture removeWarpInventoryItem(String warpName); - - CompletableFuture getWarpInventoryItem(String warpName); - - CompletableFuture> getAllWarpInventoryItems(); -} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java deleted file mode 100644 index 9a82e0add..000000000 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.eternalcode.core.feature.warp.inventory; - -import com.eternalcode.commons.scheduler.Scheduler; -import com.eternalcode.core.configuration.ConfigurationManager; -import com.eternalcode.core.feature.warp.WarpInventoryItem; -import com.eternalcode.core.injector.annotations.Inject; -import com.eternalcode.core.injector.annotations.component.Repository; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -@Repository -class WarpInventoryRepositoryImpl implements WarpInventoryRepository { - - private final WarpInventoryConfig warpInventoryConfig; - private final ConfigurationManager configurationManager; - private final Scheduler scheduler; - - @Inject - public WarpInventoryRepositoryImpl( - ConfigurationManager configurationManager, - WarpInventoryConfig warpInventoryConfig, - Scheduler scheduler - ) { - this.configurationManager = configurationManager; - this.warpInventoryConfig = warpInventoryConfig; - this.scheduler = scheduler; - } - - @Override - public CompletableFuture saveWarpInventoryItem(String warpName, WarpInventoryItem item) { - if (warpName == null || warpName.trim().isEmpty()) { - throw new IllegalArgumentException("Warp name cannot be null or empty"); - } - if (item == null) { - throw new IllegalArgumentException("WarpInventoryItem cannot be null"); - } - - return this.scheduler.completeAsync(() -> { - this.warpInventoryConfig.items().put(warpName, item); - this.configurationManager.save(this.warpInventoryConfig); - return null; - }); - } - - @Override - public CompletableFuture removeWarpInventoryItem(String warpName) { - if (warpName == null || warpName.trim().isEmpty()) { - throw new IllegalArgumentException("Warp name cannot be null or empty"); - } - - return this.scheduler.completeAsync(() -> { - this.warpInventoryConfig.items().remove(warpName); - this.configurationManager.save(this.warpInventoryConfig); - return null; - }); - } - - @Override - public CompletableFuture getWarpInventoryItem(String warpName) { - if (warpName == null || warpName.trim().isEmpty()) { - return CompletableFuture.completedFuture(null); - } - - return this.scheduler.completeAsync(() -> this.warpInventoryConfig.items().get(warpName)); - } - - @Override - public CompletableFuture> getAllWarpInventoryItems() { - return this.scheduler.completeAsync(() -> new HashMap<>(this.warpInventoryConfig.items())); - } -} From 85d4c99e5026d0df30ac27aacde4e55fdd292f83 Mon Sep 17 00:00:00 2001 From: Martin Sulikowski Date: Wed, 24 Dec 2025 04:13:56 +0100 Subject: [PATCH 6/7] Refactor Warp-related classes and services for improved configuration, maintainability, and structure --- ...Move_warp_inventory_to_dedicated_file.java | 178 ++++++++++++++++++ .../configuration/migrations/Migrations.java | 67 +++---- .../core/feature/warp/WarpConfig.java | 25 ++- .../core/feature/warp/WarpImpl.java | 15 +- .../core/feature/warp/WarpInventoryItem.java | 58 +++--- .../core/feature/warp/WarpServiceImpl.java | 33 ++-- .../core/feature/warp/WarpSettings.java | 15 +- .../feature/warp/WarpTeleportService.java | 57 +++--- .../feature/warp/inventory/WarpInventory.java | 119 ++++++------ .../warp/inventory/WarpInventoryConfig.java | 12 +- .../inventory/WarpInventoryConfigService.java | 63 +++---- .../feature/warp/messages/PLWarpMessages.java | 2 +- eternalcore-plugin/build.gradle.kts | 2 +- 13 files changed, 430 insertions(+), 216 deletions(-) create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0035_Move_warp_inventory_to_dedicated_file.java diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0035_Move_warp_inventory_to_dedicated_file.java b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0035_Move_warp_inventory_to_dedicated_file.java new file mode 100644 index 000000000..1cd753bf3 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0035_Move_warp_inventory_to_dedicated_file.java @@ -0,0 +1,178 @@ +package com.eternalcode.core.configuration.migrations; + +import eu.okaeri.configs.OkaeriConfig; +import eu.okaeri.configs.migrate.ConfigMigration; +import eu.okaeri.configs.migrate.view.RawConfigView; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import lombok.NonNull; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + +public class Migration_0035_Move_warp_inventory_to_dedicated_file implements ConfigMigration { + + private static final String ROOT_KEY = "warpInventory"; + private static final String NESTED_KEY = "warp.warpInventory"; + private static final String NESTED_SECTION = "warp"; + + @Override + public boolean migrate(@NonNull OkaeriConfig config, @NonNull RawConfigView view) { + String foundKey = null; + Map warpInventory = this.getFromView(view, ROOT_KEY); + + if (warpInventory != null) { + foundKey = ROOT_KEY; + } + else { + warpInventory = this.getFromView(view, NESTED_KEY); + if (warpInventory != null) { + foundKey = NESTED_KEY; + } + } + + if (warpInventory == null) { + warpInventory = this.getFromFileFallback(config); + } + + if (warpInventory == null) { + return false; + } + + Map newContent = this.transformData(warpInventory); + + if (!this.saveNewConfig(config, newContent)) { + return false; + } + + if (foundKey != null) { + view.remove(foundKey); + } + else { + view.remove(ROOT_KEY); + view.remove(NESTED_KEY); + } + + return true; + } + + private Map getFromView(RawConfigView view, String key) { + if (!view.exists(key)) { + return null; + } + Object obj = view.get(key); + return obj instanceof Map ? (Map) obj : null; + } + + private Map getFromFileFallback(OkaeriConfig config) { + File bindFile = config.getBindFile().toFile(); + if (bindFile == null || !bindFile.exists()) { + return null; + } + + try (FileReader reader = new FileReader(bindFile)) { + Map content = new Yaml().load(reader); + if (content == null) { + return null; + } + + if (content.containsKey(ROOT_KEY) && content.get(ROOT_KEY) instanceof Map) { + return (Map) content.get(ROOT_KEY); + } + + if (content.containsKey(NESTED_SECTION) && content.get(NESTED_SECTION) instanceof Map) { + Map warpSection = (Map) content.get(NESTED_SECTION); + if (warpSection.containsKey(ROOT_KEY) && warpSection.get(ROOT_KEY) instanceof Map) { + return (Map) warpSection.get(ROOT_KEY); + } + } + } + catch (Exception exception) { + exception.printStackTrace(); + } + return null; + } + + private Map transformData(Map source) { + Map result = new LinkedHashMap<>(); + + if (source.containsKey("title")) { + Map display = new LinkedHashMap<>(); + display.put("title", source.get("title")); + result.put("display", display); + } + + this.copyIfPresent(source, result, "items"); + this.copyIfPresent(source, result, "border"); + this.copyIfPresent(source, result, "decorationItems"); + + return result; + } + + private void copyIfPresent(Map source, Map target, String key) { + if (source.containsKey(key)) { + target.put(key, source.get(key)); + } + } + + private boolean saveNewConfig(OkaeriConfig config, Map content) { + File destFile = this.getDestinationFile(config); + if (destFile == null) { + return false; + } + + if (destFile.exists() && !this.targetIsSafeToWrite(destFile)) { + return true; + } + + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + options.setPrettyFlow(true); + options.setIndent(2); + options.setIndicatorIndent(0); + options.setSplitLines(false); + + try (FileWriter writer = new FileWriter(destFile)) { + new Yaml(options).dump(content, writer); + return true; + } + catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + private File getDestinationFile(OkaeriConfig config) { + File bindFile = config.getBindFile().toFile(); + if (bindFile == null) { + return null; + } + File dataFolder = bindFile.getParentFile(); + if ("lang".equals(dataFolder.getName())) { + dataFolder = dataFolder.getParentFile(); + } + return new File(dataFolder, "warp-inventory.yml"); + } + + private boolean targetIsSafeToWrite(File file) { + try (FileReader reader = new FileReader(file)) { + Map existing = new Yaml().load(reader); + if (existing == null || !existing.containsKey("items")) { + return true; + } + Object items = existing.get("items"); + return items instanceof Map && ((Map) items).isEmpty(); + } + catch (Exception exception) { + exception.printStackTrace(); + return false; + } + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java index 09372801e..d0c6cff5b 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java @@ -5,37 +5,38 @@ public class Migrations { public static final ConfigMigration[] ALL = new ConfigMigration[] { - new Migration_0001_Rename_privateChat_to_msg(), - new Migration_0002_Move_Spawn_Settings_to_spawn_config_section(), - new Migration_0003_Move_tprp_to_dedicated_section(), - new Migration_0006_Move_alert_to_broadcast_section(), - new Migration_0007_Move_clear_to_dedicated_section(), - new Migration_0008_Move_repair_to_dedicated_section(), - new Migration_0009_Improve_Homes_Config(), - new Migration_0010_Move_give_to_dedicated_section(), - new Migration_0011_Move_enchant_to_dedicated_section(), - new Migration_0012_Move_repair_argument_messages_to_dedicated_section(), - new Migration_0013_Move_enchant_messages_to_dedicated_section(), - new Migration_0014_Move_butcher_argument_messages_to_dedicated_section(), - new Migration_0016_Move_feed_messages_to_dedicated_section(), - new Migration_0017_Move_heal_messages_to_dedicated_section(), - new Migration_0018_Move_kill_messages_to_dedicated_section(), - new Migration_0019_Move_speed_messages_to_dedicated_section(), - new Migration_0020_Move_godmode_messages_to_dedicated_section(), - new Migration_0021_Move_fly_messages_to_dedicated_section(), - new Migration_0022_Move_ping_messages_to_dedicated_section(), - new Migration_0023_Move_gamemode_messages_to_dedicated_section(), - new Migration_0024_Move_online_messages_to_dedicated_section(), - new Migration_0025_Move_whois_messages_to_dedicated_section(), - new Migration_0026_Move_butcher_messages_to_dedicated_section(), - new Migration_0027_Move_give_messages_to_dedicated_section(), - new Migration_0028_Move_skull_messages_to_dedicated_section(), - new Migration_0029_Move_enchant_messages_to_dedicated_section(), - new Migration_0015_Move_ignore_messages_to_dedicated_section(), - new Migration_0030_Move_back_to_dedicated_section(), - new Migration_0031_Move_death_messages_to_dedicated_section(), - new Migration_0032_Move_join_quit_messages_to_dedicated_section(), - new Migration_0033_Move_disposal_messages_to_dedicated_section(), - new Migration_0034_Move_chat_settings_messages_to_dedicated_section(), - }; + new Migration_0001_Rename_privateChat_to_msg(), + new Migration_0002_Move_Spawn_Settings_to_spawn_config_section(), + new Migration_0003_Move_tprp_to_dedicated_section(), + new Migration_0006_Move_alert_to_broadcast_section(), + new Migration_0007_Move_clear_to_dedicated_section(), + new Migration_0008_Move_repair_to_dedicated_section(), + new Migration_0009_Improve_Homes_Config(), + new Migration_0010_Move_give_to_dedicated_section(), + new Migration_0011_Move_enchant_to_dedicated_section(), + new Migration_0012_Move_repair_argument_messages_to_dedicated_section(), + new Migration_0013_Move_enchant_messages_to_dedicated_section(), + new Migration_0014_Move_butcher_argument_messages_to_dedicated_section(), + new Migration_0016_Move_feed_messages_to_dedicated_section(), + new Migration_0017_Move_heal_messages_to_dedicated_section(), + new Migration_0018_Move_kill_messages_to_dedicated_section(), + new Migration_0019_Move_speed_messages_to_dedicated_section(), + new Migration_0020_Move_godmode_messages_to_dedicated_section(), + new Migration_0021_Move_fly_messages_to_dedicated_section(), + new Migration_0022_Move_ping_messages_to_dedicated_section(), + new Migration_0023_Move_gamemode_messages_to_dedicated_section(), + new Migration_0024_Move_online_messages_to_dedicated_section(), + new Migration_0025_Move_whois_messages_to_dedicated_section(), + new Migration_0026_Move_butcher_messages_to_dedicated_section(), + new Migration_0027_Move_give_messages_to_dedicated_section(), + new Migration_0028_Move_skull_messages_to_dedicated_section(), + new Migration_0029_Move_enchant_messages_to_dedicated_section(), + new Migration_0015_Move_ignore_messages_to_dedicated_section(), + new Migration_0030_Move_back_to_dedicated_section(), + new Migration_0031_Move_death_messages_to_dedicated_section(), + new Migration_0032_Move_join_quit_messages_to_dedicated_section(), + new Migration_0033_Move_disposal_messages_to_dedicated_section(), + new Migration_0034_Move_chat_settings_messages_to_dedicated_section(), + new Migration_0035_Move_warp_inventory_to_dedicated_file(), + }; } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpConfig.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpConfig.java index 683222060..bd83d488a 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpConfig.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpConfig.java @@ -1,12 +1,20 @@ package com.eternalcode.core.feature.warp; +import com.eternalcode.commons.bukkit.position.Position; import eu.okaeri.configs.OkaeriConfig; import eu.okaeri.configs.annotation.Comment; -import java.time.Duration; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import org.bukkit.Material; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + @Getter @Accessors(fluent = true) public class WarpConfig extends OkaeriConfig implements WarpSettings { @@ -19,8 +27,8 @@ public class WarpConfig extends OkaeriConfig implements WarpSettings { @Comment("# Warp inventory auto add new warps") public boolean autoAddNewWarps = true; - @Comment({"# Options below allow you to customize item representing warp added to GUI, ", - "# you can change almost everything inside language files, after the warp has been added to the inventory."}) + @Comment({ "# Options below allow you to customize item representing warp added to GUI, ", + "# you can change almost everything inside language files, after the warp has been added to the inventory." }) public String itemNamePrefix = "&8» &6Warp: &f"; public String itemLore = "&7Click to teleport!"; @@ -29,4 +37,15 @@ public class WarpConfig extends OkaeriConfig implements WarpSettings { @Comment("# Texture of the item (only for PLAYER_HEAD material)") public String itemTexture = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzk4ODVlODIzZmYxNTkyNjdjYmU4MDkwOTNlMzNhNDc2ZTI3NDliNjU5OGNhNGEyYTgxZWU2OTczODAzZmI2NiJ9fX0="; + + public Map warps = new ConcurrentHashMap<>(); + + @Getter + @Accessors(fluent = true) + @NoArgsConstructor + @AllArgsConstructor + public static class WarpConfigEntry extends OkaeriConfig { + public Position position; + public List permissions = new ArrayList<>(); + } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpImpl.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpImpl.java index 425692291..0eb662166 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpImpl.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpImpl.java @@ -2,22 +2,15 @@ import com.eternalcode.commons.bukkit.position.Position; import com.eternalcode.commons.bukkit.position.PositionAdapter; -import java.util.ArrayList; import org.bukkit.Location; import java.util.Collections; import java.util.List; -public class WarpImpl implements Warp { +public record WarpImpl(String name, Position position, List permissions) implements Warp { - private final String name; - private final Position position; - private final List permissions; - - public WarpImpl(String name, Position position, List permissions) { - this.name = name; - this.position = position; - this.permissions = new ArrayList<>(permissions); + public WarpImpl { + permissions = Collections.unmodifiableList(permissions); } @Override @@ -32,7 +25,7 @@ public Location getLocation() { @Override public List getPermissions() { - return Collections.unmodifiableList(this.permissions); + return this.permissions; } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpInventoryItem.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpInventoryItem.java index 34f40d49c..17d6fd9f6 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpInventoryItem.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpInventoryItem.java @@ -7,52 +7,68 @@ public class WarpInventoryItem implements Serializable { - public String warpName = "default"; + private String warpName; + private ConfigItem warpItem; - public ConfigItem warpItem = ConfigItem.builder() - .withName("&6Warp: &fdefault") - .withLore(Collections.singletonList("&7Click to teleport to warp")) - .withMaterial(Material.PLAYER_HEAD) - .withTexture("ewogICJ0aW1lc3RhbXAiIDogMTY2NDAzNTM1MjUyNCwKICAicHJvZmlsZUlkIiA6ICJjYjIzZWZhOWY1N2U0ZTQyOGE0MDU2OTM4NDlhODAxZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJWMUdHTyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS82MThhZjFiODNhZGZmNzM1MDA3ZmVkMjMwMTkxOWMwYjYzZWJmZTgwZTVkNjFiYTkzN2M5MmViMWVhY2Y2ZDI4IgogICAgfQogIH0KfQ==") - .withSlot(10) - .withGlow(true) - .build(); + public WarpInventoryItem() { + this.warpName = "default"; + this.warpItem = ConfigItem.builder() + .withName("&6Warp: &fdefault") + .withLore(Collections.singletonList("&7Click to teleport to warp")) + .withMaterial(Material.PLAYER_HEAD) + .withTexture( + "ewogICJ0aW1lc3RhbXAiIDogMTY2NDAzNTM1MjUyNCwKICAicHJvZmlsZUlkIiA6ICJjYjIzZWZhOWY1N2U0ZTQyOGE0MDU2OTM4NDlhODAxZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJWMUdHTyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS82MThhZjFiODNhZGZmNzM1MDA3ZmVkMjMwMTkxOWMwYjYzZWJmZTgwZTVkNjFiYTkzN2M5MmViMWVhY2Y2ZDI4IgogICAgfQogIH0KfQ==") + .withSlot(10) + .withGlow(true) + .build(); + } public WarpInventoryItem(String warpName, ConfigItem warpItem) { this.warpName = warpName; this.warpItem = warpItem; } - public WarpInventoryItem() { - - } - public String warpName() { return this.warpName; } + public WarpInventoryItem warpName(String warpName) { + this.warpName = warpName; + return this; + } + public ConfigItem warpItem() { return this.warpItem; } + public WarpInventoryItem warpItem(ConfigItem warpItem) { + this.warpItem = warpItem; + return this; + } + public static Builder builder() { return new Builder(); } public static class Builder { - - private String warpName; - private ConfigItem warpItem; - - public Builder withWarpName(String warpName) { + private String warpName = "default"; + private ConfigItem warpItem = ConfigItem.builder() + .withName("&6Warp: &fdefault") + .withLore(Collections.singletonList("&7Click to teleport to warp")) + .withMaterial(Material.PLAYER_HEAD) + .withTexture( + "ewogICJ0aW1lc3RhbXAiIDogMTY2NDAzNTM1MjUyNCwKICAicHJvZmlsZUlkIiA6ICJjYjIzZWZhOWY1N2U0ZTQyOGE0MDU2OTM4NDlhODAxZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJWMUdHTyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS82MThhZjFiODNhZGZmNzM1MDA3ZmVkMjMwMTkxOWMwYjYzZWJmZTgwZTVkNjFiYTkzN2M5MmViMWVhY2Y2ZDI4IgogICAgfQogIH0KfQ==") + .withSlot(10) + .withGlow(true) + .build(); + + public Builder warpName(String warpName) { this.warpName = warpName; - return this; } - public Builder withWarpItem(ConfigItem warpItem) { + public Builder warpItem(ConfigItem warpItem) { this.warpItem = warpItem; - return this; } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpServiceImpl.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpServiceImpl.java index 97f0c6d80..f74d7215f 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpServiceImpl.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpServiceImpl.java @@ -22,14 +22,14 @@ class WarpServiceImpl implements WarpService { private final WarpRepository warpRepository; @Inject - private WarpServiceImpl(WarpRepository warpRepository) { + WarpServiceImpl(WarpRepository warpRepository) { this.warpRepository = warpRepository; + this.loadWarps(); + } - warpRepository.getWarps().thenAcceptAsync(warps -> { - for (Warp warp : warps) { - this.warps.put(warp.getName(), warp); - } - }); + private void loadWarps() { + this.warpRepository.getWarps() + .thenAcceptAsync(warps -> warps.forEach(warp -> this.warps.put(warp.getName(), warp))); } @Override @@ -43,19 +43,19 @@ public Warp createWarp(String name, Location location) { } @Override - public void removeWarp(String warp) { - Warp remove = this.warps.remove(warp); - if (remove == null) { - return; - } + public void removeWarp(String warpName) { + Warp removed = this.warps.remove(warpName); - this.warpRepository.removeWarp(remove.getName()); + if (removed != null) { + this.warpRepository.removeWarp(removed.getName()); + } } @Override public Warp addPermissions(String warpName, String... permissions) { Warp warp = this.modifyPermissions(warpName, perms -> perms.addAll(List.of(permissions))); this.warpRepository.saveWarp(warp); + return warp; } @@ -63,11 +63,13 @@ public Warp addPermissions(String warpName, String... permissions) { public Warp removePermissions(String warpName, String... permissions) { Warp warp = this.modifyPermissions(warpName, perms -> perms.removeAll(List.of(permissions))); this.warpRepository.saveWarp(warp); + return warp; } private Warp modifyPermissions(String warpName, Consumer> modifier) { Warp warp = this.warps.get(warpName); + if (warp == null) { throw new IllegalArgumentException("Warp " + warpName + " does not exist"); } @@ -76,10 +78,9 @@ private Warp modifyPermissions(String warpName, Consumer> modifier) modifier.accept(updatedPermissions); Warp updatedWarp = new WarpImpl( - warp.getName(), - PositionAdapter.convert(warp.getLocation()), - updatedPermissions - ); + warp.getName(), + PositionAdapter.convert(warp.getLocation()), + updatedPermissions); this.warps.put(warpName, updatedWarp); return updatedWarp; diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpSettings.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpSettings.java index a07f7cd89..d272817f6 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpSettings.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpSettings.java @@ -1,11 +1,22 @@ package com.eternalcode.core.feature.warp; +import org.bukkit.Material; +import java.time.Duration; + public interface WarpSettings { + String itemTexture(); - org.bukkit.Material itemMaterial(); + + Material itemMaterial(); + String itemLore(); + String itemNamePrefix(); + boolean autoAddNewWarps(); + boolean inventoryEnabled(); - java.time.Duration teleportTimeToWarp(); + + Duration teleportTimeToWarp(); + } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpTeleportService.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpTeleportService.java index 66cd6085c..51d8c6f43 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpTeleportService.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpTeleportService.java @@ -10,17 +10,14 @@ import com.eternalcode.core.feature.warp.event.WarpTeleportEvent; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Service; -import java.time.Duration; -import java.util.UUID; import org.bukkit.Location; import org.bukkit.entity.Player; +import java.time.Duration; +import java.util.UUID; + @Service -@PermissionDocs( - name = "Warp bypass", - description = "Allows player to bypass warp teleport time.", - permission = WarpTeleportService.WARP_BYPASS -) +@PermissionDocs(name = "Warp bypass", description = "Allows player to bypass warp teleport time.", permission = WarpTeleportService.WARP_BYPASS) public class WarpTeleportService { static final String WARP_BYPASS = "eternalcore.warp.bypass"; @@ -31,41 +28,49 @@ public class WarpTeleportService { @Inject public WarpTeleportService( - TeleportTaskService teleportTaskService, - WarpSettings warpSettings, - EventCaller eventCaller - ) { + TeleportTaskService teleportTaskService, + WarpSettings warpSettings, + EventCaller eventCaller) { this.teleportTaskService = teleportTaskService; this.warpSettings = warpSettings; this.eventCaller = eventCaller; } public void teleport(Player player, Warp warp) { - Duration teleportTime = player.hasPermission(WARP_BYPASS) - ? Duration.ZERO - : this.warpSettings.teleportTimeToWarp(); + Duration teleportTime = this.calculateTeleportTime(player); - PreWarpTeleportEvent pre = this.eventCaller.callEvent(new PreWarpTeleportEvent(player, warp, teleportTime)); + PreWarpTeleportEvent event = this.eventCaller.callEvent(new PreWarpTeleportEvent(player, warp, teleportTime)); - if (pre.isCancelled()) { + if (event.isCancelled()) { return; } - Warp destinationWarp = pre.getWarp(); - Location destination = pre.getDestination(); - Position destinationLocation = PositionAdapter.convert(destination); - Position playerLocation = PositionAdapter.convert(player.getLocation()); + this.processTeleport(player, event.getWarp(), event.getDestination(), event.getTeleportTime()); + } + + private Duration calculateTeleportTime(Player player) { + if (player.hasPermission(WARP_BYPASS)) { + return Duration.ZERO; + } + + return this.warpSettings.teleportTimeToWarp(); + } + + private void processTeleport(Player player, Warp warp, Location destination, Duration duration) { + Position destinationPosition = PositionAdapter.convert(destination); + Position playerPosition = PositionAdapter.convert(player.getLocation()); UUID uniqueId = player.getUniqueId(); Teleport teleport = this.teleportTaskService.createTeleport( - uniqueId, - playerLocation, - destinationLocation, - pre.getTeleportTime() - ); + uniqueId, + playerPosition, + destinationPosition, + duration); teleport.getResult().whenComplete((result, throwable) -> { - this.eventCaller.callEvent(new WarpTeleportEvent(player, destinationWarp, destination)); + if (throwable == null) { + this.eventCaller.callEvent(new WarpTeleportEvent(player, warp, destination)); + } }); } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java index 56b7d8412..6bbfdd5f3 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java @@ -51,14 +51,13 @@ public class WarpInventory { @Inject public WarpInventory( - WarpService warpService, - Server server, - MiniMessage miniMessage, - WarpTeleportService warpTeleportService, - WarpSettings warpSettings, - Scheduler scheduler, - WarpInventoryConfigService warpInventoryConfigService - ) { + WarpService warpService, + Server server, + MiniMessage miniMessage, + WarpTeleportService warpTeleportService, + WarpSettings warpSettings, + Scheduler scheduler, + WarpInventoryConfigService warpInventoryConfigService) { this.warpService = warpService; this.server = server; this.miniMessage = miniMessage; @@ -70,23 +69,23 @@ public WarpInventory( public void open(Player player) { this.warpInventoryConfigService.getWarpInventoryData() - .thenAccept(warpData -> { - this.scheduler.run(() -> { - Gui gui = this.create(player, warpData); - gui.open(player); - }); - }) - .exceptionally(FutureHandler::handleException); + .thenAccept(warpData -> { + this.scheduler.run(() -> { + Gui gui = this.create(player, warpData); + gui.open(player); + }); + }) + .exceptionally(FutureHandler::handleException); } private Gui create(Player player, WarpInventoryConfigService.WarpInventoryConfigData warpData) { int rows = calculateRowsCount(warpData); Gui gui = Gui.gui() - .title(this.miniMessage.deserialize(warpData.title())) - .rows(rows) - .disableAllInteractions() - .create(); + .title(this.miniMessage.deserialize(warpData.title())) + .rows(rows) + .disableAllInteractions() + .create(); this.createWarpItems(player, warpData, gui); this.createBorder(warpData, gui); @@ -134,9 +133,9 @@ private GuiItem createBorderItem(WarpInventoryConfig.BorderSection borderSection if (!borderSection.lore().isEmpty()) { List loreComponents = borderSection.lore() - .stream() - .map(entry -> AdventureUtil.resetItalic(this.miniMessage.deserialize(entry))) - .toList(); + .stream() + .map(entry -> AdventureUtil.resetItalic(this.miniMessage.deserialize(entry))) + .toList(); borderItem.lore(loreComponents); } @@ -206,22 +205,22 @@ private BaseItemBuilder createItem(ConfigItem item) { Component name = AdventureUtil.resetItalic(this.miniMessage.deserialize(item.name())); List lore = item.lore() - .stream() - .map(entry -> AdventureUtil.resetItalic(this.miniMessage.deserialize(entry))) - .toList(); + .stream() + .map(entry -> AdventureUtil.resetItalic(this.miniMessage.deserialize(entry))) + .toList(); if (item.material() == Material.PLAYER_HEAD && !item.texture().isEmpty()) { return ItemBuilder.skull() - .name(name) - .lore(lore) - .texture(item.texture()) - .glow(item.glow()); + .name(name) + .lore(lore) + .texture(item.texture()) + .glow(item.glow()); } return ItemBuilder.from(item.material()) - .name(name) - .lore(lore) - .glow(item.glow()); + .name(name) + .lore(lore) + .glow(item.glow()); } public CompletableFuture addWarp(Warp warp) { @@ -230,28 +229,28 @@ public CompletableFuture addWarp(Warp warp) { } return this.warpInventoryConfigService.getWarpInventoryData() - .thenCompose(warpData -> { - int slot = getSlot(warpData); + .thenCompose(warpData -> { + int slot = getSlot(warpData); - WarpInventoryItem warpInventoryItem = createWarpInventoryItem(warp, slot); + WarpInventoryItem warpInventoryItem = createWarpInventoryItem(warp, slot); - return this.warpInventoryConfigService.addWarpItem(warp.getName(), warpInventoryItem); - }) - .exceptionally(FutureHandler::handleException); + return this.warpInventoryConfigService.addWarpItem(warp.getName(), warpInventoryItem); + }) + .exceptionally(FutureHandler::handleException); } private WarpInventoryItem createWarpInventoryItem(Warp warp, int slot) { return WarpInventoryItem.builder() - .withWarpName(warp.getName()) - .withWarpItem(ConfigItem.builder() - .withName(this.warpSettings.itemNamePrefix() + warp.getName()) - .withLore(Collections.singletonList(this.warpSettings.itemLore())) - .withMaterial(this.warpSettings.itemMaterial()) - .withTexture(this.warpSettings.itemTexture()) - .withSlot(slot) - .withGlow(true) - .build()) - .build(); + .warpName(warp.getName()) + .warpItem(ConfigItem.builder() + .withName(this.warpSettings.itemNamePrefix() + warp.getName()) + .withLore(Collections.singletonList(this.warpSettings.itemLore())) + .withMaterial(this.warpSettings.itemMaterial()) + .withTexture(this.warpSettings.itemTexture()) + .withSlot(slot) + .withGlow(true) + .build()) + .build(); } private int getSlot(WarpInventoryConfigService.WarpInventoryConfigData warpData) { @@ -275,26 +274,26 @@ public CompletableFuture removeWarp(String warpName) { } return this.warpInventoryConfigService.removeWarpItem(warpName) - .thenCompose(removed -> { - if (removed != null) { - return this.shiftWarpItems(removed, items); - } - return CompletableFuture.completedFuture(null); - }); + .thenCompose(removed -> { + if (removed != null) { + return this.shiftWarpItems(removed, items); + } + return CompletableFuture.completedFuture(null); + }); } private CompletableFuture shiftWarpItems(WarpInventoryItem removed, Map items) { - int removedSlot = removed.warpItem.slot; + int removedSlot = removed.warpItem().slot; List itemsToShift = items.values().stream() - .filter(item -> item.warpItem.slot > removedSlot) - .sorted(Comparator.comparingInt(item -> item.warpItem.slot)) - .toList(); + .filter(item -> item.warpItem().slot > removedSlot) + .sorted(Comparator.comparingInt(item -> item.warpItem().slot)) + .toList(); int currentShift = removedSlot; for (WarpInventoryItem item : itemsToShift) { - int nextShift = item.warpItem.slot; - item.warpItem.slot = currentShift; + int nextShift = item.warpItem().slot; + item.warpItem().slot = currentShift; currentShift = nextShift; } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java index b0fd3b744..a0284a409 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java @@ -21,24 +21,24 @@ public class WarpInventoryConfig extends AbstractConfigurationFile { @Comment({ - "# Warp inventory configuration", - "# This file contains the GUI layout and item definitions for the warp inventory", - "# Text content (titles, names, lore) should be configured in language files" + "# Warp inventory configuration", + "# This file contains the GUI layout and item definitions for the warp inventory", + "# Text content (titles, names, lore) should be configured in language files" }) public DisplaySection display = new DisplaySection(); @Comment({ - "# Border configuration for the warp inventory" + "# Border configuration for the warp inventory" }) public BorderSection border = new BorderSection(); @Comment({ - "# Decoration items that can be placed in the inventory" + "# Decoration items that can be placed in the inventory" }) public DecorationItemsSection decorationItems = new DecorationItemsSection(); @Comment({ - "# Warp items configuration - maps warp names to their inventory representation" + "# Warp items configuration - maps warp names to their inventory representation" }) public Map items = new HashMap<>(); diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java index 9e152a7bd..cf73a4ad3 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java @@ -7,6 +7,7 @@ import com.eternalcode.core.feature.warp.inventory.WarpInventoryConfig.DecorationItemsSection; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Service; + import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -14,75 +15,65 @@ @Service public class WarpInventoryConfigService { - private final WarpInventoryConfig warpInventoryConfig; + private final WarpInventoryConfig config; private final ConfigurationManager configurationManager; private final Scheduler scheduler; @Inject public WarpInventoryConfigService( ConfigurationManager configurationManager, - WarpInventoryConfig warpInventoryConfig, + WarpInventoryConfig config, Scheduler scheduler ) { this.configurationManager = configurationManager; - this.warpInventoryConfig = warpInventoryConfig; + this.config = config; this.scheduler = scheduler; } public CompletableFuture getWarpInventoryData() { - return this.scheduler.>completeAsync(() -> new HashMap<>( - this.warpInventoryConfig.items())) + return scheduler.>completeAsync(() -> new HashMap<>(config.items())) .thenApply(items -> new WarpInventoryConfigData( - this.warpInventoryConfig.display().title(), - this.warpInventoryConfig.border(), - this.warpInventoryConfig.decorationItems(), + config.display().title(), + config.border(), + config.decorationItems(), items )); } public CompletableFuture addWarpItem(String warpName, WarpInventoryItem item) { - return this.scheduler.completeAsync(() -> { - this.warpInventoryConfig.items().put(warpName, item); - this.configurationManager.save(this.warpInventoryConfig); + return scheduler.completeAsync(() -> { + config.items().put(warpName, item); + configurationManager.save(config); return null; }); } public CompletableFuture removeWarpItem(String warpName) { - if (warpName == null || warpName.trim().isEmpty()) { + if (isBlank(warpName)) { return CompletableFuture.completedFuture(null); } - CompletableFuture result; - if (warpName == null || warpName.trim().isEmpty()) { - result = CompletableFuture.completedFuture(null); - } - else { - result = - this.scheduler.completeAsync(() -> this.warpInventoryConfig.items() - .get(warpName)); - } - - return result + return scheduler.completeAsync(() -> config.items().get(warpName)) .thenCompose(item -> { - if (item != null) { - if (warpName == null || warpName.trim().isEmpty()) { - throw new IllegalArgumentException("Warp name cannot be null or empty"); - } - - return this.scheduler.completeAsync(() -> { - this.warpInventoryConfig.items().remove(warpName); - this.configurationManager.save(this.warpInventoryConfig); - return null; - }) - .thenApply(v -> item); + if (item == null) { + return CompletableFuture.completedFuture(null); } - return CompletableFuture.completedFuture(null); + + return scheduler.completeAsync(() -> { + config.items().remove(warpName); + configurationManager.save(config); + return null; + }) + .thenApply(v -> item); }); } public Map getWarpItems() { - return new HashMap<>(this.warpInventoryConfig.items()); + return new HashMap<>(config.items()); + } + + private boolean isBlank(String value) { + return value == null || value.trim().isEmpty(); } public record WarpInventoryConfigData( diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/PLWarpMessages.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/PLWarpMessages.java index 1fe1b59c2..d30a8d94a 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/PLWarpMessages.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/messages/PLWarpMessages.java @@ -30,6 +30,6 @@ public class PLWarpMessages extends OkaeriConfig implements WarpMessages { Notice missingWarpArgument = Notice.chat("Musisz podać nazwę warpu!"); Notice missingPermissionArgument = Notice.chat("Musisz podać uprawnienie!"); - @Comment({" ", "# {WARPS} - Lista dostępnych warpów"}) + @Comment({ " ", "# {WARPS} - Lista dostępnych warpów" }) Notice available = Notice.chat("Dostepne warpy: {WARPS}!"); } diff --git a/eternalcore-plugin/build.gradle.kts b/eternalcore-plugin/build.gradle.kts index cf7cd04f4..96c522848 100644 --- a/eternalcore-plugin/build.gradle.kts +++ b/eternalcore-plugin/build.gradle.kts @@ -36,7 +36,7 @@ dependencies { tasks { runServer { - minecraftVersion("1.21.10") + minecraftVersion("1.21.11") downloadPlugins.modrinth("luckperms", "v${Versions.LUCKPERMS}-bukkit") } } From b2654771286473a13bb181f82d1b40bfcd30f276 Mon Sep 17 00:00:00 2001 From: Martin Sulikowski Date: Wed, 24 Dec 2025 04:22:58 +0100 Subject: [PATCH 7/7] Refactor WarpInventory-related components for consistent formatting, improved async handling, and better configuration management; introduce Warp interface and enhance migration logging. --- ...Move_warp_inventory_to_dedicated_file.java | 26 ++-- .../eternalcode/core/feature/warp/Warp.java | 29 +++++ .../feature/warp/inventory/WarpInventory.java | 113 +++++++++--------- .../inventory/WarpInventoryConfigService.java | 20 ++-- 4 files changed, 111 insertions(+), 77 deletions(-) create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/Warp.java diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0035_Move_warp_inventory_to_dedicated_file.java b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0035_Move_warp_inventory_to_dedicated_file.java index 1cd753bf3..986959996 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0035_Move_warp_inventory_to_dedicated_file.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migration_0035_Move_warp_inventory_to_dedicated_file.java @@ -9,12 +9,16 @@ import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; import lombok.NonNull; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; public class Migration_0035_Move_warp_inventory_to_dedicated_file implements ConfigMigration { + private static final Logger LOGGER = Logger + .getLogger(Migration_0035_Move_warp_inventory_to_dedicated_file.class.getName()); private static final String ROOT_KEY = "warpInventory"; private static final String NESTED_KEY = "warp.warpInventory"; private static final String NESTED_SECTION = "warp"; @@ -26,8 +30,7 @@ public boolean migrate(@NonNull OkaeriConfig config, @NonNull RawConfigView view if (warpInventory != null) { foundKey = ROOT_KEY; - } - else { + } else { warpInventory = this.getFromView(view, NESTED_KEY); if (warpInventory != null) { foundKey = NESTED_KEY; @@ -50,8 +53,7 @@ public boolean migrate(@NonNull OkaeriConfig config, @NonNull RawConfigView view if (foundKey != null) { view.remove(foundKey); - } - else { + } else { view.remove(ROOT_KEY); view.remove(NESTED_KEY); } @@ -89,9 +91,8 @@ private Map getFromFileFallback(OkaeriConfig config) { return (Map) warpSection.get(ROOT_KEY); } } - } - catch (Exception exception) { - exception.printStackTrace(); + } catch (Exception exception) { + LOGGER.log(Level.SEVERE, "Failed to read configuration file: " + bindFile.getAbsolutePath(), exception); } return null; } @@ -142,9 +143,8 @@ private boolean saveNewConfig(OkaeriConfig config, Map content) try (FileWriter writer = new FileWriter(destFile)) { new Yaml(options).dump(content, writer); return true; - } - catch (IOException e) { - e.printStackTrace(); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Failed to save new configuration file: " + destFile.getAbsolutePath(), e); return false; } } @@ -169,9 +169,9 @@ private boolean targetIsSafeToWrite(File file) { } Object items = existing.get("items"); return items instanceof Map && ((Map) items).isEmpty(); - } - catch (Exception exception) { - exception.printStackTrace(); + } catch (Exception exception) { + LOGGER.log(Level.SEVERE, "Failed to check if target file is safe to write: " + file.getAbsolutePath(), + exception); return false; } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/Warp.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/Warp.java new file mode 100644 index 000000000..42a64b7b1 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/Warp.java @@ -0,0 +1,29 @@ +package com.eternalcode.core.feature.warp; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import java.util.List; + +public interface Warp { + + String getName(); + + Location getLocation(); + + List getPermissions(); + + default boolean hasPermissions(Player player) { + if (this.getPermissions().isEmpty()) { + return true; + } + + for (String permission : this.getPermissions()) { + if (player.hasPermission(permission)) { + return true; + } + } + + return false; + } + +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java index 6bbfdd5f3..7f19752fc 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java @@ -51,13 +51,13 @@ public class WarpInventory { @Inject public WarpInventory( - WarpService warpService, - Server server, - MiniMessage miniMessage, - WarpTeleportService warpTeleportService, - WarpSettings warpSettings, - Scheduler scheduler, - WarpInventoryConfigService warpInventoryConfigService) { + WarpService warpService, + Server server, + MiniMessage miniMessage, + WarpTeleportService warpTeleportService, + WarpSettings warpSettings, + Scheduler scheduler, + WarpInventoryConfigService warpInventoryConfigService) { this.warpService = warpService; this.server = server; this.miniMessage = miniMessage; @@ -69,23 +69,23 @@ public WarpInventory( public void open(Player player) { this.warpInventoryConfigService.getWarpInventoryData() - .thenAccept(warpData -> { - this.scheduler.run(() -> { - Gui gui = this.create(player, warpData); - gui.open(player); - }); - }) - .exceptionally(FutureHandler::handleException); + .thenAccept(warpData -> { + this.scheduler.run(() -> { + Gui gui = this.create(player, warpData); + gui.open(player); + }); + }) + .exceptionally(FutureHandler::handleException); } private Gui create(Player player, WarpInventoryConfigService.WarpInventoryConfigData warpData) { int rows = calculateRowsCount(warpData); Gui gui = Gui.gui() - .title(this.miniMessage.deserialize(warpData.title())) - .rows(rows) - .disableAllInteractions() - .create(); + .title(this.miniMessage.deserialize(warpData.title())) + .rows(rows) + .disableAllInteractions() + .create(); this.createWarpItems(player, warpData, gui); this.createBorder(warpData, gui); @@ -133,9 +133,9 @@ private GuiItem createBorderItem(WarpInventoryConfig.BorderSection borderSection if (!borderSection.lore().isEmpty()) { List loreComponents = borderSection.lore() - .stream() - .map(entry -> AdventureUtil.resetItalic(this.miniMessage.deserialize(entry))) - .toList(); + .stream() + .map(entry -> AdventureUtil.resetItalic(this.miniMessage.deserialize(entry))) + .toList(); borderItem.lore(loreComponents); } @@ -205,22 +205,22 @@ private BaseItemBuilder createItem(ConfigItem item) { Component name = AdventureUtil.resetItalic(this.miniMessage.deserialize(item.name())); List lore = item.lore() - .stream() - .map(entry -> AdventureUtil.resetItalic(this.miniMessage.deserialize(entry))) - .toList(); + .stream() + .map(entry -> AdventureUtil.resetItalic(this.miniMessage.deserialize(entry))) + .toList(); if (item.material() == Material.PLAYER_HEAD && !item.texture().isEmpty()) { return ItemBuilder.skull() - .name(name) - .lore(lore) - .texture(item.texture()) - .glow(item.glow()); - } - - return ItemBuilder.from(item.material()) .name(name) .lore(lore) + .texture(item.texture()) .glow(item.glow()); + } + + return ItemBuilder.from(item.material()) + .name(name) + .lore(lore) + .glow(item.glow()); } public CompletableFuture addWarp(Warp warp) { @@ -229,28 +229,28 @@ public CompletableFuture addWarp(Warp warp) { } return this.warpInventoryConfigService.getWarpInventoryData() - .thenCompose(warpData -> { - int slot = getSlot(warpData); + .thenCompose(warpData -> { + int slot = getSlot(warpData); - WarpInventoryItem warpInventoryItem = createWarpInventoryItem(warp, slot); + WarpInventoryItem warpInventoryItem = createWarpInventoryItem(warp, slot); - return this.warpInventoryConfigService.addWarpItem(warp.getName(), warpInventoryItem); - }) - .exceptionally(FutureHandler::handleException); + return this.warpInventoryConfigService.addWarpItem(warp.getName(), warpInventoryItem); + }) + .exceptionally(FutureHandler::handleException); } private WarpInventoryItem createWarpInventoryItem(Warp warp, int slot) { return WarpInventoryItem.builder() - .warpName(warp.getName()) - .warpItem(ConfigItem.builder() - .withName(this.warpSettings.itemNamePrefix() + warp.getName()) - .withLore(Collections.singletonList(this.warpSettings.itemLore())) - .withMaterial(this.warpSettings.itemMaterial()) - .withTexture(this.warpSettings.itemTexture()) - .withSlot(slot) - .withGlow(true) - .build()) - .build(); + .warpName(warp.getName()) + .warpItem(ConfigItem.builder() + .withName(this.warpSettings.itemNamePrefix() + warp.getName()) + .withLore(Collections.singletonList(this.warpSettings.itemLore())) + .withMaterial(this.warpSettings.itemMaterial()) + .withTexture(this.warpSettings.itemTexture()) + .withSlot(slot) + .withGlow(true) + .build()) + .build(); } private int getSlot(WarpInventoryConfigService.WarpInventoryConfigData warpData) { @@ -274,21 +274,22 @@ public CompletableFuture removeWarp(String warpName) { } return this.warpInventoryConfigService.removeWarpItem(warpName) - .thenCompose(removed -> { - if (removed != null) { - return this.shiftWarpItems(removed, items); - } - return CompletableFuture.completedFuture(null); - }); + .thenCompose(removed -> { + if (removed != null) { + return this.shiftWarpItems(removed, items) + .thenCompose(v -> this.warpInventoryConfigService.save()); + } + return CompletableFuture.completedFuture(null); + }); } private CompletableFuture shiftWarpItems(WarpInventoryItem removed, Map items) { int removedSlot = removed.warpItem().slot; List itemsToShift = items.values().stream() - .filter(item -> item.warpItem().slot > removedSlot) - .sorted(Comparator.comparingInt(item -> item.warpItem().slot)) - .toList(); + .filter(item -> item.warpItem().slot > removedSlot) + .sorted(Comparator.comparingInt(item -> item.warpItem().slot)) + .toList(); int currentShift = removedSlot; for (WarpInventoryItem item : itemsToShift) { diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java index cf73a4ad3..cb423e286 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java @@ -7,7 +7,6 @@ import com.eternalcode.core.feature.warp.inventory.WarpInventoryConfig.DecorationItemsSection; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Service; - import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -23,8 +22,7 @@ public class WarpInventoryConfigService { public WarpInventoryConfigService( ConfigurationManager configurationManager, WarpInventoryConfig config, - Scheduler scheduler - ) { + Scheduler scheduler) { this.configurationManager = configurationManager; this.config = config; this.scheduler = scheduler; @@ -36,8 +34,8 @@ public CompletableFuture getWarpInventoryData() { config.display().title(), config.border(), config.decorationItems(), - items - )); + items) + ); } public CompletableFuture addWarpItem(String warpName, WarpInventoryItem item) { @@ -53,7 +51,7 @@ public CompletableFuture removeWarpItem(String warpName) { return CompletableFuture.completedFuture(null); } - return scheduler.completeAsync(() -> config.items().get(warpName)) + return scheduler.completeAsync(() -> config.items().get(warpName)) .thenCompose(item -> { if (item == null) { return CompletableFuture.completedFuture(null); @@ -68,6 +66,13 @@ public CompletableFuture removeWarpItem(String warpName) { }); } + public CompletableFuture save() { + return scheduler.completeAsync(() -> { + configurationManager.save(config); + return null; + }); + } + public Map getWarpItems() { return new HashMap<>(config.items()); } @@ -80,7 +85,6 @@ public record WarpInventoryConfigData( String title, BorderSection border, DecorationItemsSection decorationItems, - Map items - ) { + Map items) { } }