From 0826518751774294960e31496ef815dd641e9082 Mon Sep 17 00:00:00 2001 From: Jakob Reiser Date: Wed, 22 Feb 2023 14:50:10 +0100 Subject: [PATCH 01/15] Add support for custom guis. Add OpenGui action --- .../notquests/paper/gui/GuiActions.java | 2 + .../notquests/paper/gui/GuiService.java | 248 ++++++++++++++++++ .../paper/gui/panes/ActiveQuestsPane.java | 2 + .../paper/gui/panes/AvilableQuestspane.java | 2 + .../gui/propertytype/ActionPropertyType.java | 21 ++ .../propertytype/ConditionPropertyType.java | 21 ++ .../managers/registering/ActionManager.java | 25 +- .../paper/structs/actions/OpenGuiAction.java | 93 +++++++ paper/src/main/resources/guis/testgui.xml | 16 ++ 9 files changed, 408 insertions(+), 22 deletions(-) create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiService.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/ActiveQuestsPane.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/AvilableQuestspane.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ActionPropertyType.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ConditionPropertyType.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/structs/actions/OpenGuiAction.java create mode 100644 paper/src/main/resources/guis/testgui.xml diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java new file mode 100644 index 000000000..e85884bbd --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java @@ -0,0 +1,2 @@ +package rocks.gravili.notquests.paper.gui;public class GuiAction { +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiService.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiService.java new file mode 100644 index 000000000..e5793e31e --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiService.java @@ -0,0 +1,248 @@ +package rocks.gravili.notquests.paper.gui; + +import com.github.stefvanschie.inventoryframework.exception.XMLLoadException; +import com.github.stefvanschie.inventoryframework.gui.type.*; +import com.github.stefvanschie.inventoryframework.gui.type.util.Gui; +import com.github.stefvanschie.inventoryframework.gui.type.util.NamedGui; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import rocks.gravili.notquests.paper.NotQuests; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; + +public class GuiService { + private final NotQuests notQuests; + + // TODO: add a config variable for that + private static final String EMPTY_DISPLAYNAME_KEYWORD = "EMPTY"; + private final GuiActions guiActions; + private final Map guis; + + public GuiService(NotQuests notQuests) { + this.notQuests = notQuests; + this.guis = new HashMap<>(); + this.guiActions = new GuiActions(notQuests); + } + + /** + * Saves all default guis to the guis folder of the plugin + */ + public void saveDefaultGuis() { + saveDefaultGui("testgui"); + } + + /** + * Saves a gui with the specified name from the resources folder to the guis folder of the plugin + * @param name the name of the gui that should be saved + */ + public void saveDefaultGui(String name){ + notQuests.getMain().saveResource(Paths.get("guis/", name + ".xml").toString(), false); + } + + /** + * Loads a Gui from an XML file located in a specified folder + * @param guisFolder the folder in which the gui is located + * @param fileName the name of the gui file. The name is also used to identify the gui later on + */ + public void loadGui(Path guisFolder, String fileName) { + var guiPath = guisFolder.resolve(fileName); + Gui gui = null; + try (InputStream inputStream = Files.newInputStream(guiPath)) { + gui = Gui.load(guiActions, inputStream); + var guiName = fileName.replace(".xml", ""); + guis.put(guiName, gui); + } catch (IOException e) { + notQuests.getLogManager().warn("Failed to load gui with name ' " + fileName + "' See below for more information", e); + e.printStackTrace(); + } catch (XMLLoadException e) { + notQuests.getLogManager().warn("Failed to load gui with name ' " + fileName + "'", e); + notQuests.getLogManager().warn("Type: Error in XML syntax, see below for more information "); + e.printStackTrace(); + } + } + + /** + * Loads all guis found in the predefined folder into the gui storage + */ + public void loadAllGuis() { + var guisFolder = notQuests.getMain().getDataFolder().toPath().resolve(Paths.get("guis")); + + var fileNames = guisFolder.toFile().list(); + + if (fileNames == null) { + saveDefaultGuis(); + loadAllGuis(); + return; + } + + Arrays.stream(fileNames).filter(fileName -> fileName.endsWith(".xml")).forEach(fileName -> { + loadGui(guisFolder, fileName); + }); + } + + /** + * Opens the first gui matching the given name for the player + * @param guiName the nome of the gui that should be opened + * @param player the player to open the gui for + */ + public void showGui(String guiName, Player player) { + var firstMatch = guis.get(guiName); + + if (firstMatch == null) { + // TODO: Error message + return; + } + + var gui = firstMatch.copy(); + + var langManager = notQuests.getLanguageManager(); + + // Replace title path with actual title + if (gui instanceof NamedGui namedGui) { + var title = LegacyComponentSerializer.legacySection().serialize(langManager.getComponent(namedGui.getTitle(), player)); + namedGui.setTitle(title); + } + + /* + CRAFTING TABLE: replace display name and lore for all items + */ + if (gui instanceof CraftingTableGui craftingTableGui) { + craftingTableGui.getInputComponent().getPanes().forEach( + pane -> pane.getItems().forEach( + guiItem -> { + var itemStack = getWithReplacedLoreAndDisplayName(guiItem.getItem(), player); + guiItem.setItem(itemStack); + } + ) + + ); + craftingTableGui.getOutputComponent().getPanes().forEach( + pane -> pane.getItems().forEach( + guiItem -> { + var itemStack = getWithReplacedLoreAndDisplayName(guiItem.getItem(), player); + guiItem.setItem(itemStack); + } + ) + ); + } + + /* + CHEST: replace display name and lore for all items + */ + if (gui instanceof ChestGui chestGui) { + chestGui.getInventoryComponent().getPanes().forEach( + pane -> pane.getItems().forEach( + guiItem -> { + var itemStack = getWithReplacedLoreAndDisplayName(guiItem.getItem(), player); + guiItem.setItem(itemStack); + } + ) + ); + } + + /* + HOPPER: replace display name and lore for all items + */ + if (gui instanceof HopperGui hopperGui) { + hopperGui.getSlotsComponent().getPanes().forEach( + pane -> pane.getItems().forEach( + guiItem -> { + var itemStack = getWithReplacedLoreAndDisplayName(guiItem.getItem(), player); + guiItem.setItem(itemStack); + } + ) + ); + } + + /* + DROPPER: replace display name and lore for all items + */ + if (gui instanceof DropperGui dropperGui) { + dropperGui.getContentsComponent().getPanes().forEach( + pane -> pane.getItems().forEach( + guiItem -> { + var itemStack = getWithReplacedLoreAndDisplayName(guiItem.getItem(), player); + guiItem.setItem(itemStack); + } + + ) + ); + } + + // TODO: Implement missing gui types + + // Important for the changes to take effect + gui.update(); + + // Open the gui for the player + gui.show(player); + } + + + /** + * Replace display name and lore for given item + * @param itemStack the item to replace lore and display name + * @param player the player which the placeholders should be replaced for + * @return the item with new lore and display name + */ + private ItemStack getWithReplacedLoreAndDisplayName(ItemStack itemStack, Player player) { + var newLore = fetchLore(itemStack, player); + itemStack.lore(newLore); + + var displayName = fetchDisplayName(itemStack, player); + var itemMeta = itemStack.getItemMeta(); + itemMeta.displayName(displayName); + itemStack.setItemMeta(itemMeta); + + return itemStack; + } + + /** + * Retrieve the lore of an item assuming the current first lore line is a path to the actual lore + * @param itemStack the item for which we are looking for the lore + * @param player the player for whom we want to replace the placeholders in the lore + * @return the new lore as a component list with all placeholder replaced + */ + private List fetchLore(ItemStack itemStack, Player player) { + var currentLore = itemStack.lore(); + if (currentLore == null) { + return Collections.emptyList(); + } + var loreConfigPath = PlainTextComponentSerializer.plainText().serialize(currentLore.get(0)); + return notQuests.getLanguageManager().getComponentList(loreConfigPath, player); + } + + /** + * Retrieve the display name of an item assuming that the current display name is a path to the actual name + * @param itemStack the item for which we are looking for the display name + * @param player the player for whom we want to replace the placeholders in the display name + * @return the new lore as a component list with all placeholder replaced + */ + private Component fetchDisplayName(ItemStack itemStack, Player player) { + var currentDisplayName = itemStack.displayName(); + + var displayNameAsString = PlainTextComponentSerializer.plainText().serialize(currentDisplayName).replace("[", "").replace("]", ""); + + if (displayNameAsString.equalsIgnoreCase(EMPTY_DISPLAYNAME_KEYWORD)) { + return Component.empty(); + } + + return notQuests.getLanguageManager().getComponent(displayNameAsString, player); + } + + /** + * Returns a with all guis and their names + * @return A map with all guis, identified by their names + */ + public final Map getGuis() { + return guis; + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/ActiveQuestsPane.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/ActiveQuestsPane.java new file mode 100644 index 000000000..3e34d874e --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/ActiveQuestsPane.java @@ -0,0 +1,2 @@ +package rocks.gravili.notquests.paper.gui.panes;public class ActiveQuestsPane { +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/AvilableQuestspane.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/AvilableQuestspane.java new file mode 100644 index 000000000..ab746e412 --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/AvilableQuestspane.java @@ -0,0 +1,2 @@ +package rocks.gravili.notquests.paper.gui.panes;public class AvilableQuestspane { +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ActionPropertyType.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ActionPropertyType.java new file mode 100644 index 000000000..12c915c35 --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ActionPropertyType.java @@ -0,0 +1,21 @@ +package rocks.gravili.notquests.paper.gui.propertytype; + +import java.util.Arrays; +import java.util.List; + +public class ActionPropertyType { + private static final String STRING_REPRESENTATION = "action"; + private final String value; + + private ActionPropertyType(String value) { + this.value = value; + } + + public static ActionPropertyType of(String string) { + return new ActionPropertyType(string); + } + + public List toStringList() { + return Arrays.asList(value.split("\n")); + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ConditionPropertyType.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ConditionPropertyType.java new file mode 100644 index 000000000..09c98848b --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ConditionPropertyType.java @@ -0,0 +1,21 @@ +package rocks.gravili.notquests.paper.gui.propertytype; + +import java.util.Arrays; +import java.util.List; + +public class ConditionPropertyType { + private static final String STRING_REPRESENTATION = "action"; + private final String value; + + private ConditionPropertyType(String value) { + this.value = value; + } + + public static ConditionPropertyType of(String string) { + return new ConditionPropertyType(string); + } + + public List toStringList() { + return Arrays.asList(value.split("\n")); + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/managers/registering/ActionManager.java b/paper/src/main/java/rocks/gravili/notquests/paper/managers/registering/ActionManager.java index 6e64f301f..b13a64f7a 100644 --- a/paper/src/main/java/rocks/gravili/notquests/paper/managers/registering/ActionManager.java +++ b/paper/src/main/java/rocks/gravili/notquests/paper/managers/registering/ActionManager.java @@ -39,28 +39,7 @@ import rocks.gravili.notquests.paper.managers.data.Category; import rocks.gravili.notquests.paper.structs.Quest; import rocks.gravili.notquests.paper.structs.QuestPlayer; -import rocks.gravili.notquests.paper.structs.actions.Action; -import rocks.gravili.notquests.paper.structs.actions.ActionAction; -import rocks.gravili.notquests.paper.structs.actions.ActionFor; -import rocks.gravili.notquests.paper.structs.actions.BeamAction; -import rocks.gravili.notquests.paper.structs.actions.BooleanAction; -import rocks.gravili.notquests.paper.structs.actions.BroadcastMessageAction; -import rocks.gravili.notquests.paper.structs.actions.CompleteQuestAction; -import rocks.gravili.notquests.paper.structs.actions.ConsoleCommandAction; -import rocks.gravili.notquests.paper.structs.actions.FailQuestAction; -import rocks.gravili.notquests.paper.structs.actions.GiveItemAction; -import rocks.gravili.notquests.paper.structs.actions.GiveQuestAction; -import rocks.gravili.notquests.paper.structs.actions.ItemStackListAction; -import rocks.gravili.notquests.paper.structs.actions.ListAction; -import rocks.gravili.notquests.paper.structs.actions.NumberAction; -import rocks.gravili.notquests.paper.structs.actions.ChatAction; -import rocks.gravili.notquests.paper.structs.actions.PlaySoundAction; -import rocks.gravili.notquests.paper.structs.actions.PlayerCommandAction; -import rocks.gravili.notquests.paper.structs.actions.SendMessageAction; -import rocks.gravili.notquests.paper.structs.actions.SpawnMobAction; -import rocks.gravili.notquests.paper.structs.actions.StartConversationAction; -import rocks.gravili.notquests.paper.structs.actions.StringAction; -import rocks.gravili.notquests.paper.structs.actions.TriggerCommandAction; +import rocks.gravili.notquests.paper.structs.actions.*; import rocks.gravili.notquests.paper.structs.actions.hooks.betonquest.BetonQuestFireEventAction; import rocks.gravili.notquests.paper.structs.actions.hooks.betonquest.BetonQuestFireInlineEventAction; import rocks.gravili.notquests.paper.structs.conditions.Condition; @@ -107,6 +86,8 @@ public void registerDefaultActions() { registerAction("PlaySound", PlaySoundAction.class); + registerAction("OpenGui", OpenGuiAction.class); + registerAction("Number", NumberAction.class); registerAction("String", StringAction.class); diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/structs/actions/OpenGuiAction.java b/paper/src/main/java/rocks/gravili/notquests/paper/structs/actions/OpenGuiAction.java new file mode 100644 index 000000000..c85a1a200 --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/structs/actions/OpenGuiAction.java @@ -0,0 +1,93 @@ +package rocks.gravili.notquests.paper.structs.actions; + +import cloud.commandframework.ArgumentDescription; +import cloud.commandframework.Command; +import cloud.commandframework.arguments.standard.StringArgument; +import cloud.commandframework.paper.PaperCommandManager; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; +import rocks.gravili.notquests.paper.NotQuests; +import rocks.gravili.notquests.paper.commands.arguments.CommandSelector; +import rocks.gravili.notquests.paper.structs.QuestPlayer; + +import java.util.ArrayList; + +public class OpenGuiAction extends Action { + private String guiName = ""; + public OpenGuiAction(NotQuests main) { + super(main); + } + + public static void handleCommands( + NotQuests main, + PaperCommandManager manager, + Command.Builder builder, + ActionFor actionFor) { + manager.command( + builder.argument( + StringArgument.builder("guiName").withSuggestionsProvider((objectCommandContext, s) -> { + + var completions = main.getGuiService().getGuis().keySet(); + + return completions.stream().toList(); + }).build(), + ArgumentDescription.of("Opens a gui for the player") + ).handler(commandContext -> { + final var guiName = (String) commandContext.get("guiName"); + + var openGuiAction = new OpenGuiAction(main); + openGuiAction.setGuiName(guiName); + + main.getActionManager().addAction(openGuiAction, commandContext, actionFor); + })); + + } + + + @Override + public String getActionDescription(QuestPlayer questPlayer, Object... objects) { + return "Opens a gui with given name for the player"; + } + + @Override + protected void executeInternally(QuestPlayer questPlayer, Object... objects) { + final var player = questPlayer.getPlayer(); + if(player == null) { + main.getLogManager() + .warn("Tried to execute PlayerCommand action with invalid player."); + return; + } + + if (Bukkit.isPrimaryThread()) { + main.getGuiService().showGui(guiName, player); + } else { + Bukkit.getScheduler() + .runTask(main.getMain(), () -> main.getGuiService().showGui(guiName, player)); + } + } + + @Override + public void save(FileConfiguration configuration, String initialPath) { + configuration.set(initialPath + ".specifics.guiName", getGuiName()); + } + + @Override + public void load(FileConfiguration configuration, String initialPath) { + this.guiName = configuration.getString(initialPath + ".specifics.guiName"); + } + + @Override + public void deserializeFromSingleLineString(ArrayList arguments) { + this.guiName = arguments.get(0); + } + + public final String getGuiName() { + return guiName; + } + + public void setGuiName(String guiName) { + this.guiName = guiName; + } +} diff --git a/paper/src/main/resources/guis/testgui.xml b/paper/src/main/resources/guis/testgui.xml new file mode 100644 index 000000000..d0042a635 --- /dev/null +++ b/paper/src/main/resources/guis/testgui.xml @@ -0,0 +1,16 @@ + + + + + + + Shop + + + Spawn + + + Home + + + \ No newline at end of file From 6724af97949dd64e5d5240d4966d31641534546d Mon Sep 17 00:00:00 2001 From: Jakob Reiser Date: Wed, 22 Feb 2023 14:52:08 +0100 Subject: [PATCH 02/15] Forgot some things in prev. commit :^) --- paper/build.gradle.kts | 7 +- .../gravili/notquests/paper/NotQuests.java | 23 +++++++ .../paper/commands/AdminCommands.java | 17 +++++ .../notquests/paper/gui/GuiActions.java | 68 ++++++++++++++++++- 4 files changed, 113 insertions(+), 2 deletions(-) diff --git a/paper/build.gradle.kts b/paper/build.gradle.kts index 5ca941076..c3ad8710c 100644 --- a/paper/build.gradle.kts +++ b/paper/build.gradle.kts @@ -213,7 +213,9 @@ dependencies { } //Else it errors: implementation("io.leangen.geantyref:geantyref:1.3.13") - //Interfaces + //Interfaces + InventoryFramework + implementation("com.github.stefvanschie.inventoryframework:IF:0.10.8") + implementation("org.incendo.interfaces:interfaces-core:1.0.0-SNAPSHOT") implementation("org.incendo.interfaces:interfaces-paper:1.0.0-SNAPSHOT") { @@ -288,6 +290,7 @@ tasks.withType { relocate("net.kyori.adventure.text.serializer.bungeecord", "$shadowPath.kyori.bungeecord") + relocate("com.github.stefvanschie.inventoryframework", "$shadowPath.if") relocate("org.incendo.interfaces", "$shadowPath.interfaces") relocate("redempt.crunch", "$shadowPath.crunch") @@ -315,6 +318,8 @@ tasks.withType { //include(dependency('io.github.retrooper.packetevents:') include(dependency("com.github.AlessioGr.packetevents:")) + + include(dependency("com.github.stefvanschie.inventoryframework:")) include(dependency("org.incendo.interfaces:")) //include(dependency('net.kyori:adventure-platform-bukkit:') diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/NotQuests.java b/paper/src/main/java/rocks/gravili/notquests/paper/NotQuests.java index fed5d13de..b6d9a2616 100644 --- a/paper/src/main/java/rocks/gravili/notquests/paper/NotQuests.java +++ b/paper/src/main/java/rocks/gravili/notquests/paper/NotQuests.java @@ -18,6 +18,7 @@ package rocks.gravili.notquests.paper; +import com.github.stefvanschie.inventoryframework.gui.type.util.Gui; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; @@ -35,6 +36,9 @@ import rocks.gravili.notquests.paper.events.QuestEvents; import rocks.gravili.notquests.paper.events.TriggerEvents; import rocks.gravili.notquests.paper.events.notquests.NotQuestsFullyLoadedEvent; +import rocks.gravili.notquests.paper.gui.GuiService; +import rocks.gravili.notquests.paper.gui.propertytype.ActionPropertyType; +import rocks.gravili.notquests.paper.gui.propertytype.ConditionPropertyType; import rocks.gravili.notquests.paper.managers.*; import rocks.gravili.notquests.paper.managers.integrations.IntegrationsManager; import rocks.gravili.notquests.paper.managers.integrations.bstats.Metrics; @@ -85,6 +89,7 @@ public class NotQuests extends NotQuestsMainAbstract { private WebManager webManager; //Registering Managers + private GuiService guiService; private ObjectiveManager objectiveManager; private ConditionsManager conditionsManager; private ActionManager actionManager; @@ -162,6 +167,10 @@ public void onEnable() { //Create a new instance of the Performance Manager which will be re-used everywhere performanceManager = new PerformanceManager(this); + //Load all guis + Gui.registerProperty("actions", ActionPropertyType::of); + Gui.registerProperty("conditions", ConditionPropertyType::of); + reloadGuis(); actionsYMLManager = new ActionsYMLManager(this); conditionsYMLManager = new ConditionsYMLManager(this); @@ -284,6 +293,17 @@ public void onEnable() { } + + /** + * Loads all guis located in the gui folder + * Use this for refreshing guis after making changes in the gui files + */ + public void reloadGuis() { + guiService = new GuiService(this); + guiService.saveDefaultGuis(); + guiService.loadAllGuis(); + } + public void setupBStats() { //bStats statistics final int pluginId = 12824; // <- Plugin ID (on bstats) @@ -569,4 +589,7 @@ public final NPCManager getNPCManager() { return npcManager; } + public GuiService getGuiService() { + return guiService; + } } diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/commands/AdminCommands.java b/paper/src/main/java/rocks/gravili/notquests/paper/commands/AdminCommands.java index c24705e6c..3c262b05a 100644 --- a/paper/src/main/java/rocks/gravili/notquests/paper/commands/AdminCommands.java +++ b/paper/src/main/java/rocks/gravili/notquests/paper/commands/AdminCommands.java @@ -33,6 +33,9 @@ import java.util.Collections; import java.util.Date; import java.util.List; + +import com.gamingmesh.jobs.economy.PaymentData; +import com.github.retrooper.packetevents.protocol.packettype.PacketType; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.HoverEvent; @@ -277,6 +280,11 @@ public AdminCommands(final NotQuests main, PaperCommandManager ma })); + manager.command(builder.literal("testgui") + .handler((context) -> { + main.getGuiService().showGui("testgui", (Player) context.getSender()); + })); + manager.command(builder.literal("progress") .argument(SinglePlayerSelectorArgument.of("player"), ArgumentDescription.of("Player progress you want to see")) .argument(ActiveQuestSelector.of("activeQuest", main, "player"), ArgumentDescription.of("Quest name of the quest you wish to see the progress for.")) @@ -645,6 +653,15 @@ public AdminCommands(final NotQuests main, PaperCommandManager ma context.getSender().sendMessage(main.parse("Languages have been reloaded.")); })); + manager.command(builder.literal("reload", "load") + .literal("guis") + .meta(CommandMeta.DESCRIPTION, "Reload the guis from gui files.") + .handler((context) -> { + main.reloadGuis(); + context.getSender().sendMessage(Component.empty()); + context.getSender().sendMessage(main.parse("Languages have been reloaded.")); + })); + manager.command(builder.literal("reload", "load") .literal("conversations") .meta(CommandMeta.DESCRIPTION, "Reload the conversations from conversations files.") diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java index e85884bbd..7890c2bb8 100644 --- a/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java @@ -1,2 +1,68 @@ -package rocks.gravili.notquests.paper.gui;public class GuiAction { +package rocks.gravili.notquests.paper.gui; + +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import rocks.gravili.notquests.paper.NotQuests; +import rocks.gravili.notquests.paper.gui.propertytype.ActionPropertyType; +import rocks.gravili.notquests.paper.gui.propertytype.ConditionPropertyType; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class GuiActions { + + private final NotQuests notQuests; + + public GuiActions(NotQuests notQuests) { + this.notQuests = notQuests; + } + + public void cancelClick(InventoryClickEvent event) { + event.setCancelled(true); + } + + public void executeAction(InventoryClickEvent event, boolean close, ActionPropertyType actionExpressions, ConditionPropertyType conditionExpressions) { + + notQuests.getLogManager().debug("Actions called: "); + var actionStrings = cleanUpStrings(actionExpressions.toStringList()); + notQuests.getLogManager().debug("Witch conditions: "); + var conditionStrings = cleanUpStrings(conditionExpressions.toStringList()); + + if (notQuests.getConversationManager() == null) { + return; + } + + if (event.getWhoClicked() instanceof Player player) { + var questPlayer = notQuests.getQuestPlayerManager().getActiveQuestPlayer(player.getUniqueId()); + + var actions = notQuests.getConversationManager().parseActionString(actionStrings); + var conditions = notQuests.getConversationManager().parseConditionsString(conditionStrings); + + actions.forEach(action -> { + if (conditions != null) { + conditions.forEach(condition -> action.addCondition(condition, false, null, null)); + } + notQuests.getActionManager().executeActionWithConditions(action, questPlayer, player, true); + }); + if (close) { + player.closeInventory(); + } + } + } + + private List cleanUpStrings(List toClean) { + var newStrings = new ArrayList(); + toClean.forEach( + expression -> { + if (!expression.isBlank()) { + notQuests.getLogManager().debug(" -> after: " + expression); + var cleanedExpression = expression.replaceAll("^\\s*", ""); + newStrings.add(cleanedExpression); + notQuests.getLogManager().debug(" -> after: " + cleanedExpression); + } + } + ); + return newStrings; + } } From 54e20749e65cd212a31568b222943d6f660e8c9e Mon Sep 17 00:00:00 2001 From: Jakob Reiser Date: Sat, 18 Mar 2023 10:43:05 +0100 Subject: [PATCH 03/15] Rebase custom gui feature on InvUi + add support for more NotQuests default inventories --- common/build.gradle.kts | 33 +- paper/build.gradle.kts | 166 +++------- .../gravili/notquests/paper/NotQuests.java | 13 +- .../paper/commands/AdminCommands.java | 13 +- .../notquests/paper/gui/CustomGui.java | 211 +++++++++++++ .../notquests/paper/gui/GuiActions.java | 68 ----- .../notquests/paper/gui/GuiContext.java | 82 +++++ .../notquests/paper/gui/GuiService.java | 283 ++++++------------ .../notquests/paper/gui/item/ActionItem.java | 102 +++++++ .../paper/gui/item/CustomTabItem.java | 51 ++++ .../paper/gui/item/PageBackItem.java | 21 ++ .../paper/gui/item/PageForwardItem.java | 20 ++ .../paper/gui/item/ScrollDownItem.java | 20 ++ .../paper/gui/item/ScrollUpItem.java | 19 ++ .../paper/gui/panes/ActiveQuestsPane.java | 2 - .../paper/gui/panes/AvilableQuestspane.java | 2 - .../paper/gui/property/IconProperty.java | 25 ++ .../gui/property/types/BaseIconProperty.java | 5 + .../gui/property/types/ListIconProperty.java | 10 + .../property/types/StringIconProperty.java | 8 + .../gui/propertytype/ActionPropertyType.java | 21 -- .../propertytype/ConditionPropertyType.java | 21 -- .../typeserializer/IconTypeSerializer.java | 55 ++++ .../typeserializer/ItemTypeSerializer.java | 25 ++ .../notquests/paper/managers/FlagParser.java | 23 ++ .../paper/managers/LanguageManager.java | 104 +++---- .../managers/registering/ActionManager.java | 1 + .../structs/actions/CloseInventoryAction.java | 48 +++ .../paper/structs/actions/OpenGuiAction.java | 110 +++++-- paper/src/main/resources/guis/main-base.yml | 43 +++ .../src/main/resources/guis/main-tab-one.yml | 0 .../main/resources/guis/main-tab-three.yml | 15 + .../src/main/resources/guis/main-tab-two.yml | 15 + paper/src/main/resources/guis/testgui.xml | 16 - plugin/build.gradle.kts | 61 ++-- spigot/build.gradle.kts | 2 +- 36 files changed, 1107 insertions(+), 607 deletions(-) create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/CustomGui.java delete mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiContext.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ActionItem.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/item/CustomTabItem.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/item/PageBackItem.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/item/PageForwardItem.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ScrollDownItem.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ScrollUpItem.java delete mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/ActiveQuestsPane.java delete mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/AvilableQuestspane.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/property/IconProperty.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/BaseIconProperty.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/ListIconProperty.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/StringIconProperty.java delete mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ActionPropertyType.java delete mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ConditionPropertyType.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/typeserializer/IconTypeSerializer.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/gui/typeserializer/ItemTypeSerializer.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/managers/FlagParser.java create mode 100644 paper/src/main/java/rocks/gravili/notquests/paper/structs/actions/CloseInventoryAction.java create mode 100644 paper/src/main/resources/guis/main-base.yml create mode 100644 paper/src/main/resources/guis/main-tab-one.yml create mode 100644 paper/src/main/resources/guis/main-tab-three.yml create mode 100644 paper/src/main/resources/guis/main-tab-two.yml delete mode 100644 paper/src/main/resources/guis/testgui.xml diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 2d6718fac..a5d133d4e 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -29,12 +29,9 @@ version = rootProject.version repositories { mavenCentral() - //mavenLocal() - } dependencies { - //implementation("net.kyori:adventure-api:4.11.0") implementation("org.spongepowered:configurate-gson:4.1.2") } @@ -45,33 +42,17 @@ val shadowPath = "rocks.gravili.notquests.shadow" tasks.withType { minimize() - //relocate("net.kyori", "$shadowPath.kyori") relocate("org.spongepowered.configurate", "$shadowPath.configurate") dependencies { - //include(dependency("net.kyori:")) include(dependency("org.spongepowered:")) - - } - //archiveBaseName.set("notquests") + archiveClassifier.set("") } -/*processResources { - def props = [version: version] - inputs.properties props - filteringCharset 'UTF-8' - filesMatching('plugin.yml') { - expand props - } -}*/ tasks { - // Run reobfJar on build - //build { - // dependsOn(shadowJar) - //} compileJava { options.encoding = Charsets.UTF_8.name() options.release.set(17) @@ -84,18 +65,6 @@ tasks { } } -/*publishing { - publications { - create("maven") { - groupId = "rocks.gravili.notquests" - artifactId = "NotQuests" - version = "4.0.0-dev" - - from(components["java"]) - } - } -}*/ - publishing { repositories { maven { diff --git a/paper/build.gradle.kts b/paper/build.gradle.kts index c3ad8710c..562382ce4 100644 --- a/paper/build.gradle.kts +++ b/paper/build.gradle.kts @@ -16,12 +16,10 @@ * along with this program. If not, see . */ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar - plugins { `java-library` `maven-publish` - id("com.github.johnrengelman.shadow") + id("com.github.johnrengelman.shadow") version "7.1.2" id("io.papermc.paperweight.userdev") id("xyz.jpenilla.run-paper") } @@ -89,12 +87,6 @@ repositories { } } - /*maven("https://repo.minebench.de/"){ - content { - includeGroup("de.themoep") - } - }*/ - maven("https://mvn.lumine.io/repository/maven-public/") { content { includeGroup("io.lumine.xikage") @@ -102,15 +94,6 @@ repositories { } } - /*maven("https://betonquest.org/nexus/repository/betonquest/") { - content { - includeGroup("org.betonquest") - } - metadataSources { - artifact() - } - }*/ - maven("https://maven.enginehub.org/repo/") { content { includeGroup("com.sk89q.worldedit") @@ -153,17 +136,14 @@ repositories { } } - //mavenLocal() + maven("https://repo.xenondevs.xyz/releases") } dependencies { implementation(project(path= ":common", configuration= "shadow")) paperDevBundle("1.19.3-R0.1-SNAPSHOT") - //compileOnly("io.papermc.paper:paper-api:1.18.1-R0.1-SNAPSHOT!!") - //implementation("de.themoep:inventorygui:1.5-SNAPSHOT") - //compileOnly("net.citizensnpcs:citizens-main:2.0.30-SNAPSHOT") compileOnly(files("libs/citizens-2.0.30-8.jar")) compileOnly("me.clip:placeholderapi:2.11.2") @@ -173,9 +153,6 @@ dependencies { compileOnly("io.lumine:Mythic-Dist:5.2.0") compileOnly(files("libs/EliteMobs.jar")) compileOnly("com.github.UlrichBR:UClansV5-API:4.5") - compileOnly(files("libs/ProjectKorra-1.10.0.jar")) - //compileOnly(files("libs/UltimateJobs-0.2.0-SNAPSHOT.jar")) - compileOnly(files("libs/ProjectKorra-1.10.0.jar")) compileOnly(files("libs/BetonQuest-2.0.0-539.jar")) @@ -187,16 +164,12 @@ dependencies { compileOnly("net.luckperms:api:5.4") - //compileOnly "com.github.NEZNAMY:TAB:2.9.2" compileOnly("com.github.TownyAdvanced:Towny:0.98.4.4") compileOnly("com.github.Zrips:Jobs:v4.17.2") compileOnly("org.geysermc.floodgate:api:2.0-SNAPSHOT") - - - //Shaded @@ -213,8 +186,10 @@ dependencies { } //Else it errors: implementation("io.leangen.geantyref:geantyref:1.3.13") - //Interfaces + InventoryFramework - implementation("com.github.stefvanschie.inventoryframework:IF:0.10.8") + + //Interfaces + InvUI + + implementation("de.studiocode.invui:InvUI:0.10.2") implementation("org.incendo.interfaces:interfaces-core:1.0.0-SNAPSHOT") @@ -222,26 +197,12 @@ dependencies { exclude(group = "com.destroystokyo.paper", module = "paper-api") } - //compileOnly("com.mojang:brigadier:1.0.18") - - - //implementation 'com.github.retrooper.packetevents:bukkit:2.0-SNAPSHOT' implementation("com.github.AlessioGr.packetevents:bukkit:2.0-SNAPSHOT") implementation("com.jeff_media:SpigotUpdateChecker:3.0.0") - - //implementation 'commons-io:commons-io:2.11.0' - //implementation 'org.apache.commons:commons-text:1.9' - //implementation 'org.apache.commons:commons-lang3:3.12.0' - //implementation 'org.apache.commons:commons-lang:3.1' - - //implementation("io.netty:netty-all:4.1.74.Final") - - implementation("commons-io:commons-io:2.11.0") - //compileOnly("com.willfp:EcoBosses:8.0.0") compileOnly(files("libs/EcoBosses-v8.78.0.jar")) compileOnly("com.willfp:eco:6.38.3") @@ -266,118 +227,65 @@ dependencies { * Configure NotQuests for shading */ val shadowPath = "rocks.gravili.notquests.paper.shadow" -tasks.withType { - - minimize() - - //exclude('com.mojang:brigadier') - - //relocate('io.papermc.lib', path.concat('.paper')) - relocate("cloud.commandframework", "$shadowPath.cloud") - relocate("io.leangen.geantyref", "$shadowPath.geantyref") - relocate("de.themoep", "$shadowPath.de.themoep") - - relocate("org.apache.commons.io", "$shadowPath.commons.io") - //relocate("org.apache.commons.text", path.concat('.commons.text')) - //relocate("org.apache.commons.lang3", path.concat('.commons.lang')) - - relocate("io.github.retrooper.packetevents", "$shadowPath.packetevents.bukkit") - relocate("com.github.retrooper.packetevents", "$shadowPath.packetevents.api") - - //Packet Stuff - // relocate('net.kyori.adventure.text.serializer.bungeecord', path.concat('.kyori.bungeecord')) - //relocate('net.kyori.adventure.platform.bukkit', path.concat('.kyori.platform-bukkit')) - relocate("net.kyori.adventure.text.serializer.bungeecord", "$shadowPath.kyori.bungeecord") - - - relocate("com.github.stefvanschie.inventoryframework", "$shadowPath.if") - relocate("org.incendo.interfaces", "$shadowPath.interfaces") - - relocate("redempt.crunch", "$shadowPath.crunch") - - relocate("com.fasterxml.jackson", "$shadowPath.jackson") - relocate("org.apache.http", "$shadowPath.apache.http") - relocate("com.zaxxer.hikari", "$shadowPath.hikari") - - relocate("com.jeff_media.updatechecker", "$shadowPath.updatechecker") - - - dependencies { - //include(dependency('org.apache.commons:') - include(dependency("commons-io:commons-io:")) - - //include(dependency('io.papermc:paperlib') - //include(dependency("de.themoep:inventorygui:1.5-SNAPSHOT")) - include(dependency("cloud.commandframework:")) - include(dependency("io.leangen.geantyref:")) - include(dependency("me.lucko:")) +tasks { + assemble { + dependsOn(reobfJar) + } - include(dependency("com.github.retrooper.packetevents:")) - //include(dependency('io.github.retrooper.packetevents:') + build { + dependsOn(reobfJar) + } - include(dependency("com.github.AlessioGr.packetevents:")) + compileJava { + dependsOn(project(":common").tasks["assemble"]) + options.encoding = Charsets.UTF_8.name() + options.release.set(17) + } - include(dependency("com.github.stefvanschie.inventoryframework:")) - include(dependency("org.incendo.interfaces:")) + shadowJar { - //include(dependency('net.kyori:adventure-platform-bukkit:') - include(dependency("net.kyori:adventure-text-serializer-bungeecord:")) + relocate("cloud.commandframework", "$shadowPath.cloud") - include(dependency("com.github.Redempt:Crunch:")) + relocate("io.leangen.geantyref", "$shadowPath.geantyref") - include(dependency("com.fasterxml.jackson.dataformat:")) - include(dependency("com.fasterxml.jackson.core:")) + relocate("de.themoep", "$shadowPath.de.themoep") - include(dependency("org.apache.httpcomponents:")) + relocate("org.apache.commons.io", "$shadowPath.commons.io") - include(dependency("com.zaxxer:")) + relocate("io.github.retrooper.packetevents", "$shadowPath.packetevents.bukkit") - include(dependency("com.jeff_media:SpigotUpdateChecker:")) + relocate("com.github.retrooper.packetevents", "$shadowPath.packetevents.api") - } + //Packet Stuff + relocate("net.kyori.adventure.text.serializer.bungeecord", "$shadowPath.kyori.bungeecord") + relocate("de.studiocode", "$shadowPath.invui") - //archiveBaseName.set("notquests") - archiveClassifier.set("") + relocate("org.incendo.interfaces", "$shadowPath.interfaces") + relocate("redempt.crunch", "$shadowPath.crunch") - // configurations.forEach { println("E: " + it.toString()) } + relocate("com.fasterxml.jackson", "$shadowPath.jackson") - // println("Size: " + configurations.size) + relocate("org.apache.http", "$shadowPath.apache.http") + relocate("com.zaxxer.hikari", "$shadowPath.hikari") -} + relocate("com.jeff_media.updatechecker", "$shadowPath.updatechecker") - -tasks { - // Run reobfJar on build - //build { - // dependsOn(shadowJar) - //} - assemble { - dependsOn(reobfJar) - } - - build { - dependsOn(reobfJar) + archiveClassifier.set("") } - /*shadowJar { - dependsOn(reobfJar) - }*/ - - compileJava { - options.encoding = Charsets.UTF_8.name() - options.release.set(17) - } javadoc { options.encoding = Charsets.UTF_8.name() } + processResources { filteringCharset = Charsets.UTF_8.name() } + runServer { // Configure the Minecraft version for our task. // This is the only required configuration besides applying the plugin. diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/NotQuests.java b/paper/src/main/java/rocks/gravili/notquests/paper/NotQuests.java index b6d9a2616..8855e7109 100644 --- a/paper/src/main/java/rocks/gravili/notquests/paper/NotQuests.java +++ b/paper/src/main/java/rocks/gravili/notquests/paper/NotQuests.java @@ -18,7 +18,6 @@ package rocks.gravili.notquests.paper; -import com.github.stefvanschie.inventoryframework.gui.type.util.Gui; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; @@ -37,8 +36,6 @@ import rocks.gravili.notquests.paper.events.TriggerEvents; import rocks.gravili.notquests.paper.events.notquests.NotQuestsFullyLoadedEvent; import rocks.gravili.notquests.paper.gui.GuiService; -import rocks.gravili.notquests.paper.gui.propertytype.ActionPropertyType; -import rocks.gravili.notquests.paper.gui.propertytype.ConditionPropertyType; import rocks.gravili.notquests.paper.managers.*; import rocks.gravili.notquests.paper.managers.integrations.IntegrationsManager; import rocks.gravili.notquests.paper.managers.integrations.bstats.Metrics; @@ -167,10 +164,6 @@ public void onEnable() { //Create a new instance of the Performance Manager which will be re-used everywhere performanceManager = new PerformanceManager(this); - //Load all guis - Gui.registerProperty("actions", ActionPropertyType::of); - Gui.registerProperty("conditions", ConditionPropertyType::of); - reloadGuis(); actionsYMLManager = new ActionsYMLManager(this); conditionsYMLManager = new ConditionsYMLManager(this); @@ -190,7 +183,7 @@ public void onEnable() { updateManager = new UpdateManager(this); - guiManager = new GUIManager(this); + reloadGuis(); /* * Tell the Data Manager: Hey, NPCs have not been loaded yet. If this is set to false, the plugin will @@ -223,6 +216,8 @@ public void onEnable() { actionManager = new ActionManager(this); triggerManager = new TriggerManager(this); + guiManager = new GUIManager(this); + variablesManager.alreadyFullRegisteredVariables.addAll(variablesManager.getVariableIdentifiers()); commandManager.setupCommands(); @@ -300,7 +295,7 @@ public void onEnable() { */ public void reloadGuis() { guiService = new GuiService(this); - guiService.saveDefaultGuis(); + guiService.saveAllDefaultGuis(); guiService.loadAllGuis(); } diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/commands/AdminCommands.java b/paper/src/main/java/rocks/gravili/notquests/paper/commands/AdminCommands.java index 3c262b05a..030c3fdc6 100644 --- a/paper/src/main/java/rocks/gravili/notquests/paper/commands/AdminCommands.java +++ b/paper/src/main/java/rocks/gravili/notquests/paper/commands/AdminCommands.java @@ -29,6 +29,8 @@ import cloud.commandframework.bukkit.parsers.selector.SinglePlayerSelectorArgument; import cloud.commandframework.meta.CommandMeta; import cloud.commandframework.paper.PaperCommandManager; + +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -52,6 +54,7 @@ import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; +import org.spongepowered.configurate.ConfigurateException; import rocks.gravili.notquests.paper.NotQuests; import rocks.gravili.notquests.paper.commands.arguments.*; import rocks.gravili.notquests.paper.commands.arguments.variables.BooleanVariableValueArgument; @@ -280,11 +283,6 @@ public AdminCommands(final NotQuests main, PaperCommandManager ma })); - manager.command(builder.literal("testgui") - .handler((context) -> { - main.getGuiService().showGui("testgui", (Player) context.getSender()); - })); - manager.command(builder.literal("progress") .argument(SinglePlayerSelectorArgument.of("player"), ArgumentDescription.of("Player progress you want to see")) .argument(ActiveQuestSelector.of("activeQuest", main, "player"), ArgumentDescription.of("Quest name of the quest you wish to see the progress for.")) @@ -626,13 +624,14 @@ public AdminCommands(final NotQuests main, PaperCommandManager ma main.getDataManager().loadGeneralConfig(); main.getLanguageManager().loadLanguageConfig(false); + main.reloadGuis(); if(main.getConversationManager() != null) { main.getConversationManager().loadConversationsFromConfig(); }else{ context.getSender().sendMessage(" Loading conversations has been skipped: ConversationManager is null"); } context.getSender().sendMessage(Component.empty()); - context.getSender().sendMessage(main.parse("NotQuests general.yml, language configuration and conversations have been re-loaded. If you want to reload more, please use the ServerUtils plugin (available on spigot) or restart the server. This reload command does not reload the quests file or the database.")); + context.getSender().sendMessage(main.parse("NotQuests general.yml, language configuration, guis and conversations have been re-loaded. If you want to reload more, please use the ServerUtils plugin (available on spigot) or restart the server. This reload command does not reload the quests file or the database.")); })); manager.command(builder.literal("reload", "load") @@ -659,7 +658,7 @@ public AdminCommands(final NotQuests main, PaperCommandManager ma .handler((context) -> { main.reloadGuis(); context.getSender().sendMessage(Component.empty()); - context.getSender().sendMessage(main.parse("Languages have been reloaded.")); + context.getSender().sendMessage(main.parse("Guis have been reloaded.")); })); manager.command(builder.literal("reload", "load") diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/CustomGui.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/CustomGui.java new file mode 100644 index 000000000..a60a0d65a --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/CustomGui.java @@ -0,0 +1,211 @@ +package rocks.gravili.notquests.paper.gui; + +import de.studiocode.invui.gui.GUI; +import de.studiocode.invui.gui.builder.GUIBuilder; +import de.studiocode.invui.gui.builder.guitype.GUIType; +import de.studiocode.invui.gui.structure.Markers; +import de.studiocode.invui.gui.structure.Structure; +import de.studiocode.invui.item.Item; + +import rocks.gravili.notquests.paper.NotQuests; +import rocks.gravili.notquests.paper.gui.icon.Button; +import rocks.gravili.notquests.paper.gui.icon.ButtonType; +import rocks.gravili.notquests.paper.gui.icon.SpecialIconType; +import rocks.gravili.notquests.paper.gui.property.types.StringIconProperty; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class CustomGui { + private final String pathToTitle; + private final String type; + private String[] structure; + private final Map icons; + private final List additionalGuis; + private NotQuests notQuests; + + private GUI gui; + + public CustomGui(String[] structure, String pathToTitle, String type, Map icons, List additionalGuis) { + this.pathToTitle = pathToTitle; + this.structure = structure; + this.type = type; + this.icons = icons; + this.additionalGuis = additionalGuis; + } + + public GUI buildGui(NotQuests notQuests, GuiContext guiContext) { + this.notQuests = notQuests; + + switch (type) { + case "TAB" -> this.gui = handleTabGui(guiContext); + case "PAGED_ITEMS" -> this.gui = handlePagedItemsGui(guiContext); + /* + case "PAGED_GUIS" -> this.gui = handlePagedGuisGui(guiObjectContext); + case "SCROLL_ITEMS" -> this.gui = handleScrollItemsGui(guiObjectContext); + case "SCROLL_GUIS" -> this.gui = handleScrollGuisGui(guiObjectContext); + + */ + default -> this.gui = handleNormalGui(guiContext); + } + return this.gui; + } + + + + private SpecialIconType fetchSpecialIconType(Button icon) { + SpecialIconType specialIconType; + if (icon.getIconProperty("specialicontype").isEmpty()) { + specialIconType = SpecialIconType.DEFAULT; + notQuests.getLogManager().debug("Case 1 " + icon.getType()); + } else { + if (icon.getIconProperty("specialicontype").get().getValue() instanceof StringIconProperty stringIconProperty) { + notQuests.getLogManager().debug("Case 2 " + icon.getType()); + specialIconType = SpecialIconType.valueOf(stringIconProperty.value()); + notQuests.getLogManager().debug(specialIconType.name()); + } else { + notQuests.getLogManager().debug("Case 3 " + icon.getType()); + specialIconType = SpecialIconType.DEFAULT; + } + } + return specialIconType; + } + + private GUI handleNormalGui(GuiContext guiContext) { + var guibuilder = new GUIBuilder<>(GUIType.NORMAL).setStructure(structure); + + icons.forEach((key, icon) -> guibuilder.addIngredient(key, icon.buildItem(notQuests, guiContext))); + for (Object o : guiContext.getAsObjectArray()) { + notQuests.getLogManager().debug(String.valueOf(o)); + } + + return guibuilder.build(); + } + private GUI handlePagedItemsGui(GuiContext guiContext) { + var structureObject = new Structure(structure); + var targetQuestPlayer = notQuests.getQuestPlayerManager().getOrCreateQuestPlayerFromDatabase(guiContext.getPlayer().getUniqueId()); + + var guiBuilder = new GUIBuilder<>(GUIType.PAGED_ITEMS).setStructure(structure); + + //X and Y are reserved characters! + var pagedIcon = icons.get('X'); + var fillerIcon = icons.get('Y'); + + if (pagedIcon == null) { + notQuests.getLogManager().debug("Paged icon null"); + return guiBuilder.build(); + } + + + var pagedIconSpecialType = fetchSpecialIconType(pagedIcon); + + guiBuilder.addIngredient('X', Markers.ITEM_LIST_SLOT_HORIZONTAL); + structureObject.addIngredient('X', Markers.ITEM_LIST_SLOT_HORIZONTAL); + + var items = new ArrayList(); + var guiSize = structureObject.getIngredientList().findItemListSlots().length; + var numberOfTotalItems = guiSize; + + switch (pagedIconSpecialType) { + case PLAYER_ACTIVE_QUEST -> { + numberOfTotalItems = guiSize * ((targetQuestPlayer.getActiveQuests().size() / guiSize) + 1); + targetQuestPlayer.getActiveQuests().forEach(activeQuest -> { + if (activeQuest != null) { + var itemGuiContext = guiContext.clone(); + itemGuiContext.setActiveQuest(activeQuest); + items.add(pagedIcon.buildItem(notQuests, itemGuiContext)); + } + }); + } + + case NPC_SHOWN_QUEST -> { + if (guiContext.getNqnpc() != null) { + var npc = guiContext.getNqnpc(); + var npcQuests = notQuests.getQuestManager().getQuestsFromListWithVisibilityEvaluations(targetQuestPlayer, notQuests.getQuestManager().getQuestsAttachedToNPCWithShowing(npc)); + npcQuests.forEach(quest -> notQuests.getLogManager().info(quest.getIdentifier())); + numberOfTotalItems = guiSize * ((npcQuests.size() / guiSize) + 1); + npcQuests.forEach(quest -> { + var itemGuiContext = guiContext.clone(); + itemGuiContext.setQuest(quest); + items.add(pagedIcon.buildItem(notQuests, itemGuiContext)); + }); + } + } + case CATEGORY -> { + + } + case DEFAULT -> items.add(pagedIcon.buildItem(notQuests, guiContext)); + } + + if (fillerIcon != null) { + while(items.size() < numberOfTotalItems) { + items.add(fillerIcon.buildItem(notQuests, guiContext)); + } + } + + icons.forEach((key, icon) -> { + if (icon == null) { + return; + } + if (fetchSpecialIconType(icon) != SpecialIconType.DEFAULT) { + return; + } + guiBuilder.addIngredient(key, icon.buildItem(notQuests, guiContext)); + }); + + + guiBuilder.setItems(items); + + return guiBuilder.build(); + } + + /* + private GUI handlePagedGuisGui(GuiObjectContext guiObjectContext) {} + private GUI handleScrollItemsGui(GuiObjectContext guiObjectContext){} + private GUI handleScrollGuisGui(GuiObjectContext guiObjectContext) {} + + */ + private GUI handleTabGui(GuiContext guiContext) { + var tabGuis = new ArrayList(); + + additionalGuis.forEach(string -> { + var tabGui = notQuests.getGuiService().getGuis().get(string); + if (tabGui == null) { + return; + } + + tabGuis.add(tabGui.buildGui(notQuests, guiContext)); + }); + + var guiBuilder = new GUIBuilder<>(GUIType.TAB) + .setStructure(structure) + .setGUIs(tabGuis) + .addIngredient('X', Markers.ITEM_LIST_SLOT_HORIZONTAL); + + icons.forEach((key, icon) -> { + if (icon == null) { + return; + } + if (icon.getType() == ButtonType.PAGED) { + return; + } + guiBuilder.addIngredient(key, icon.buildItem(notQuests, guiContext)); + }); + + return guiBuilder.build(); + } + + + public String getPathToTitle() { + return pathToTitle; + } + + public String getType() { + return type; + } + + public Map getIcons() { + return icons; + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java deleted file mode 100644 index 7890c2bb8..000000000 --- a/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiActions.java +++ /dev/null @@ -1,68 +0,0 @@ -package rocks.gravili.notquests.paper.gui; - -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryClickEvent; -import rocks.gravili.notquests.paper.NotQuests; -import rocks.gravili.notquests.paper.gui.propertytype.ActionPropertyType; -import rocks.gravili.notquests.paper.gui.propertytype.ConditionPropertyType; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class GuiActions { - - private final NotQuests notQuests; - - public GuiActions(NotQuests notQuests) { - this.notQuests = notQuests; - } - - public void cancelClick(InventoryClickEvent event) { - event.setCancelled(true); - } - - public void executeAction(InventoryClickEvent event, boolean close, ActionPropertyType actionExpressions, ConditionPropertyType conditionExpressions) { - - notQuests.getLogManager().debug("Actions called: "); - var actionStrings = cleanUpStrings(actionExpressions.toStringList()); - notQuests.getLogManager().debug("Witch conditions: "); - var conditionStrings = cleanUpStrings(conditionExpressions.toStringList()); - - if (notQuests.getConversationManager() == null) { - return; - } - - if (event.getWhoClicked() instanceof Player player) { - var questPlayer = notQuests.getQuestPlayerManager().getActiveQuestPlayer(player.getUniqueId()); - - var actions = notQuests.getConversationManager().parseActionString(actionStrings); - var conditions = notQuests.getConversationManager().parseConditionsString(conditionStrings); - - actions.forEach(action -> { - if (conditions != null) { - conditions.forEach(condition -> action.addCondition(condition, false, null, null)); - } - notQuests.getActionManager().executeActionWithConditions(action, questPlayer, player, true); - }); - if (close) { - player.closeInventory(); - } - } - } - - private List cleanUpStrings(List toClean) { - var newStrings = new ArrayList(); - toClean.forEach( - expression -> { - if (!expression.isBlank()) { - notQuests.getLogManager().debug(" -> after: " + expression); - var cleanedExpression = expression.replaceAll("^\\s*", ""); - newStrings.add(cleanedExpression); - notQuests.getLogManager().debug(" -> after: " + cleanedExpression); - } - } - ); - return newStrings; - } -} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiContext.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiContext.java new file mode 100644 index 000000000..dfafea5ee --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiContext.java @@ -0,0 +1,82 @@ +package rocks.gravili.notquests.paper.gui; + +import org.bukkit.entity.Player; +import rocks.gravili.notquests.paper.managers.data.Category; +import rocks.gravili.notquests.paper.managers.npc.NQNPC; +import rocks.gravili.notquests.paper.structs.ActiveQuest; +import rocks.gravili.notquests.paper.structs.Quest; + +public class GuiContext { + private Player player; + private Quest quest; + private ActiveQuest activeQuest; + private NQNPC nqnpc; + + private Category category; + + public GuiContext() { + + } + + public GuiContext(Player player, Quest quest, ActiveQuest activeQuest, NQNPC nqnpc, Category category) { + this.player = player; + this.quest = quest; + this.activeQuest = activeQuest; + this.nqnpc = nqnpc; + this.category = category; + } + + public Player getPlayer() { + return player; + } + + public void setPlayer(Player player) { + this.player = player; + } + + public Quest getQuest() { + return quest; + } + + public ActiveQuest getActiveQuest() { + return activeQuest; + } + + public void setQuest(Quest quest) { + this.quest = quest; + } + + public void setActiveQuest(ActiveQuest activeQuest) { + this.activeQuest = activeQuest; + } + + public NQNPC getNqnpc() { + return nqnpc; + } + + public void setNqnpc(NQNPC nqnpc) { + this.nqnpc = nqnpc; + } + + public Category getCategory() { + return category; + } + + public void setCategory(Category category) { + this.category = category; + } + + public Object[] getAsObjectArray() { + return new Object[]{ + player, + activeQuest, + quest, + nqnpc, + category + }; + } + + public GuiContext clone() { + return new GuiContext(player, quest, activeQuest, nqnpc, category); + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiService.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiService.java index e5793e31e..b87ec5b3a 100644 --- a/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiService.java +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/GuiService.java @@ -1,248 +1,161 @@ package rocks.gravili.notquests.paper.gui; -import com.github.stefvanschie.inventoryframework.exception.XMLLoadException; -import com.github.stefvanschie.inventoryframework.gui.type.*; -import com.github.stefvanschie.inventoryframework.gui.type.util.Gui; -import com.github.stefvanschie.inventoryframework.gui.type.util.NamedGui; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import de.studiocode.inventoryaccess.component.AdventureComponentWrapper; +import de.studiocode.invui.window.impl.single.SimpleWindow; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; +import org.spongepowered.configurate.CommentedConfigurationNode; +import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.yaml.YamlConfigurationLoader; import rocks.gravili.notquests.paper.NotQuests; +import rocks.gravili.notquests.paper.gui.icon.Button; +import rocks.gravili.notquests.paper.gui.icon.Icon; +import rocks.gravili.notquests.paper.gui.typeserializer.IconTypeSerializer; +import rocks.gravili.notquests.paper.gui.typeserializer.ItemTypeSerializer; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; +import java.util.logging.Level; public class GuiService { private final NotQuests notQuests; - - // TODO: add a config variable for that - private static final String EMPTY_DISPLAYNAME_KEYWORD = "EMPTY"; - private final GuiActions guiActions; - private final Map guis; + private final Map guis; + private final Set knownProperties; public GuiService(NotQuests notQuests) { this.notQuests = notQuests; this.guis = new HashMap<>(); - this.guiActions = new GuiActions(notQuests); + this.knownProperties = new HashSet<>(); } - /** - * Saves all default guis to the guis folder of the plugin - */ - public void saveDefaultGuis() { - saveDefaultGui("testgui"); + public void showGui(String guiName, Player player, GuiContext guiContext) { + + var customGui = guis.get(guiName); + if (customGui == null) { + notQuests.getLogManager().info("Failed showing gui '" + guiName + "' to player " + player.getName()); + return; + } + var title = new AdventureComponentWrapper(notQuests.getLanguageManager().getComponent(customGui.getPathToTitle(), player, guiContext.getAsObjectArray())); + var window = new SimpleWindow(player, title, customGui.buildGui(notQuests, guiContext)); + window.show(); } - /** - * Saves a gui with the specified name from the resources folder to the guis folder of the plugin - * @param name the name of the gui that should be saved - */ - public void saveDefaultGui(String name){ - notQuests.getMain().saveResource(Paths.get("guis/", name + ".xml").toString(), false); + public void saveAllDefaultGuis() { + saveDefaultGui("main-base"); + saveDefaultGui("main-tab-one"); + saveDefaultGui("main-tab-two"); + saveDefaultGui("main-tab-three"); } - /** - * Loads a Gui from an XML file located in a specified folder - * @param guisFolder the folder in which the gui is located - * @param fileName the name of the gui file. The name is also used to identify the gui later on - */ - public void loadGui(Path guisFolder, String fileName) { - var guiPath = guisFolder.resolve(fileName); - Gui gui = null; - try (InputStream inputStream = Files.newInputStream(guiPath)) { - gui = Gui.load(guiActions, inputStream); - var guiName = fileName.replace(".xml", ""); - guis.put(guiName, gui); - } catch (IOException e) { - notQuests.getLogManager().warn("Failed to load gui with name ' " + fileName + "' See below for more information", e); - e.printStackTrace(); - } catch (XMLLoadException e) { - notQuests.getLogManager().warn("Failed to load gui with name ' " + fileName + "'", e); - notQuests.getLogManager().warn("Type: Error in XML syntax, see below for more information "); - e.printStackTrace(); - } + public void saveDefaultGui(String guiName) { + notQuests.getMain().saveResource("guis/" + guiName + ".yml", false); } - /** - * Loads all guis found in the predefined folder into the gui storage - */ public void loadAllGuis() { var guisFolder = notQuests.getMain().getDataFolder().toPath().resolve(Paths.get("guis")); var fileNames = guisFolder.toFile().list(); if (fileNames == null) { - saveDefaultGuis(); - loadAllGuis(); + notQuests.getLogManager().warn("No guis found"); return; } - Arrays.stream(fileNames).filter(fileName -> fileName.endsWith(".xml")).forEach(fileName -> { + Arrays.stream(fileNames).filter(fileName -> fileName.endsWith(".yml")).forEach(fileName -> { + notQuests.getLogManager().info("Found gui file: " + fileName + ""); + notQuests.getLogManager().info("Attempting to load gui from file..."); loadGui(guisFolder, fileName); }); } - /** - * Opens the first gui matching the given name for the player - * @param guiName the nome of the gui that should be opened - * @param player the player to open the gui for - */ - public void showGui(String guiName, Player player) { - var firstMatch = guis.get(guiName); + public void loadGui(Path path, String name) { + var guiName = name.replace(".yml", ""); + var guiPath = path.resolve(Paths.get(name)); + var yamlLoader = YamlConfigurationLoader.builder() + .path(guiPath) + .defaultOptions(opts -> opts.serializers(build -> build.register(Button.class, new IconTypeSerializer()))) + .defaultOptions(opts -> opts.serializers(build -> build.register(Icon.class, new ItemTypeSerializer()))) + .build(); - if (firstMatch == null) { - // TODO: Error message - return; - } - - var gui = firstMatch.copy(); + CommentedConfigurationNode rootNode = null; - var langManager = notQuests.getLanguageManager(); + try { + rootNode = yamlLoader.load(); + } catch (ConfigurateException e) { + notQuests.getLogManager().warn("Failed loading gui '" + name + "'", e); + notQuests.getMain().getLogger().log(Level.WARNING, "Error:", e); - // Replace title path with actual title - if (gui instanceof NamedGui namedGui) { - var title = LegacyComponentSerializer.legacySection().serialize(langManager.getComponent(namedGui.getTitle(), player)); - namedGui.setTitle(title); + return; } - /* - CRAFTING TABLE: replace display name and lore for all items - */ - if (gui instanceof CraftingTableGui craftingTableGui) { - craftingTableGui.getInputComponent().getPanes().forEach( - pane -> pane.getItems().forEach( - guiItem -> { - var itemStack = getWithReplacedLoreAndDisplayName(guiItem.getItem(), player); - guiItem.setItem(itemStack); - } - ) - - ); - craftingTableGui.getOutputComponent().getPanes().forEach( - pane -> pane.getItems().forEach( - guiItem -> { - var itemStack = getWithReplacedLoreAndDisplayName(guiItem.getItem(), player); - guiItem.setItem(itemStack); - } - ) - ); - } + List structure = null; - /* - CHEST: replace display name and lore for all items - */ - if (gui instanceof ChestGui chestGui) { - chestGui.getInventoryComponent().getPanes().forEach( - pane -> pane.getItems().forEach( - guiItem -> { - var itemStack = getWithReplacedLoreAndDisplayName(guiItem.getItem(), player); - guiItem.setItem(itemStack); - } - ) - ); + try { + structure = rootNode.node("structure").getList(String.class); + } catch (SerializationException e) { + notQuests.getLogManager().warn("An error occurred while loading the gui " + name); + notQuests.getMain().getLogger().log(Level.WARNING, "ERROR:", e); } - /* - HOPPER: replace display name and lore for all items - */ - if (gui instanceof HopperGui hopperGui) { - hopperGui.getSlotsComponent().getPanes().forEach( - pane -> pane.getItems().forEach( - guiItem -> { - var itemStack = getWithReplacedLoreAndDisplayName(guiItem.getItem(), player); - guiItem.setItem(itemStack); - } - ) - ); + if (structure == null) { + notQuests.getLogManager().warn("An error occurred while loading the gui " + name); + notQuests.getLogManager().warn("ERROR: No structure specified"); + return; } - /* - DROPPER: replace display name and lore for all items - */ - if (gui instanceof DropperGui dropperGui) { - dropperGui.getContentsComponent().getPanes().forEach( - pane -> pane.getItems().forEach( - guiItem -> { - var itemStack = getWithReplacedLoreAndDisplayName(guiItem.getItem(), player); - guiItem.setItem(itemStack); - } - - ) - ); + var type = rootNode.node("type").getString(); + if (type == null) { + type = "NORMAL"; } - // TODO: Implement missing gui types - - // Important for the changes to take effect - gui.update(); + var pathToTitle = rootNode.node("title").getString(); - // Open the gui for the player - gui.show(player); - } + // Load gui "tabs" + var additionalGuis = List.of(""); + try { + additionalGuis = rootNode.node("additionalguis").getList(String.class); + } catch (SerializationException e) { + notQuests.getLogManager().warn("An error occurred while loading the gui " + name); + notQuests.getMain().getLogger().log(Level.WARNING, "Error:", e); + } - /** - * Replace display name and lore for given item - * @param itemStack the item to replace lore and display name - * @param player the player which the placeholders should be replaced for - * @return the item with new lore and display name - */ - private ItemStack getWithReplacedLoreAndDisplayName(ItemStack itemStack, Player player) { - var newLore = fetchLore(itemStack, player); - itemStack.lore(newLore); - var displayName = fetchDisplayName(itemStack, player); - var itemMeta = itemStack.getItemMeta(); - itemMeta.displayName(displayName); - itemStack.setItemMeta(itemMeta); + var iconsMap = rootNode.node("icons").childrenMap(); + var icons = new HashMap(); + iconsMap.forEach((key, node) -> { + try { + var icon = iconsMap.get(key).get(Button.class); + icons.put(String.valueOf(key).charAt(0), icon); + } catch (SerializationException | IllegalArgumentException e) { + notQuests.getLogManager().warn("An error occurred while loading the gui " + name); + notQuests.getMain().getLogger().log(Level.WARNING, "Error:", e); + } - return itemStack; - } + }); - /** - * Retrieve the lore of an item assuming the current first lore line is a path to the actual lore - * @param itemStack the item for which we are looking for the lore - * @param player the player for whom we want to replace the placeholders in the lore - * @return the new lore as a component list with all placeholder replaced - */ - private List fetchLore(ItemStack itemStack, Player player) { - var currentLore = itemStack.lore(); - if (currentLore == null) { - return Collections.emptyList(); - } - var loreConfigPath = PlainTextComponentSerializer.plainText().serialize(currentLore.get(0)); - return notQuests.getLanguageManager().getComponentList(loreConfigPath, player); - } + var itemsMap = rootNode.node("items").childrenMap(); + var items = new HashMap(); + itemsMap.forEach((key, node) -> { + try { + var item = itemsMap.get(key).get(Icon.class); + items.put(String.valueOf(key), item); + } catch (SerializationException e) { + notQuests.getLogManager().warn("An error occurred while loading the gui " + name); + notQuests.getMain().getLogger().log(Level.WARNING, "Error:", e); + } - /** - * Retrieve the display name of an item assuming that the current display name is a path to the actual name - * @param itemStack the item for which we are looking for the display name - * @param player the player for whom we want to replace the placeholders in the display name - * @return the new lore as a component list with all placeholder replaced - */ - private Component fetchDisplayName(ItemStack itemStack, Player player) { - var currentDisplayName = itemStack.displayName(); + }); - var displayNameAsString = PlainTextComponentSerializer.plainText().serialize(currentDisplayName).replace("[", "").replace("]", ""); + icons.forEach((key, icon) -> icon.registerIcons(items)); - if (displayNameAsString.equalsIgnoreCase(EMPTY_DISPLAYNAME_KEYWORD)) { - return Component.empty(); - } + var customGui = new CustomGui(structure.toArray(String[]::new), pathToTitle, type, icons, additionalGuis); - return notQuests.getLanguageManager().getComponent(displayNameAsString, player); + guis.put(guiName, customGui); } - /** - * Returns a with all guis and their names - * @return A map with all guis, identified by their names - */ - public final Map getGuis() { + public Map getGuis() { return guis; } } diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ActionItem.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ActionItem.java new file mode 100644 index 000000000..36cda95d9 --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ActionItem.java @@ -0,0 +1,102 @@ +package rocks.gravili.notquests.paper.gui.item; + +import de.studiocode.invui.item.ItemProvider; +import de.studiocode.invui.item.ItemWrapper; +import de.studiocode.invui.item.impl.BaseItem; +import me.clip.placeholderapi.PlaceholderAPI; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.jetbrains.annotations.NotNull; +import rocks.gravili.notquests.paper.NotQuests; +import rocks.gravili.notquests.paper.gui.GuiContext; +import rocks.gravili.notquests.paper.gui.icon.Button; +import rocks.gravili.notquests.paper.gui.property.types.ListIconProperty; +import rocks.gravili.notquests.paper.structs.QuestPlayer; +import rocks.gravili.notquests.paper.structs.actions.Action; +import rocks.gravili.notquests.paper.structs.conditions.Condition; + +import java.util.ArrayList; +import java.util.List; + +public class ActionItem extends BaseItem { + + private final NotQuests notQuests; + private final Button icon; + private final GuiContext guiContext; + private final ItemWrapper itemWrapper; + + public ActionItem(NotQuests notQuests, ItemWrapper itemWrapper, Button icon, GuiContext guiContext) { + this.notQuests = notQuests; + this.itemWrapper = itemWrapper; + this.icon = icon; + this.guiContext = guiContext; + } + + @Override + public ItemProvider getItemProvider() { + return itemWrapper; + } + + @Override + public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) { + + if (notQuests.getConversationManager() == null) { + return; + } + + // get possible actions and replace all placeholders + var actionProperty = icon.getIconProperty("actions"); + if (actionProperty.isEmpty() || !(actionProperty.get().getValue() instanceof ListIconProperty listActionProperty)) { + return; + } + var replacedActionStrings = replaceWithPlaceholders(listActionProperty.value(), player, guiContext); + + // get possible conditions and replace all placeholders + var conditionProperty = icon.getIconProperty("conditions"); + + var questPlayer = notQuests.getQuestPlayerManager().getActiveQuestPlayer(player.getUniqueId()); + var actions = notQuests.getConversationManager().parseActionString(replacedActionStrings); + + List conditions = null; + + if (conditionProperty.isPresent() && actionProperty.get().getValue() instanceof ListIconProperty listConditionProperty) { + var replacedConditionStrings = replaceWithPlaceholders(listConditionProperty.value(), player, guiContext); + conditions = notQuests.getConversationManager().parseConditionsString(replacedConditionStrings); + } + + executeActionsWithConditions(actions, conditions, questPlayer); + } + + public void executeActionsWithConditions(List actions, List conditions, QuestPlayer questPlayer) { + actions.forEach(action -> { + if (conditions != null) { + conditions.forEach(condition -> action.addCondition(condition, false, null, null)); + } + notQuests.getActionManager().executeActionWithConditions(action, questPlayer, questPlayer.getPlayer(), true); + }); + } + + public List replaceWithPlaceholders(List toReplace, Player player, GuiContext guiContext) { + var replacedStrings = new ArrayList(); + + toReplace.forEach(actionString -> { + var replacedString = actionString; + + var languageManager = notQuests.getLanguageManager(); + if (!notQuests.getConfiguration().supportPlaceholderAPIInTranslationStrings || !notQuests.getIntegrationsManager().isPlaceholderAPIEnabled() || player == null) { + replacedString = languageManager.applySpecial( + languageManager.applyInternalPlaceholders(replacedString, player, guiContext.getAsObjectArray()) + ); + } else { + replacedString = languageManager.applySpecial(PlaceholderAPI.setPlaceholders( + player, languageManager.applyInternalPlaceholders( + replacedString, player, guiContext.getAsObjectArray() + )) + ); + } + replacedStrings.add(replacedString); + }); + return replacedStrings; + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/CustomTabItem.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/CustomTabItem.java new file mode 100644 index 000000000..43486c938 --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/CustomTabItem.java @@ -0,0 +1,51 @@ +package rocks.gravili.notquests.paper.gui.item; + +import de.studiocode.inventoryaccess.component.AdventureComponentWrapper; +import de.studiocode.invui.gui.impl.TabGUI; +import de.studiocode.invui.item.ItemProvider; +import de.studiocode.invui.item.ItemWrapper; +import de.studiocode.invui.item.impl.controlitem.TabItem; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Set; + +public class CustomTabItem extends TabItem { + + private final int tab; + private final List itemStacks; + private final Component newTitle; + public CustomTabItem(int tab, Component newTitle, List itemStacks) { + super(tab); + this.tab = tab; + this.itemStacks = itemStacks; + this.newTitle = newTitle; + } + + @Override + public ItemProvider getItemProvider(TabGUI gui) { + var activeTabItem = itemStacks.get(0); + var inactiveTabItem = itemStacks.get(0); + if (itemStacks.size() > 1) { + inactiveTabItem = itemStacks.get(1); + } + if (gui.getCurrentTab() == tab) { + return new ItemWrapper(activeTabItem); + } else { + return new ItemWrapper(inactiveTabItem); + } + } + + @Override + public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) { + super.handleClick(clickType, player, event); + var window = getWindows().stream().filter(w -> w.getCurrentViewer().equals(player)).findFirst().get(); + + window.changeTitle(new AdventureComponentWrapper(newTitle)); + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/PageBackItem.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/PageBackItem.java new file mode 100644 index 000000000..61584d5dd --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/PageBackItem.java @@ -0,0 +1,21 @@ +package rocks.gravili.notquests.paper.gui.item; + +import de.studiocode.invui.gui.impl.PagedGUI; +import de.studiocode.invui.item.ItemProvider; +import de.studiocode.invui.item.ItemWrapper; +import de.studiocode.invui.item.impl.controlitem.PageItem; + +public class PageBackItem extends PageItem { + + private ItemWrapper itemWrapper; + + public PageBackItem(ItemWrapper itemWrapper) { + super(false); + this.itemWrapper = itemWrapper; + } + + @Override + public ItemProvider getItemProvider(PagedGUI gui) { + return itemWrapper; + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/PageForwardItem.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/PageForwardItem.java new file mode 100644 index 000000000..b1be8e596 --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/PageForwardItem.java @@ -0,0 +1,20 @@ +package rocks.gravili.notquests.paper.gui.item; + +import de.studiocode.invui.gui.impl.PagedGUI; +import de.studiocode.invui.item.ItemProvider; +import de.studiocode.invui.item.ItemWrapper; +import de.studiocode.invui.item.impl.controlitem.PageItem; + +public class PageForwardItem extends PageItem { + private ItemWrapper itemWrapper; + + public PageForwardItem(ItemWrapper itemWrapper) { + super(true); + this.itemWrapper = itemWrapper; + } + + @Override + public ItemProvider getItemProvider(PagedGUI gui) { + return itemWrapper; + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ScrollDownItem.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ScrollDownItem.java new file mode 100644 index 000000000..2599218d8 --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ScrollDownItem.java @@ -0,0 +1,20 @@ +package rocks.gravili.notquests.paper.gui.item; + +import de.studiocode.invui.gui.impl.ScrollGUI; +import de.studiocode.invui.item.ItemProvider; +import de.studiocode.invui.item.ItemWrapper; +import de.studiocode.invui.item.impl.controlitem.ScrollItem; + +public class ScrollDownItem extends ScrollItem { + + private ItemWrapper itemWrapper; + public ScrollDownItem(ItemWrapper itemWrapper) { + super(1); + this.itemWrapper = itemWrapper; + } + + @Override + public ItemProvider getItemProvider(ScrollGUI gui) { + return itemWrapper; + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ScrollUpItem.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ScrollUpItem.java new file mode 100644 index 000000000..26d81422b --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/item/ScrollUpItem.java @@ -0,0 +1,19 @@ +package rocks.gravili.notquests.paper.gui.item; + +import de.studiocode.invui.gui.impl.ScrollGUI; +import de.studiocode.invui.item.ItemProvider; +import de.studiocode.invui.item.ItemWrapper; +import de.studiocode.invui.item.impl.controlitem.ScrollItem; + +public class ScrollUpItem extends ScrollItem { + private ItemWrapper itemWrapper; + public ScrollUpItem(ItemWrapper itemWrapper) { + super(-1); + this.itemWrapper = itemWrapper; + } + + @Override + public ItemProvider getItemProvider(ScrollGUI gui) { + return itemWrapper; + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/ActiveQuestsPane.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/ActiveQuestsPane.java deleted file mode 100644 index 3e34d874e..000000000 --- a/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/ActiveQuestsPane.java +++ /dev/null @@ -1,2 +0,0 @@ -package rocks.gravili.notquests.paper.gui.panes;public class ActiveQuestsPane { -} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/AvilableQuestspane.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/AvilableQuestspane.java deleted file mode 100644 index ab746e412..000000000 --- a/paper/src/main/java/rocks/gravili/notquests/paper/gui/panes/AvilableQuestspane.java +++ /dev/null @@ -1,2 +0,0 @@ -package rocks.gravili.notquests.paper.gui.panes;public class AvilableQuestspane { -} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/IconProperty.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/IconProperty.java new file mode 100644 index 000000000..3df9ebb0e --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/IconProperty.java @@ -0,0 +1,25 @@ +package rocks.gravili.notquests.paper.gui.property; + +import rocks.gravili.notquests.paper.gui.property.types.BaseIconProperty; + +public class IconProperty { + private final String key; + private final BaseIconProperty value; + + private IconProperty(String key, BaseIconProperty value) { + this.key = key; + this.value = value; + } + + public static IconProperty of(String key, BaseIconProperty value) { + return new IconProperty(key, value); + } + + public String getKey() { + return key; + } + + public BaseIconProperty getValue() { + return value; + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/BaseIconProperty.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/BaseIconProperty.java new file mode 100644 index 000000000..8cb2c5423 --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/BaseIconProperty.java @@ -0,0 +1,5 @@ +package rocks.gravili.notquests.paper.gui.property.types; + +public interface BaseIconProperty { + +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/ListIconProperty.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/ListIconProperty.java new file mode 100644 index 000000000..25d3fb6e7 --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/ListIconProperty.java @@ -0,0 +1,10 @@ +package rocks.gravili.notquests.paper.gui.property.types; + +import java.util.List; + +public record ListIconProperty(List value) implements BaseIconProperty { + + public static ListIconProperty of(List value) { + return new ListIconProperty(value); + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/StringIconProperty.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/StringIconProperty.java new file mode 100644 index 000000000..09db4469e --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/property/types/StringIconProperty.java @@ -0,0 +1,8 @@ +package rocks.gravili.notquests.paper.gui.property.types; + +public record StringIconProperty(String value) implements BaseIconProperty { + + public static StringIconProperty of(String value) { + return new StringIconProperty(value); + } +} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ActionPropertyType.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ActionPropertyType.java deleted file mode 100644 index 12c915c35..000000000 --- a/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ActionPropertyType.java +++ /dev/null @@ -1,21 +0,0 @@ -package rocks.gravili.notquests.paper.gui.propertytype; - -import java.util.Arrays; -import java.util.List; - -public class ActionPropertyType { - private static final String STRING_REPRESENTATION = "action"; - private final String value; - - private ActionPropertyType(String value) { - this.value = value; - } - - public static ActionPropertyType of(String string) { - return new ActionPropertyType(string); - } - - public List toStringList() { - return Arrays.asList(value.split("\n")); - } -} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ConditionPropertyType.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ConditionPropertyType.java deleted file mode 100644 index 09c98848b..000000000 --- a/paper/src/main/java/rocks/gravili/notquests/paper/gui/propertytype/ConditionPropertyType.java +++ /dev/null @@ -1,21 +0,0 @@ -package rocks.gravili.notquests.paper.gui.propertytype; - -import java.util.Arrays; -import java.util.List; - -public class ConditionPropertyType { - private static final String STRING_REPRESENTATION = "action"; - private final String value; - - private ConditionPropertyType(String value) { - this.value = value; - } - - public static ConditionPropertyType of(String string) { - return new ConditionPropertyType(string); - } - - public List toStringList() { - return Arrays.asList(value.split("\n")); - } -} diff --git a/paper/src/main/java/rocks/gravili/notquests/paper/gui/typeserializer/IconTypeSerializer.java b/paper/src/main/java/rocks/gravili/notquests/paper/gui/typeserializer/IconTypeSerializer.java new file mode 100644 index 000000000..781ddbc3a --- /dev/null +++ b/paper/src/main/java/rocks/gravili/notquests/paper/gui/typeserializer/IconTypeSerializer.java @@ -0,0 +1,55 @@ +package rocks.gravili.notquests.paper.gui.typeserializer; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.TypeSerializer; +import rocks.gravili.notquests.paper.gui.icon.Button; +import rocks.gravili.notquests.paper.gui.icon.ButtonType; +import rocks.gravili.notquests.paper.gui.property.IconProperty; +import rocks.gravili.notquests.paper.gui.property.types.ListIconProperty; +import rocks.gravili.notquests.paper.gui.property.types.StringIconProperty; + +import java.lang.reflect.Type; +import java.util.HashSet; +import java.util.Set; + +public class IconTypeSerializer implements TypeSerializer