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/WarpInventory.java deleted file mode 100644 index 8a250463d..000000000 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpInventory.java +++ /dev/null @@ -1,283 +0,0 @@ -package com.eternalcode.core.feature.warp; - -import com.eternalcode.commons.adventure.AdventureUtil; -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.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; -import dev.triumphteam.gui.guis.GuiItem; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Optional; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.Material; -import org.bukkit.Server; -import org.bukkit.entity.Player; - -@Service -public class WarpInventory { - - private static final int GUI_ITEM_SLOT_WITH_TOP_BORDER = 9; - private static final int GUI_ITEM_SLOT_WITHOUT_BORDER = 0; - private static final int GUI_ITEM_SLOT_WITH_ALL_BORDER = 1; - private static final int GUI_ITEM_SLOT_WITH_BORDER = 10; - - private static final int GUI_ROW_SIZE_WITHOUT_BORDER = 9; - private static final int GUI_ROW_SIZE_WITH_BORDER = 7; - - 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; - - @Inject - WarpInventory( - TranslationManager translationManager, - WarpService warpService, - Server server, - MiniMessage miniMessage, - WarpTeleportService warpTeleportService, - ConfigurationManager configurationManager, - WarpSettings warpSettings, - Scheduler scheduler - ) { - this.translationManager = translationManager; - this.warpService = warpService; - this.server = server; - this.miniMessage = miniMessage; - this.warpTeleportService = warpTeleportService; - this.configurationManager = configurationManager; - this.warpSettings = warpSettings; - this.scheduler = scheduler; - } - - public void openInventory(Player player) { - Gui gui = this.createInventory(player); - this.scheduler.run(() -> gui.open(player)); - } - - private Gui createInventory(Player player) { - Translation translation = this.translationManager.getMessages(); - WarpMessages.WarpInventorySection warpSection = translation.warp().warpInventory(); - - int rowsCount; - int size = warpSection.items().size(); - - if (!warpSection.border().enabled()) { - rowsCount = (size + 1) / GUI_ROW_SIZE_WITHOUT_BORDER + 1; - } - else { - switch (warpSection.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()); - } - } - - Gui gui = Gui.gui() - .title(this.miniMessage.deserialize(warpSection.title())) - .rows(rowsCount) - .disableAllInteractions() - .create(); - - this.createWarpItems(player, warpSection, gui); - this.createBorder(warpSection, gui); - this.createDecorations(warpSection, gui); - - return gui; - } - - private void createBorder(WarpInventorySection warpSection, Gui gui) { - if (warpSection.border().enabled()) { - WarpInventorySection.BorderSection borderSection = warpSection.border(); - - ItemBuilder borderItem = ItemBuilder.from(borderSection.material()); - - if (!borderSection.name().isBlank()) { - borderItem.name(AdventureUtil.resetItalic(this.miniMessage.deserialize(borderSection.name()))); - } - - if (!borderSection.lore().isEmpty()) { - borderItem.lore(borderSection.lore() - .stream() - .map(entry -> AdventureUtil.resetItalic(this.miniMessage.deserialize(entry))) - .toList()); - } - - GuiItem guiItem = new GuiItem(borderItem.build()); - - 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()); - } - } - } - - private void createDecorations(WarpInventorySection warpSection, Gui gui) { - for (ConfigItem item : warpSection.decorationItems().items()) { - BaseItemBuilder baseItemBuilder = this.createItem(item); - GuiItem guiItem = baseItemBuilder.asGuiItem(); - - 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(); - }); - - gui.setItem(item.slot(), guiItem); - } - } - - private void createWarpItems(Player player, WarpInventorySection warpSection, Gui gui) { - warpSection.items().values().forEach(item -> { - Optional warpOptional = this.warpService.findWarp(item.warpName()); - - if (warpOptional.isEmpty()) { - return; - } - - Warp warp = warpOptional.get(); - ConfigItem warpItem = item.warpItem(); - - if (!warp.hasPermissions(player)) { - return; - } - - BaseItemBuilder baseItemBuilder = this.createItem(warpItem); - GuiItem guiItem = baseItemBuilder.asGuiItem(); - - guiItem.setAction(event -> { - if (!warp.hasPermissions(player)) { - return; - } - - player.closeInventory(); - this.warpTeleportService.teleport(player, warp); - }); - - gui.setItem(warpItem.slot(), guiItem); - }); - } - - 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(); - - 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) - .glow(item.glow()); - } - - public void addWarp(Warp warp) { - if (!this.warpService.exists(warp.getName())) { - 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); - } - - private int getSlot(WarpMessages.WarpInventorySection warpSection) { - int size = warpSection.items().size(); - if (!warpSection.border().enabled()) { - return GUI_ITEM_SLOT_WITHOUT_BORDER + size; - } - - return switch (warpSection.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; - case BOTTOM -> size; - }; - } - - public void removeWarp(String warpName) { - if (!this.warpSettings.autoAddNewWarps()) { - 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); - } - - private void shiftWarpItems(WarpInventoryItem removed, WarpMessages.WarpInventorySection warpSection) { - 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; - } - } -} 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/inventory/WarpInventory.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java new file mode 100644 index 000000000..6d2f3ce9c --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventory.java @@ -0,0 +1,307 @@ +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.contextual.ConfigItem; +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 dev.triumphteam.gui.builder.item.BaseItemBuilder; +import dev.triumphteam.gui.builder.item.ItemBuilder; +import dev.triumphteam.gui.guis.Gui; +import dev.triumphteam.gui.guis.GuiItem; +import java.util.Collections; +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; +import org.bukkit.Server; +import org.bukkit.entity.Player; + +@Service +public class WarpInventory { + + private static final int GUI_ITEM_SLOT_WITH_TOP_BORDER = 9; + private static final int GUI_ITEM_SLOT_WITHOUT_BORDER = 0; + private static final int GUI_ITEM_SLOT_WITH_ALL_BORDER = 1; + private static final int GUI_ITEM_SLOT_WITH_BORDER = 10; + + private static final int GUI_ROW_SIZE_WITHOUT_BORDER = 9; + private static final int GUI_ROW_SIZE_WITH_BORDER = 7; + + private static final int BORDER_ROW_COUNT = 2; + private static final int UGLY_BORDER_ROW_COUNT = 1; + + private final WarpService warpService; + private final Server server; + private final MiniMessage miniMessage; + private final WarpTeleportService warpTeleportService; + private final WarpSettings warpSettings; + private final Scheduler scheduler; + private final WarpInventoryConfigService warpInventoryConfigService; + + @Inject + public WarpInventory( + WarpService warpService, + Server server, + MiniMessage miniMessage, + WarpTeleportService warpTeleportService, + WarpSettings warpSettings, + Scheduler scheduler, + WarpInventoryConfigService warpInventoryConfigService + ) { + this.warpService = warpService; + this.server = server; + this.miniMessage = miniMessage; + this.warpTeleportService = warpTeleportService; + this.warpSettings = warpSettings; + this.scheduler = scheduler; + this.warpInventoryConfigService = warpInventoryConfigService; + } + + public void openInventory(Player 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, WarpInventoryConfigService.WarpInventoryConfigData warpData) { + int rowsCount = calculateRowsCount(warpData); + + Gui gui = Gui.gui() + .title(this.miniMessage.deserialize(warpData.title())) + .rows(rowsCount) + .disableAllInteractions() + .create(); + + this.createWarpItems(player, warpData, gui); + this.createBorder(warpData, gui); + this.createDecorations(warpData, gui); + + 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()) { + return; + } + + WarpInventoryConfig.BorderSection borderSection = warpData.border(); + GuiItem guiItem = createBorderItem(borderSection); + + 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); + } + } + + private GuiItem createBorderItem(WarpInventoryConfig.BorderSection borderSection) { + ItemBuilder borderItem = ItemBuilder.from(borderSection.material()); + + if (!borderSection.name().isBlank()) { + borderItem.name(AdventureUtil.resetItalic(this.miniMessage.deserialize(borderSection.name()))); + } + + 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) { + for (ConfigItem item : warpData.decorationItems().items()) { + BaseItemBuilder baseItemBuilder = this.createItem(item); + GuiItem guiItem = baseItemBuilder.asGuiItem(); + + guiItem.setAction(event -> { + Player player = (Player) event.getWhoClicked(); + 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()); + + if (warpOptional.isEmpty()) { + return; + } + + Warp warp = warpOptional.get(); + + if (!warp.hasPermissions(player)) { + return; + } + + this.createWarpGuiItem(player, warp, item.warpItem(), gui); + }); + } + + private void createWarpGuiItem(Player player, Warp warp, ConfigItem warpItem, Gui gui) { + BaseItemBuilder baseItemBuilder = this.createItem(warpItem); + GuiItem guiItem = baseItemBuilder.asGuiItem(); + + guiItem.setAction(event -> { + if (!warp.hasPermissions(player)) { + return; + } + + player.closeInventory(); + this.warpTeleportService.teleport(player, warp); + }); + + gui.setItem(warpItem.slot(), guiItem); + } + + 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(); + + 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) + .glow(item.glow()); + } + + public CompletableFuture addWarp(Warp warp) { + if (!this.warpService.exists(warp.getName())) { + return CompletableFuture.completedFuture(null); + } + + return this.warpInventoryConfigService.getWarpInventoryData() + .thenCompose(warpData -> { + int slot = getSlot(warpData); + + 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()) { + return GUI_ITEM_SLOT_WITHOUT_BORDER + size; + } + + return switch (warpData.border().fillType()) { + 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 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 CompletableFuture.completedFuture(null); + }) + .exceptionally(FutureHandler::handleException); + } + + private CompletableFuture shiftWarpItems(WarpInventoryItem removed) { + 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; + }); + } + + 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 new file mode 100644 index 000000000..3e2a92d54 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfig.java @@ -0,0 +1,98 @@ +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"); + } + + 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 { + @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; + + @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(); + } +} 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..1b29a8aad --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryConfigService.java @@ -0,0 +1,78 @@ +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 -> 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) { + 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..eafc8c7af --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepository.java @@ -0,0 +1,16 @@ +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 new file mode 100644 index 000000000..429137d9d --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/inventory/WarpInventoryRepositoryImpl.java @@ -0,0 +1,107 @@ +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; +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 + ) { + 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) { + if (warpName == null || warpName.trim().isEmpty()) { + return CompletableFuture.completedFuture(null); + } + + return this.transactionalSupply(items -> 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(); + } + }); + } +} 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(); - } - } }