From 748781fd50cc31cbf8abf433c06bc10fc9904540 Mon Sep 17 00:00:00 2001 From: alexcrea Date: Sun, 31 Mar 2024 15:04:15 +0200 Subject: [PATCH 01/12] check permission on chat message --- .../cuanvil/gui/config/global/EnchantConflictGui.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java index f5cadf6..49f4302 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java @@ -151,6 +151,12 @@ private Consumer prepareCreateItemConsumer(HumanEntity player) { Consumer selfCallback = (message) -> { if (message == null) return; + // check permission + if (!player.hasPermission(CustomAnvil.editConfigPermission)) { + player.sendMessage(GuiGlobalActions.NO_EDIT_PERM); + return; + } + message = message.toLowerCase(Locale.ROOT); if ("cancel".equalsIgnoreCase(message)) { player.sendMessage("conflict creation cancelled..."); From 39ae8845b541532057884b50b90729e5518091af Mon Sep 17 00:00:00 2001 From: alexcrea Date: Fri, 5 Apr 2024 17:00:04 +0200 Subject: [PATCH 02/12] Add custom recipe manager. --- .../alexcrea/cuanvil/config/ConfigHolder.java | 25 ++++++ .../cuanvil/recipe/AnvilCustomRecipe.kt | 84 +++++++++++++++++++ .../recipe/CustomAnvilRecipeManager.kt | 65 ++++++++++++++ .../xyz/alexcrea/cuanvil/util/MetricsUtil.kt | 11 +++ src/main/resources/custom_recipes.yml | 5 ++ 5 files changed, 190 insertions(+) create mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt create mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/recipe/CustomAnvilRecipeManager.kt create mode 100644 src/main/resources/custom_recipes.yml diff --git a/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java b/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java index b7f351b..68d6f68 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java +++ b/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java @@ -6,6 +6,7 @@ import org.bukkit.configuration.file.YamlConfiguration; import xyz.alexcrea.cuanvil.group.EnchantConflictManager; import xyz.alexcrea.cuanvil.group.ItemGroupManager; +import xyz.alexcrea.cuanvil.recipe.CustomAnvilRecipeManager; import xyz.alexcrea.cuanvil.util.MetricsUtil; import java.io.File; @@ -18,12 +19,14 @@ public abstract class ConfigHolder { public static ItemGroupConfigHolder ITEM_GROUP_HOLDER; public static ConflictConfigHolder CONFLICT_HOLDER; public static UnitRepairHolder UNIT_REPAIR_HOLDER; + public static CustomAnvilCraftHolder CUSTOM_RECIPE_HOLDER; public static boolean loadConfig() { DEFAULT_CONFIG = new DefaultConfigHolder(); ITEM_GROUP_HOLDER = new ItemGroupConfigHolder(); CONFLICT_HOLDER = new ConflictConfigHolder(); UNIT_REPAIR_HOLDER = new UnitRepairHolder(); + CUSTOM_RECIPE_HOLDER = new CustomAnvilCraftHolder(); boolean result = reloadAllFromDisk(true); if (result) { @@ -41,6 +44,9 @@ public static boolean reloadAllFromDisk(boolean hardfail) { sucess = CONFLICT_HOLDER.reloadFromDisk(hardfail); if (!sucess) return false; sucess = UNIT_REPAIR_HOLDER.reloadFromDisk(hardfail); + if (!sucess) return false; + sucess = CUSTOM_RECIPE_HOLDER.reloadFromDisk(hardfail); + return sucess; } @@ -242,6 +248,7 @@ public void reload() { public static class UnitRepairHolder extends ResourceConfigHolder { private final static String ITEM_GROUP_FILE_NAME = "unit_repair_item"; + private UnitRepairHolder() { super(ITEM_GROUP_FILE_NAME); } @@ -253,4 +260,22 @@ public void reload() { } + // Class for custom anvil craft + public static class CustomAnvilCraftHolder extends ResourceConfigHolder { + private final static String CUSTOM_CRAFT_FILE_NAME = "custom_recipes"; + CustomAnvilRecipeManager recipeManager; + + private CustomAnvilCraftHolder() { + super(CUSTOM_CRAFT_FILE_NAME); + } + + @Override + public void reload() { + this.recipeManager = new CustomAnvilRecipeManager(); + this.recipeManager.prepareRecipes(this.configuration); + } + + } + + } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt new file mode 100644 index 0000000..584271e --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt @@ -0,0 +1,84 @@ +package xyz.alexcrea.cuanvil.recipe + +import org.bukkit.configuration.ConfigurationSection +import org.bukkit.inventory.ItemStack +import xyz.alexcrea.cuanvil.config.ConfigHolder +import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant + +class AnvilCustomRecipe( + val name: String, + var exactCount: Boolean, + var exactLeft: Boolean, + var exactRight: Boolean, + + var xpCostPerCraft: Int, + + var leftItem: ItemStack?, + var rightItem: ItemStack?, + var resultItem: ItemStack?, +) { + + // Static config name + companion object { + const val EXACT_COUNT_CONFIG = "exact_count" + const val EXACT_LEFT_CONFIG = "exact_left" + const val EXACT_RIGHT_CONFIG = "exact_right" + + const val XP_COST_CONFIG = "xp_cost" + + const val LEFT_ITEM_CONFIG = "left_item" + const val RIGHT_ITEM_CONFIG = "right_item" + const val RESULT_ITEM_CONFIG = "result_item" + + fun getFromConfig(name: String, configSection: ConfigurationSection?): AnvilCustomRecipe? { + if(configSection == null) return null; + return AnvilCustomRecipe( + name, + configSection.getBoolean(EXACT_COUNT_CONFIG, true), + configSection.getBoolean(EXACT_LEFT_CONFIG, true), + configSection.getBoolean(EXACT_RIGHT_CONFIG, true), + + configSection.getInt(XP_COST_CONFIG, 10), + + configSection.getItemStack(LEFT_ITEM_CONFIG, null), + configSection.getItemStack(RIGHT_ITEM_CONFIG, null), + configSection.getItemStack(RESULT_ITEM_CONFIG, null), + + ) + } + + fun getFromConfig(name: String): AnvilCustomRecipe? { + return getFromConfig(name, ConfigHolder.CUSTOM_RECIPE_HOLDER.config.getConfigurationSection(name)) + } + } + + fun validate(): Boolean { + return (leftItem != null) && !(leftItem!!.type.isAir) && (leftItem!!.amount > 0) && + //(rightItem != null) && !(rightItem!!.type.isAir) && (rightItem!!.amount > 0) && + ((rightItem == null) || (!(rightItem!!.type.isAir) && (rightItem!!.amount > 0))) && + (resultItem != null) && !(resultItem!!.type.isAir) && (resultItem!!.amount > 0) + + } + + fun saveToFile(){ + val fileConfig = ConfigHolder.CUSTOM_RECIPE_HOLDER.config + + fileConfig.set("$name.$EXACT_COUNT_CONFIG", exactCount) + fileConfig.set("$name.$EXACT_LEFT_CONFIG", exactLeft) + fileConfig.set("$name.$EXACT_RIGHT_CONFIG", exactRight) + + fileConfig.set("$name.$XP_COST_CONFIG", xpCostPerCraft) + + fileConfig.set("$name.$LEFT_ITEM_CONFIG", leftItem) + fileConfig.set("$name.$RIGHT_ITEM_CONFIG", rightItem) + fileConfig.set("$name.$RESULT_ITEM_CONFIG", resultItem) + + + if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) { + ConfigHolder.CONFLICT_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE); + } + } + + + +} diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/CustomAnvilRecipeManager.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/CustomAnvilRecipeManager.kt new file mode 100644 index 0000000..82f80be --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/CustomAnvilRecipeManager.kt @@ -0,0 +1,65 @@ +package xyz.alexcrea.cuanvil.recipe + +import io.delilaheve.CustomAnvil +import org.bukkit.Material +import org.bukkit.configuration.file.FileConfiguration +import org.bukkit.inventory.ItemStack +import java.util.LinkedHashMap + +class CustomAnvilRecipeManager { + + lateinit var recipeMap: LinkedHashMap + + lateinit var recipeByMat: LinkedHashMap> + + fun prepareRecipes(config: FileConfiguration) { + recipeMap = LinkedHashMap() + recipeByMat = LinkedHashMap() + + // read all configs + val keys = config.getKeys(false) + for (key in keys) { + if (recipeMap.containsKey(key)) + continue + val recipe = AnvilCustomRecipe.getFromConfig(key) + if(recipe == null){ + CustomAnvil.log("Can't load recipe $key") + continue + } + + recipeMap[key] = recipe + val leftItem = recipe.leftItem + if(leftItem != null){ + addToMap(recipe, leftItem) + } + } + + } + + fun cleanSetLeftItem(recipe: AnvilCustomRecipe, leftItem: ItemStack?){ + // Remove left item mat if exist + val oldLeftItem = recipe.leftItem + if(oldLeftItem != null){ + val oldMat = oldLeftItem.type + + val test = recipeByMat[oldMat] + test!!.remove(recipe) + } + if(leftItem != null){ + addToMap(recipe, leftItem) + } + + recipe.leftItem = leftItem + } + + fun addToMap(recipe: AnvilCustomRecipe, leftItem: ItemStack){ + var recipeList = recipeByMat[leftItem.type] + if(recipeList == null){ + recipeList = ArrayList() + recipeByMat[leftItem.type] = recipeList + } + recipeList.add(recipe) + + } + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/util/MetricsUtil.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/util/MetricsUtil.kt index 0f60e48..614116d 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/util/MetricsUtil.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/util/MetricsUtil.kt @@ -13,18 +13,21 @@ object MetricsUtil { private const val enchantConflictConfigHash = 1406650190 private const val itemGroupsConfigHash = 1406650190 private const val unitRepairItemConfigHash = 536871958 + private const val customAnvilCraftConfigHash = 0 private const val baseConfigPieName = "isDefaultBaseConfig" private const val enchantLimitsConfigPieName = "isDefaultEnchantLimitsConfig" private const val enchantValuesConfigPieName = "isDefaultEnchantValuesConfig" private const val enchantConflictConfigPieName = "isDefaultEnchantConflictConfig" private const val itemGroupsConfigPieName = "isDefaultItemGroupsConfig" private const val unitRepairItemConfigPieName = "isDefaultUnitRepairItemConfig" + private const val customAnvilCraftConfigPieName = "isDefaultCustomAnvilCraftConfig" private var isDefaultBaseConfig = true private var isDefaultEnchantLimitsConfig = true private var isDefaultEnchantValuesConfig = true private var isDefaultEnchantConflictConfig = true private var isDefaultItemGroupsConfig = true private var isDefaultUnitRepairItemConfig = true + private var isDefaultCustomAnvilCraftConfig = true /** * Get hash of a key, value a pair of a configuration section @@ -73,6 +76,7 @@ object MetricsUtil { val enchantConflictConfig = getConfigurationHash(ConfigHolder.CONFLICT_HOLDER.config) val itemGroupConfig = getConfigurationHash(ConfigHolder.ITEM_GROUP_HOLDER.config) val unitRepairConfig = getConfigurationHash(ConfigHolder.UNIT_REPAIR_HOLDER.config) + val customRecipeConfig = getConfigurationHash(ConfigHolder.CUSTOM_RECIPE_HOLDER.config) // Test if default isDefaultBaseConfig = baseConfigHash == baseConfig isDefaultEnchantLimitsConfig = enchantLimitsConfigHash == limitEnchantConfig @@ -80,6 +84,7 @@ object MetricsUtil { isDefaultEnchantConflictConfig = enchantConflictConfigHash == enchantConflictConfig isDefaultItemGroupsConfig = itemGroupsConfigHash == itemGroupConfig isDefaultUnitRepairItemConfig = unitRepairItemConfigHash == unitRepairConfig + isDefaultCustomAnvilCraftConfig = customAnvilCraftConfigHash == customRecipeConfig // If not default and debug flag active, print the hash. if (ConfigOptions.debugLog) { if (!isDefaultBaseConfig) { @@ -100,6 +105,9 @@ object MetricsUtil { if (!isDefaultUnitRepairItemConfig) { CustomAnvil.log("unitRepairConfig: $unitRepairConfig") } + if (!isDefaultCustomAnvilCraftConfig) { + CustomAnvil.log("customRecipeConfig: $customRecipeConfig") + } } } @@ -141,6 +149,9 @@ object MetricsUtil { metric.addCustomChart(Metrics.SimplePie(unitRepairItemConfigPieName) { isDefaultUnitRepairItemConfig.toString() }) + metric.addCustomChart(Metrics.SimplePie(customAnvilCraftConfigPieName) { + isDefaultCustomAnvilCraftConfig.toString() + }) } } \ No newline at end of file diff --git a/src/main/resources/custom_recipes.yml b/src/main/resources/custom_recipes.yml new file mode 100644 index 0000000..57c2220 --- /dev/null +++ b/src/main/resources/custom_recipes.yml @@ -0,0 +1,5 @@ +# ---------------------------------------------------- +# This config file is to store custom craft +# It is recommended to use the in game config editor for this configuration. +# /customanvilconfig With ca.config.edit permission +# ---------------------------------------------------- From 9f31d396ce7c27082c645a64d2f190dcdf406045 Mon Sep 17 00:00:00 2001 From: alexcrea Date: Fri, 5 Apr 2024 18:00:46 +0200 Subject: [PATCH 03/12] Add logic for custom recipe. Add default for custom recipe. --- .../alexcrea/cuanvil/config/ConfigHolder.java | 9 ++- .../io/delilaheve/AnvilEventListener.kt | 71 ++++++++++++++++++- .../cuanvil/recipe/AnvilCustomRecipe.kt | 61 ++++++++++++---- 3 files changed, 122 insertions(+), 19 deletions(-) diff --git a/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java b/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java index 68d6f68..6fafded 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java +++ b/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java @@ -262,11 +262,15 @@ public void reload() { // Class for custom anvil craft public static class CustomAnvilCraftHolder extends ResourceConfigHolder { - private final static String CUSTOM_CRAFT_FILE_NAME = "custom_recipes"; + private final static String CUSTOM_RECIPE_FILE_NAME = "custom_recipes"; CustomAnvilRecipeManager recipeManager; private CustomAnvilCraftHolder() { - super(CUSTOM_CRAFT_FILE_NAME); + super(CUSTOM_RECIPE_FILE_NAME); + } + + public CustomAnvilRecipeManager getRecipeManager() { + return recipeManager; } @Override @@ -274,7 +278,6 @@ public void reload() { this.recipeManager = new CustomAnvilRecipeManager(); this.recipeManager.prepareRecipes(this.configuration); } - } diff --git a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt index eab2c6b..0718d81 100644 --- a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt +++ b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt @@ -11,6 +11,7 @@ import io.delilaheve.util.ItemUtil.setEnchantmentsUnsafe import io.delilaheve.util.ItemUtil.unitRepair import org.bukkit.GameMode import org.bukkit.Material +import org.bukkit.entity.Item import org.bukkit.entity.Player import org.bukkit.event.Event import org.bukkit.event.EventHandler @@ -25,6 +26,7 @@ import org.bukkit.inventory.ItemStack import org.bukkit.inventory.meta.Repairable import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.group.ConflictType +import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair import kotlin.math.min @@ -58,6 +60,25 @@ class AnvilEventListener : Listener { val player = event.view.player if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return + // Test custom recipe + val recipe = getCustomRecipe(first, second) + if(recipe != null){ + val amount = getCustomRecipeAmount(recipe, first, second) + + val resultItem: ItemStack + if(amount <= 1){ + resultItem = recipe.resultItem!! + }else{ + resultItem = recipe.resultItem!!.clone() + resultItem.amount *= amount + } + + event.result = resultItem + handleAnvilXp(inventory, event, recipe.xpCostPerCraft * amount, true) + + return + } + // Test rename lonely item if (second == null) { val resultItem = first.clone() @@ -139,6 +160,7 @@ class AnvilEventListener : Listener { CustomAnvil.log("no anvil fuse type found") event.result = null } + } private fun handleRename(resultItem: ItemStack, inventory: AnvilInventory): Int { @@ -168,6 +190,13 @@ class AnvilEventListener : Listener { val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT) + // Test custom craft + val recipe = getCustomRecipe(leftItem, rightItem) + if(recipe != null){ + event.result = Event.Result.ALLOW + return + } + val canMerge = leftItem.canMergeWith(rightItem) val unitRepairResult = leftItem.getRepair(rightItem) val allowed = (rightItem == null) @@ -370,16 +399,50 @@ class AnvilEventListener : Listener { return rightValue + illegalPenalty } + private fun getCustomRecipe ( + leftItem: ItemStack, + rightItem: ItemStack?) : AnvilCustomRecipe? { + + val recipeList = ConfigHolder.CUSTOM_RECIPE_HOLDER.recipeManager.recipeByMat[leftItem.type] ?: return null + + for (recipe in recipeList) { + if(recipe.testItem(leftItem, rightItem)){ + return recipe + } + } + + return null + } + + private fun getCustomRecipeAmount( + recipe: AnvilCustomRecipe, + leftItem: ItemStack, + rightItem: ItemStack? + ): Int{ + return if(recipe.exactCount) { 1 } + else { + // test amount + val resultItem = recipe.resultItem!! // we know exist as the recipe was returned to us + val maxResultAmount = resultItem.type.maxStackSize/resultItem.amount + val maxLeftAmount = leftItem.amount/recipe.leftItem!!.amount + val maxRightAmount = if(rightItem == null){ 1 } else{ rightItem.amount/recipe.rightItem!!.amount } + + min(min(maxResultAmount, maxLeftAmount), maxRightAmount) + } + } + + /** * Display xp needed for the work on the anvil inventory */ private fun handleAnvilXp( inventory: AnvilInventory, event: PrepareAnvilEvent, - anvilCost: Int + anvilCost: Int, + ignoreRules: Boolean = false ) { // Test repair cost limit - val finalAnvilCost = if (ConfigOptions.limitRepairCost) { + val finalAnvilCost = if (ConfigOptions.limitRepairCost && !ignoreRules) { min(anvilCost, ConfigOptions.limitRepairValue) } else { anvilCost @@ -392,8 +455,10 @@ class AnvilEventListener : Listener { .server .scheduler .runTask(CustomAnvil.instance, Runnable { - if (ConfigOptions.removeRepairLimit) { + if (ConfigOptions.removeRepairLimit || ignoreRules) { inventory.maximumRepairCost = Int.MAX_VALUE + } else{ + inventory.maximumRepairCost = 40 // minecraft default } inventory.repairCost = finalAnvilCost diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt index 584271e..697c3d0 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt @@ -8,8 +8,8 @@ import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant class AnvilCustomRecipe( val name: String, var exactCount: Boolean, - var exactLeft: Boolean, - var exactRight: Boolean, + //var exactLeft: Boolean, + //var exactRight: Boolean, var xpCostPerCraft: Int, @@ -21,8 +21,8 @@ class AnvilCustomRecipe( // Static config name companion object { const val EXACT_COUNT_CONFIG = "exact_count" - const val EXACT_LEFT_CONFIG = "exact_left" - const val EXACT_RIGHT_CONFIG = "exact_right" + //const val EXACT_LEFT_CONFIG = "exact_left" + //const val EXACT_RIGHT_CONFIG = "exact_right" const val XP_COST_CONFIG = "xp_cost" @@ -30,19 +30,32 @@ class AnvilCustomRecipe( const val RIGHT_ITEM_CONFIG = "right_item" const val RESULT_ITEM_CONFIG = "result_item" + + val DEFAULT_EXACT_COUNT_CONFIG = true + //val DEFAULT_EXACT_LEFT_CONFIG = true + //val DEFAULT_EXACT_RIGHT_CONFIG = true + + val DEFAULT_XP_COST_CONFIG = 1 + + val DEFAULT_LEFT_ITEM_CONFIG = null + val DEFAULT_RIGHT_ITEM_CONFIG = null + val DEFAULT_RESULT_ITEM_CONFIG = null + + val XP_COST_CONFIG_RANGE = 0..255 + fun getFromConfig(name: String, configSection: ConfigurationSection?): AnvilCustomRecipe? { if(configSection == null) return null; return AnvilCustomRecipe( name, - configSection.getBoolean(EXACT_COUNT_CONFIG, true), - configSection.getBoolean(EXACT_LEFT_CONFIG, true), - configSection.getBoolean(EXACT_RIGHT_CONFIG, true), + configSection.getBoolean(EXACT_COUNT_CONFIG, DEFAULT_EXACT_COUNT_CONFIG), + //configSection.getBoolean(EXACT_LEFT_CONFIG, true), + //configSection.getBoolean(EXACT_RIGHT_CONFIG, true), - configSection.getInt(XP_COST_CONFIG, 10), + configSection.getInt(XP_COST_CONFIG, DEFAULT_XP_COST_CONFIG), - configSection.getItemStack(LEFT_ITEM_CONFIG, null), - configSection.getItemStack(RIGHT_ITEM_CONFIG, null), - configSection.getItemStack(RESULT_ITEM_CONFIG, null), + configSection.getItemStack(LEFT_ITEM_CONFIG, DEFAULT_LEFT_ITEM_CONFIG), + configSection.getItemStack(RIGHT_ITEM_CONFIG, DEFAULT_RIGHT_ITEM_CONFIG), + configSection.getItemStack(RESULT_ITEM_CONFIG, DEFAULT_RESULT_ITEM_CONFIG), ) } @@ -64,8 +77,8 @@ class AnvilCustomRecipe( val fileConfig = ConfigHolder.CUSTOM_RECIPE_HOLDER.config fileConfig.set("$name.$EXACT_COUNT_CONFIG", exactCount) - fileConfig.set("$name.$EXACT_LEFT_CONFIG", exactLeft) - fileConfig.set("$name.$EXACT_RIGHT_CONFIG", exactRight) + //fileConfig.set("$name.$EXACT_LEFT_CONFIG", exactLeft) + //fileConfig.set("$name.$EXACT_RIGHT_CONFIG", exactRight) fileConfig.set("$name.$XP_COST_CONFIG", xpCostPerCraft) @@ -79,6 +92,28 @@ class AnvilCustomRecipe( } } + fun testItem(item1: ItemStack, item2: ItemStack?): Boolean { + // We assume this function can be call only if leftItem != null + + // Test is valid + if(!validate()) return false + + // test of left item + if(!leftItem!!.isSimilar(item1)) return false // Test similar + if(exactCount){ + if((leftItem!!.amount != item1.amount)) return false // test exact amount + }else if(item1.amount < leftItem!!.amount) return false // test if it has at least the amount we ask + + // we don't know if right item can be + if(rightItem == null){ // null test + if(item2 != null) return false + }else if(!rightItem!!.isSimilar(item2)) return false // test if similar when not null + else if(exactCount) { + if (rightItem!!.amount != item2!!.amount) return false // test exact amount + }else if(item2!!.amount < rightItem!!.amount) return false // test if it has at least the amount we ask + + return true + } } From 9a2b005cfbb56a371a86635c2a06c1e504345a54 Mon Sep 17 00:00:00 2001 From: alexcrea Date: Fri, 5 Apr 2024 19:30:49 +0200 Subject: [PATCH 04/12] Add item setting gui --- .../gui/config/settings/ItemSettingGui.java | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java new file mode 100644 index 0000000..a215611 --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java @@ -0,0 +1,221 @@ +package xyz.alexcrea.cuanvil.gui.config.settings; + +import com.github.stefvanschie.inventoryframework.gui.GuiItem; +import com.github.stefvanschie.inventoryframework.pane.PatternPane; +import com.github.stefvanschie.inventoryframework.pane.util.Pattern; +import io.delilaheve.CustomAnvil; +import org.bukkit.Material; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import xyz.alexcrea.cuanvil.config.ConfigHolder; +import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; +import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; +import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant; +import xyz.alexcrea.cuanvil.util.MetricsUtil; + +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +/** + * An instance of a gui used to edit an item setting. + */ +public class ItemSettingGui extends AbstractSettingGui { + + private final ItemSettingFactory holder; + private final ItemStack before; + private ItemStack now; + + /** + * Create an item setting config gui. + * + * @param holder Configuration factory of this setting. + * @param now The defined value of this setting. + */ + protected ItemSettingGui(ItemSettingFactory holder, ItemStack now) { + super(3, holder.getTitle(), holder.parent); + this.holder = holder; + this.before = now; + this.now = now; + + prepareReturnToDefault(); + updateValueDisplay(); + } + + + @Override + public Pattern getGuiPattern() { + return new Pattern( + GuiSharedConstant.EMPTY_GUI_FULL_LINE, + "D0-0v0+00", + "B0000000S" + ); + } + + protected GuiItem returnToDefault; + + /** + * Prepare "return to default value" gui item. + */ + protected void prepareReturnToDefault() { + ItemStack item = new ItemStack(Material.COMMAND_BLOCK); + ItemMeta meta = item.getItemMeta(); + + meta.setDisplayName("\u00A7eReset to default value"); + meta.setLore(Collections.singletonList("\u00A77Default value is: " + holder.defaultVal)); + item.setItemMeta(meta); + returnToDefault = new GuiItem(item, event -> { + event.setCancelled(true); + now = holder.defaultVal; + updateValueDisplay(); + update(); + }, CustomAnvil.instance); + } + + protected final static List CLICK_LORE = Collections.singletonList("\u00A77Click Here with an item to change the value"); + + /** + * Update item using the setting value to match the new value + */ + protected void updateValueDisplay() { + PatternPane pane = getPane(); + + // Get displayed value for this config. + ItemStack displayedItem; + if(this.now != null){ + displayedItem = this.now; + }else{ + displayedItem = new ItemStack(Material.BARRIER); + ItemMeta valueMeta = displayedItem.getItemMeta(); + + valueMeta.setDisplayName("§4NO ITEM SET"); + valueMeta.setLore(CLICK_LORE); + + displayedItem.setItemMeta(valueMeta); + } + + GuiItem resultItem = new GuiItem(displayedItem, setItemAsCursor(), CustomAnvil.instance); + pane.bindItem('v', resultItem); + + // reset to default + GuiItem returnToDefault; + if (now != holder.defaultVal) { + returnToDefault = this.returnToDefault; + } else { + returnToDefault = GuiGlobalItems.backgroundItem(); + } + pane.bindItem('D', returnToDefault); + + } + + /** + * @return A consumer to update the current setting's value. + */ + protected Consumer setItemAsCursor() { //TODO redo consumer + return event -> { + event.setCancelled(true); + + HumanEntity player = event.getWhoClicked(); + ItemStack cursor = player.getItemOnCursor(); + + if(cursor.getType().isAir()) return; + + now = cursor; + + updateValueDisplay(); + update(); + }; + } + + @Override + public boolean onSave() { + holder.config.getConfig().set(holder.configPath, now); + + MetricsUtil.INSTANCE.notifyChange(this.holder.config, this.holder.configPath); + if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) { + return holder.config.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE); + } + return true; + } + + @Override + public boolean hadChange() { + return now != before; + } + + /** + * Create aa item setting factory from setting's parameters. + * + * @param title The title of the gui. + * @param parent Parent gui to go back when completed. + * @param configPath Configuration path of this setting. + * @param config Configuration holder of this setting. + * @param defaultVal Default value if not found on the config. + * @return A factory for an item setting gui. + */ + public static ItemSettingGui.ItemSettingFactory itemFactory(@NotNull String title, ValueUpdatableGui parent, + String configPath, ConfigHolder config, + ItemStack defaultVal) { + return new ItemSettingGui.ItemSettingFactory( + title, parent, + configPath, config, + defaultVal); + } + + /** + * A factory for an item setting gui that hold setting's information. + */ + public static class ItemSettingFactory extends SettingGuiFactory { + @NotNull + String title; + ValueUpdatableGui parent; + ItemStack defaultVal; + + /** + * Constructor for an item setting gui factory. + * + * @param title The title of the gui. + * @param parent Parent gui to go back when completed. + * @param configPath Configuration path of this setting. + * @param config Configuration holder of this setting. + * @param defaultVal Default value if not found on the config. + */ + protected ItemSettingFactory( + @NotNull String title, ValueUpdatableGui parent, + String configPath, ConfigHolder config, + ItemStack defaultVal) { + super(configPath, config); + this.title = title; + this.parent = parent; + + this.defaultVal = defaultVal; + } + + /** + * @return Get setting's gui title. + */ + @NotNull + public String getTitle() { + return title; + } + + /** + * @return The configured value for the associated setting. + */ + public ItemStack getConfiguredValue() { + return this.config.getConfig().getItemStack(this.configPath, this.defaultVal); + } + + @Override + public AbstractSettingGui create() { + // Get current value or default + ItemStack now = getConfiguredValue(); + // create new gui + return new ItemSettingGui(this, now); + } + + } +} From 8c936658a17b216f8c02ecdb4d6bd2c3ef29ed6c Mon Sep 17 00:00:00 2001 From: alexcrea Date: Fri, 5 Apr 2024 20:23:51 +0200 Subject: [PATCH 05/12] Add item to temporary close the item config gui. --- .../gui/config/settings/ItemSettingGui.java | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java index a215611..95c4f43 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java @@ -41,20 +41,49 @@ protected ItemSettingGui(ItemSettingFactory holder, ItemStack now) { this.before = now; this.now = now; - prepareReturnToDefault(); + prepareStaticItems(); updateValueDisplay(); } - @Override public Pattern getGuiPattern() { return new Pattern( GuiSharedConstant.EMPTY_GUI_FULL_LINE, - "D0-0v0+00", + "D0-0v0+0s", "B0000000S" ); } + + public void prepareStaticItems(){ + prepareReturnToDefault(); + + ItemStack item = new ItemStack(Material.YELLOW_TERRACOTTA); + ItemMeta meta = item.getItemMeta(); + + meta.setDisplayName("\u00A7eTemporary close this menu"); + meta.setLore(Collections.singletonList("\u00A77Allow you to chose other item then return here.")); + item.setItemMeta(meta); + GuiItem guiItem = new GuiItem(item, event -> { + event.setCancelled(true); + + HumanEntity player = event.getWhoClicked(); + + CustomAnvil.Companion.getChatListener().setListenedCallback(player, (message) ->{ + + if(message != null) return; + show(player); + + }); + + player.sendMessage("\u00A7eWrite something in chat to return to the item config menu."); + player.closeInventory(); + }, CustomAnvil.instance); + + getPane().bindItem('s', guiItem); + } + + protected GuiItem returnToDefault; /** @@ -91,7 +120,7 @@ protected void updateValueDisplay() { displayedItem = new ItemStack(Material.BARRIER); ItemMeta valueMeta = displayedItem.getItemMeta(); - valueMeta.setDisplayName("§4NO ITEM SET"); + valueMeta.setDisplayName("\u00A74NO ITEM SET"); valueMeta.setLore(CLICK_LORE); displayedItem.setItemMeta(valueMeta); From 0004f2426f3f40f8106792c6750ed8d3d0f29d72 Mon Sep 17 00:00:00 2001 From: alexcrea Date: Fri, 5 Apr 2024 21:27:36 +0200 Subject: [PATCH 06/12] Add an abstract layer for global config gui list. --- .../AbstractEnchantConfigGui.java | 2 +- .../global/ElementListGlobalConfigGui.java | 292 ++++++++++++++++++ .../gui/config/global/EnchantConflictGui.java | 267 ++-------------- .../config/global/EnchantCostConfigGui.java | 1 - .../config/global/EnchantLimitConfigGui.java | 1 - .../EnchantConflictSubSettingGui.java | 2 +- 6 files changed, 320 insertions(+), 245 deletions(-) rename src/main/java/xyz/alexcrea/cuanvil/gui/config/{ => global}/AbstractEnchantConfigGui.java (98%) create mode 100644 src/main/java/xyz/alexcrea/cuanvil/gui/config/global/ElementListGlobalConfigGui.java diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/AbstractEnchantConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/AbstractEnchantConfigGui.java similarity index 98% rename from src/main/java/xyz/alexcrea/cuanvil/gui/config/AbstractEnchantConfigGui.java rename to src/main/java/xyz/alexcrea/cuanvil/gui/config/global/AbstractEnchantConfigGui.java index da8e34d..7c6d31e 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/AbstractEnchantConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/AbstractEnchantConfigGui.java @@ -1,4 +1,4 @@ -package xyz.alexcrea.cuanvil.gui.config; +package xyz.alexcrea.cuanvil.gui.config.global; import com.github.stefvanschie.inventoryframework.gui.GuiItem; import com.github.stefvanschie.inventoryframework.pane.Orientable; diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/ElementListGlobalConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/ElementListGlobalConfigGui.java new file mode 100644 index 0000000..2f8a6c6 --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/ElementListGlobalConfigGui.java @@ -0,0 +1,292 @@ +package xyz.alexcrea.cuanvil.gui.config.global; + +import com.github.stefvanschie.inventoryframework.gui.GuiItem; +import com.github.stefvanschie.inventoryframework.pane.Orientable; +import com.github.stefvanschie.inventoryframework.pane.OutlinePane; +import com.github.stefvanschie.inventoryframework.pane.Pane; +import com.github.stefvanschie.inventoryframework.pane.PatternPane; +import com.github.stefvanschie.inventoryframework.pane.util.Pattern; +import io.delilaheve.CustomAnvil; +import org.bukkit.Material; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; +import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; +import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +public abstract class ElementListGlobalConfigGui< T > extends ValueUpdatableGui { + + + public ElementListGlobalConfigGui(int rows, @NotNull String title) { + super(rows, title, CustomAnvil.instance); + } + + + protected OutlinePane firstPage; + protected ArrayList pages; + protected HashMap pageMap; + protected PatternPane backgroundPane; + + public void init() { + // Back item panel + Pattern pattern = new Pattern( + GuiSharedConstant.EMPTY_GUI_FULL_LINE, + GuiSharedConstant.EMPTY_GUI_FULL_LINE, + GuiSharedConstant.EMPTY_GUI_FULL_LINE, + GuiSharedConstant.EMPTY_GUI_FULL_LINE, + GuiSharedConstant.EMPTY_GUI_FULL_LINE, + "B11L1R11C" + ); + this.backgroundPane = new PatternPane(0, 0, 9, 6, Pane.Priority.LOW, pattern); + + GuiGlobalItems.addBackItem(this.backgroundPane, MainConfigGui.INSTANCE); + + GuiGlobalItems.addBackgroundItem(this.backgroundPane); + this.backgroundPane.bindItem('1', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM); + addPane(this.backgroundPane); + + // Page init + this.pages = new ArrayList<>(); + this.pageMap = new HashMap<>(); + + // enchant item panel + this.firstPage = createEmptyPage(); + this.pages.add(this.firstPage); + + prepareStaticValues(); + reloadValues(); + } + + protected GuiItem goLeftItem; + protected GuiItem goRightItem; + + protected void prepareStaticValues(){ + // Left item creation for consumer & bind + this.goLeftItem = new GuiItem(new ItemStack(Material.RED_TERRACOTTA), event -> { + HumanEntity viewer = event.getWhoClicked(); + UUID playerUUID = viewer.getUniqueId(); + int page = this.pageMap.getOrDefault(playerUUID, 0); + this.pageMap.put(playerUUID, page - 1); + + ItemStack cursor = viewer.getItemOnCursor(); + viewer.setItemOnCursor(new ItemStack(Material.AIR)); + + show(viewer); + + viewer.setItemOnCursor(cursor); + }, CustomAnvil.instance); + + // Right item creation for consumer & bind + this.goRightItem = new GuiItem(new ItemStack(Material.GREEN_TERRACOTTA), event -> { + HumanEntity viewer = event.getWhoClicked(); + UUID playerUUID = viewer.getUniqueId(); + int page = pageMap.getOrDefault(playerUUID, 0); + this.pageMap.put(playerUUID, page + 1); + + ItemStack cursor = viewer.getItemOnCursor(); + viewer.setItemOnCursor(new ItemStack(Material.AIR)); + + show(viewer); + + viewer.setItemOnCursor(cursor); + }, CustomAnvil.instance); + + this.backgroundPane.bindItem('C', prepareCreateNewItem()); + } + protected void reloadValues(){ + this.firstPage.clear(); + this.pages.clear(); + this.pages.add(this.firstPage); + + for (T conflict : getEveryDisplayableInstanceOfGeneric()) { + updateValueForGeneric(conflict, false); + } + + update(); + } + + protected abstract GuiItem prepareCreateNewItem(); + + protected OutlinePane createEmptyPage() { + OutlinePane page = new OutlinePane(0, 0, 9, 5); + page.align(OutlinePane.Alignment.BEGIN); + page.setOrientation(Orientable.Orientation.HORIZONTAL); + + return page; + } + + public int getPlayerPageID(UUID uuid) { + int pageId = this.pageMap.getOrDefault(uuid, 0); + if (pageId >= this.pages.size()) { + pageId = this.pages.size() - 1; + } + return pageId; + } + + protected void addToPage(GuiItem guiItem) { + // Get first available page or create one + OutlinePane page = this.pages.get(this.pages.size() - 1); + if (page.getItems().size() >= 5 * 9) { + page = createEmptyPage(); + this.pages.add(page); + } + + page.addItem(guiItem); + } + + private void removeFromPage(GuiItem guiItem) { + // get item page + OutlinePane page = null; + int pageID = 0; + while (pageID < this.pages.size()) { + OutlinePane tempPage = this.pages.get(pageID); + if (tempPage.getItems().contains(guiItem)) { + page = tempPage; + break; + } + pageID++; + } + + if (page == null) {// Why... + return; + } + removeFromPage(page, pageID, guiItem); + } + + private void removeFromPage(OutlinePane page, int pageID, GuiItem guiItem) { + page.removeItem(guiItem); + + // There is now a slot available, let fill it if possible + if (pageID < (this.pages.size() - 1)) { + OutlinePane newPage = this.pages.get(pageID + 1); + GuiItem nextPageItem = newPage.getItems().get(0); + + removeFromPage(newPage, pageID + 1, nextPageItem); + + OutlinePane thisPage = this.pages.get(pageID); + thisPage.addItem(nextPageItem); + } else if (pageID > 0 && page.getItems().isEmpty()) { + this.pages.remove(pageID); + } + } + + public void placeArrow(int page, boolean customise) { + + // Place left arrow + addPane(this.backgroundPane); + if (page > 0) { + if (customise) { + ItemStack leftItem = this.goLeftItem.getItem(); + ItemMeta leftMeta = leftItem.getItemMeta(); + + leftMeta.setDisplayName("\u00A7eReturn to page " + (page)); + + leftItem.setItemMeta(leftMeta); + this.goLeftItem.setItem(leftItem); + } + + this.backgroundPane.bindItem('L', this.goLeftItem); + } else { + this.backgroundPane.bindItem('L', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM); + } + + // Place right arrow + if (page < pages.size() - 1) { + if (customise) { + ItemStack rightItem = this.goRightItem.getItem(); + ItemMeta rightMeta = rightItem.getItemMeta(); + + rightMeta.setDisplayName("\u00A7eGo to page " + (page + 2)); + + rightItem.setItemMeta(rightMeta); + this.goRightItem.setItem(rightItem); + } + + this.backgroundPane.bindItem('R', this.goRightItem); + } else { + this.backgroundPane.bindItem('R', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM); + } + } + + @Override // assume will not be called in multiple thread + public void show(@NotNull HumanEntity humanEntity) { + int pageID = getPlayerPageID(humanEntity.getUniqueId()); + OutlinePane page = this.pages.get(pageID); + + getPanes().clear(); + + // display the page arrow pane + placeArrow(pageID, true); + // and add actual page + addPane(page); + + // set title + setTitle("Conflict Config (" + (pageID + 1) + "/" + (pages.size()) + ")"); + + super.show(humanEntity); + + } + + @Override // assume will not be called in multiple thread + public void click(@NotNull InventoryClickEvent event) { + int pageID = getPlayerPageID(event.getWhoClicked().getUniqueId()); + OutlinePane page = this.pages.get(pageID); + + getPanes().clear(); + + // set the page arrow pane + placeArrow(pageID, false); + // and add actual page + addPane(page); + + super.click(event); + } + + // ------------------------- + // Methods using generic T + // ------------------------- + + public void updateValueForGeneric(T generic, boolean shouldUpdate) { + ItemStack item = createItemForGeneric(generic); + + updateGeneric(generic, item); + + if (shouldUpdate) { + update(); + } + + } + + public void removeConflict(T generic) { + GuiItem item = findGuiItemForRemoval(generic); + if(item == null) return; + removeFromPage(item); + + update(); + } + + protected abstract GuiItem findGuiItemForRemoval(T generic); + + protected abstract ItemStack createItemForGeneric(T generic); + + protected abstract void updateGeneric(T generic, ItemStack usedItem); + + protected abstract List getEveryDisplayableInstanceOfGeneric(); + + @Override + public void updateGuiValues() { + // Not the optimised way to update this gui + // TODO maybe rework ValueUpdatableGui and it's dependency to allow a 1 item reload every time. + + reloadValues(); + } + +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java index 49f4302..e713e36 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java @@ -1,34 +1,28 @@ package xyz.alexcrea.cuanvil.gui.config.global; import com.github.stefvanschie.inventoryframework.gui.GuiItem; -import com.github.stefvanschie.inventoryframework.gui.type.ChestGui; -import com.github.stefvanschie.inventoryframework.pane.Orientable; -import com.github.stefvanschie.inventoryframework.pane.OutlinePane; -import com.github.stefvanschie.inventoryframework.pane.Pane; -import com.github.stefvanschie.inventoryframework.pane.PatternPane; -import com.github.stefvanschie.inventoryframework.pane.util.Pattern; import io.delilaheve.CustomAnvil; import org.bukkit.Material; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.HumanEntity; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; -import org.jetbrains.annotations.NotNull; import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.group.EnchantConflictGroup; import xyz.alexcrea.cuanvil.group.IncludeGroup; import xyz.alexcrea.cuanvil.gui.config.settings.subsetting.EnchantConflictSubSettingGui; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions; -import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant; import xyz.alexcrea.cuanvil.util.CasedStringUtil; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; -public class EnchantConflictGui extends ChestGui { +public class EnchantConflictGui extends ElementListGlobalConfigGui { public final static EnchantConflictGui INSTANCE = new EnchantConflictGui(); @@ -39,80 +33,12 @@ public class EnchantConflictGui extends ChestGui { private final HashMap conflictGuiMap; private EnchantConflictGui() { - super(6, "Conflict Config", CustomAnvil.instance); + super(6, "Conflict Config"); this.conflictGuiMap = new HashMap<>(); } - private OutlinePane firstPage; - private ArrayList pages; - private HashMap pageMap; - private PatternPane backgroundPane; - - private void init() { - // Back item panel - Pattern pattern = new Pattern( - GuiSharedConstant.EMPTY_GUI_FULL_LINE, - GuiSharedConstant.EMPTY_GUI_FULL_LINE, - GuiSharedConstant.EMPTY_GUI_FULL_LINE, - GuiSharedConstant.EMPTY_GUI_FULL_LINE, - GuiSharedConstant.EMPTY_GUI_FULL_LINE, - "B11L1R11C" - ); - this.backgroundPane = new PatternPane(0, 0, 9, 6, Pane.Priority.LOW, pattern); - - GuiGlobalItems.addBackItem(this.backgroundPane, MainConfigGui.INSTANCE); - - GuiGlobalItems.addBackgroundItem(this.backgroundPane); - this.backgroundPane.bindItem('1', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM); - addPane(this.backgroundPane); - - // Page init - this.pages = new ArrayList<>(); - this.pageMap = new HashMap<>(); - - // enchant item panel - this.firstPage = createEmptyPage(); - this.pages.add(this.firstPage); - - prepareOtherValues(); - reloadValues(); - } - - - private GuiItem goLeftItem; - private GuiItem goRightItem; - - private void prepareOtherValues() { - // Left item creation for consumer & bind - this.goLeftItem = new GuiItem(new ItemStack(Material.RED_TERRACOTTA), event -> { - HumanEntity viewer = event.getWhoClicked(); - UUID playerUUID = viewer.getUniqueId(); - int page = this.pageMap.getOrDefault(playerUUID, 0); - this.pageMap.put(playerUUID, page - 1); - - ItemStack cursor = viewer.getItemOnCursor(); - viewer.setItemOnCursor(new ItemStack(Material.AIR)); - - show(viewer); - - viewer.setItemOnCursor(cursor); - }, CustomAnvil.instance); - - // Right item creation for consumer & bind - this.goRightItem = new GuiItem(new ItemStack(Material.GREEN_TERRACOTTA), event -> { - HumanEntity viewer = event.getWhoClicked(); - UUID playerUUID = viewer.getUniqueId(); - int page = pageMap.getOrDefault(playerUUID, 0); - this.pageMap.put(playerUUID, page + 1); - - ItemStack cursor = viewer.getItemOnCursor(); - viewer.setItemOnCursor(new ItemStack(Material.AIR)); - - show(viewer); - - viewer.setItemOnCursor(cursor); - }, CustomAnvil.instance); - + @Override + protected GuiItem prepareCreateNewItem(){ // Create new conflict item ItemStack createItem = new ItemStack(Material.PAPER); ItemMeta createMeta = createItem.getItemMeta(); @@ -126,7 +52,7 @@ private void prepareOtherValues() { createItem.setItemMeta(createMeta); - this.backgroundPane.bindItem('C', new GuiItem(createItem, (clickEvent) -> { + return new GuiItem(createItem, (clickEvent) -> { clickEvent.setCancelled(true); HumanEntity player = clickEvent.getWhoClicked(); @@ -143,7 +69,7 @@ private void prepareOtherValues() { CustomAnvil.Companion.getChatListener().setListenedCallback(player, prepareCreateItemConsumer(player)); - }, CustomAnvil.instance)); + }, CustomAnvil.instance); } private Consumer prepareCreateItemConsumer(HumanEntity player) { @@ -184,7 +110,7 @@ private Consumer prepareCreateItemConsumer(HumanEntity player) { 0); ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList().add(conflict); - updateValueForConflict(conflict, true); + updateValueForGeneric(conflict, true); // save empty conflict in config String[] emptyStringArray = new String[0]; @@ -207,29 +133,16 @@ private Consumer prepareCreateItemConsumer(HumanEntity player) { return selfCallback; } - private OutlinePane createEmptyPage() { - OutlinePane page = new OutlinePane(0, 0, 9, 5); - page.align(OutlinePane.Alignment.BEGIN); - page.setOrientation(Orientable.Orientation.HORIZONTAL); - - return page; - } - + @Override public void reloadValues() { this.conflictGuiMap.forEach((conflict, gui) -> gui.cleanUnused()); this.conflictGuiMap.clear(); - this.firstPage.clear(); - this.pages.clear(); - this.pages.add(this.firstPage); - for (EnchantConflictGroup conflict : ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList()) { - updateValueForConflict(conflict, false); - } - - update(); + super.reloadValues(); } - public static ItemStack createItemForConflict(EnchantConflictGroup conflict) { + @Override + public ItemStack createItemForGeneric(EnchantConflictGroup conflict) { ItemStack item = new ItemStack(conflict.getRepresentativeMaterial()); ItemMeta meta = item.getItemMeta(); @@ -245,14 +158,14 @@ public static ItemStack createItemForConflict(EnchantConflictGroup conflict) { return item; } - public void updateValueForConflict(EnchantConflictGroup conflict, boolean shouldUpdate) { + @Override + protected void updateGeneric(EnchantConflictGroup conflict, ItemStack usedItem) { EnchantConflictSubSettingGui gui = this.conflictGuiMap.get(conflict); - ItemStack item = createItemForConflict(conflict); GuiItem guiItem; if (gui == null) { // Create new sub setting gui - guiItem = new GuiItem(item, CustomAnvil.instance); + guiItem = new GuiItem(usedItem, CustomAnvil.instance); gui = new EnchantConflictSubSettingGui(this, conflict, guiItem); guiItem.setAction(GuiGlobalActions.openGuiAction(gui)); @@ -262,152 +175,24 @@ public void updateValueForConflict(EnchantConflictGroup conflict, boolean should } else { // Replace item with the updated one guiItem = gui.getParentItemForThisGui(); - guiItem.setItem(item); + guiItem.setItem(usedItem); } - gui.updateLocal(); - if (shouldUpdate) { - update(); - } } - public void removeConflict(EnchantConflictGroup conflict) { + @Override + protected GuiItem findGuiItemForRemoval(EnchantConflictGroup conflict) { EnchantConflictSubSettingGui gui = this.conflictGuiMap.get(conflict); - if (gui == null) return; + if (gui == null) return null; this.conflictGuiMap.remove(conflict); - removeFromPage(gui.getParentItemForThisGui()); - - update(); - } - - private void addToPage(GuiItem guiItem) { - // Get first available page or create one - OutlinePane page = this.pages.get(this.pages.size() - 1); - if (page.getItems().size() >= 5 * 9) { - page = createEmptyPage(); - this.pages.add(page); - } - - page.addItem(guiItem); + return gui.getParentItemForThisGui(); } - private void removeFromPage(GuiItem guiItem) { - // get item page - OutlinePane page = null; - int pageID = 0; - while (pageID < this.pages.size()) { - OutlinePane tempPage = this.pages.get(pageID); - if (tempPage.getItems().contains(guiItem)) { - page = tempPage; - break; - } - pageID++; - } - - if (page == null) {// Why... - return; - } - removeFromPage(page, pageID, guiItem); - } - - private void removeFromPage(OutlinePane page, int pageID, GuiItem guiItem) { - page.removeItem(guiItem); - - // There is now a slot available, let fill it if possible - if (pageID < (this.pages.size() - 1)) { - OutlinePane newPage = this.pages.get(pageID + 1); - GuiItem nextPageItem = newPage.getItems().get(0); - - removeFromPage(newPage, pageID + 1, nextPageItem); - - OutlinePane thisPage = this.pages.get(pageID); - thisPage.addItem(nextPageItem); - } else if (pageID > 0 && page.getItems().isEmpty()) { - this.pages.remove(pageID); - } - } - - - public int getPlayerPageID(UUID uuid) { - int pageId = this.pageMap.getOrDefault(uuid, 0); - if (pageId >= this.pages.size()) { - pageId = this.pages.size() - 1; - } - return pageId; - } - - public void placeArrow(int page, boolean customise) { - - // Place left arrow - addPane(this.backgroundPane); - if (page > 0) { - if (customise) { - ItemStack leftItem = this.goLeftItem.getItem(); - ItemMeta leftMeta = leftItem.getItemMeta(); - - leftMeta.setDisplayName("\u00A7eReturn to page " + (page)); - - leftItem.setItemMeta(leftMeta); - this.goLeftItem.setItem(leftItem); - } - - this.backgroundPane.bindItem('L', this.goLeftItem); - } else { - this.backgroundPane.bindItem('L', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM); - } - - // Place right arrow - if (page < pages.size() - 1) { - if (customise) { - ItemStack rightItem = this.goRightItem.getItem(); - ItemMeta rightMeta = rightItem.getItemMeta(); - - rightMeta.setDisplayName("\u00A7eGo to page " + (page + 2)); - - rightItem.setItemMeta(rightMeta); - this.goRightItem.setItem(rightItem); - } - - this.backgroundPane.bindItem('R', this.goRightItem); - } else { - this.backgroundPane.bindItem('R', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM); - } - } - - @Override // assume will not be called in multiple thread - public void show(@NotNull HumanEntity humanEntity) { - int pageID = getPlayerPageID(humanEntity.getUniqueId()); - OutlinePane page = this.pages.get(pageID); - - getPanes().clear(); - - // display the page arrow pane - placeArrow(pageID, true); - // and add actual page - addPane(page); - - // set title - setTitle("Conflict Config (" + (pageID + 1) + "/" + (pages.size()) + ")"); - - super.show(humanEntity); - - } - - @Override // assume will not be called in multiple thread - public void click(@NotNull InventoryClickEvent event) { - int pageID = getPlayerPageID(event.getWhoClicked().getUniqueId()); - OutlinePane page = this.pages.get(pageID); - - getPanes().clear(); - - // set the page arrow pane - placeArrow(pageID, false); - // and add actual page - addPane(page); - - super.click(event); + @Override + protected List getEveryDisplayableInstanceOfGeneric() { + return ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList(); } } diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java index 2c2427b..2a1937b 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java @@ -8,7 +8,6 @@ import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.enchant.EnchantmentProperties; import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity; -import xyz.alexcrea.cuanvil.gui.config.AbstractEnchantConfigGui; import xyz.alexcrea.cuanvil.gui.config.settings.EnchantCostSettingsGui; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.util.CasedStringUtil; diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantLimitConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantLimitConfigGui.java index ae89b54..999f2a7 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantLimitConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantLimitConfigGui.java @@ -4,7 +4,6 @@ import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import xyz.alexcrea.cuanvil.config.ConfigHolder; -import xyz.alexcrea.cuanvil.gui.config.AbstractEnchantConfigGui; import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.util.CasedStringUtil; diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java index 6671d12..d6f243f 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java @@ -151,7 +151,7 @@ private ConfirmActionGui createDeleteGui() { @Override public void updateGuiValues() { - this.parent.updateValueForConflict(this.enchantConflict, true); + this.parent.updateValueForGeneric(this.enchantConflict, true); // Parent should call updateLocal } From e440d05bb9208334267348692c28488b87fd7de5 Mon Sep 17 00:00:00 2001 From: alexcrea Date: Sat, 6 Apr 2024 15:21:40 +0200 Subject: [PATCH 07/12] Create global and sub setting recipe config gui. --- .../config/global/CustomRecipeConfigGui.java | 86 +++++++ .../global/ElementListGlobalConfigGui.java | 6 +- .../gui/config/global/EnchantConflictGui.java | 158 ++---------- .../gui/config/global/MainConfigGui.java | 15 +- .../global/MappedElementListConfigGui.java | 156 ++++++++++++ .../subsetting/CustomRecipeSubSettingGui.java | 241 ++++++++++++++++++ .../EnchantConflictSubSettingGui.java | 34 ++- .../subsetting/MappedToListSubSettingGui.java | 28 ++ .../cuanvil/group/EnchantConflictGroup.kt | 9 +- .../cuanvil/group/EnchantConflictManager.kt | 4 +- .../xyz/alexcrea/cuanvil/interfaces/Named.kt | 7 + .../cuanvil/recipe/AnvilCustomRecipe.kt | 15 +- .../recipe/CustomAnvilRecipeManager.kt | 34 ++- 13 files changed, 613 insertions(+), 180 deletions(-) create mode 100644 src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java create mode 100644 src/main/java/xyz/alexcrea/cuanvil/gui/config/global/MappedElementListConfigGui.java create mode 100644 src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java create mode 100644 src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/MappedToListSubSettingGui.java create mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/interfaces/Named.kt diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java new file mode 100644 index 0000000..ed00af6 --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java @@ -0,0 +1,86 @@ +package xyz.alexcrea.cuanvil.gui.config.global; + +import com.github.stefvanschie.inventoryframework.gui.GuiItem; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import xyz.alexcrea.cuanvil.config.ConfigHolder; +import xyz.alexcrea.cuanvil.gui.config.settings.subsetting.CustomRecipeSubSettingGui; +import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe; +import xyz.alexcrea.cuanvil.util.CasedStringUtil; + +import java.util.Arrays; +import java.util.List; + +public class CustomRecipeConfigGui extends MappedElementListConfigGui { + + + public final static CustomRecipeConfigGui INSTANCE = new CustomRecipeConfigGui(); + + static { + INSTANCE.init(); + } + + private CustomRecipeConfigGui() { + super("title"); + + } + + @Override + protected ItemStack createItemForGeneric(AnvilCustomRecipe recipe) { + // Get base item to display + ItemStack craftResultItem = recipe.getResultItem(); + ItemStack displaydItem; + if(craftResultItem == null){ + displaydItem = new ItemStack(Material.BARRIER); + }else{ + displaydItem = craftResultItem.clone(); + } + + // edit displayed item + ItemMeta meta = displaydItem.getItemMeta(); + + meta.setDisplayName("\u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(recipe.getName()) + " \u00A7fCustom recipe"); + meta.setLore(Arrays.asList( + "TODO" + )); + + displaydItem.setItemMeta(meta); + return displaydItem; + } + + @Override + protected CustomRecipeSubSettingGui newInstanceOfGui(AnvilCustomRecipe generic, GuiItem item) { + return new CustomRecipeSubSettingGui(this, generic, item); + } + + @Override + protected String genericDisplayedName() { + return "custom recipe"; + } + + @Override + protected AnvilCustomRecipe createAndSaveNewEmptyGeneric(String name) { + // Create new empty conflict and display it to the admin + AnvilCustomRecipe recipe = new AnvilCustomRecipe( + name, + AnvilCustomRecipe.Companion.getDEFAULT_EXACT_COUNT_CONFIG(), + AnvilCustomRecipe.Companion.getDEFAULT_XP_COST_CONFIG(), + AnvilCustomRecipe.Companion.getDEFAULT_LEFT_ITEM_CONFIG(), + AnvilCustomRecipe.Companion.getDEFAULT_RIGHT_ITEM_CONFIG(), + AnvilCustomRecipe.Companion.getDEFAULT_RESULT_ITEM_CONFIG()); + + ConfigHolder.CUSTOM_RECIPE_HOLDER.getRecipeManager().cleanAddNew(recipe); + + // Save recipe to file + recipe.saveToFile(); + + return recipe; + } + + + @Override + protected List getEveryDisplayableInstanceOfGeneric() { + return ConfigHolder.CUSTOM_RECIPE_HOLDER.getRecipeManager().getRecipeList(); + } +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/ElementListGlobalConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/ElementListGlobalConfigGui.java index 2f8a6c6..1655c30 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/ElementListGlobalConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/ElementListGlobalConfigGui.java @@ -25,8 +25,8 @@ public abstract class ElementListGlobalConfigGui< T > extends ValueUpdatableGui { - public ElementListGlobalConfigGui(int rows, @NotNull String title) { - super(rows, title, CustomAnvil.instance); + public ElementListGlobalConfigGui(@NotNull String title) { + super(6, title, CustomAnvil.instance); } @@ -265,7 +265,7 @@ public void updateValueForGeneric(T generic, boolean shouldUpdate) { } - public void removeConflict(T generic) { + public void removeGeneric(T generic) { GuiItem item = findGuiItemForRemoval(generic); if(item == null) return; removeFromPage(item); diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java index e713e36..0b9e22f 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java @@ -1,28 +1,20 @@ package xyz.alexcrea.cuanvil.gui.config.global; import com.github.stefvanschie.inventoryframework.gui.GuiItem; -import io.delilaheve.CustomAnvil; -import org.bukkit.Material; import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.entity.HumanEntity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.group.EnchantConflictGroup; import xyz.alexcrea.cuanvil.group.IncludeGroup; import xyz.alexcrea.cuanvil.gui.config.settings.subsetting.EnchantConflictSubSettingGui; -import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions; import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant; import xyz.alexcrea.cuanvil.util.CasedStringUtil; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Locale; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; -public class EnchantConflictGui extends ElementListGlobalConfigGui { +public class EnchantConflictGui extends MappedElementListConfigGui { public final static EnchantConflictGui INSTANCE = new EnchantConflictGui(); @@ -30,115 +22,33 @@ public class EnchantConflictGui extends ElementListGlobalConfigGui conflictGuiMap; - private EnchantConflictGui() { - super(6, "Conflict Config"); - this.conflictGuiMap = new HashMap<>(); + super( "Conflict Config"); } @Override - protected GuiItem prepareCreateNewItem(){ - // Create new conflict item - ItemStack createItem = new ItemStack(Material.PAPER); - ItemMeta createMeta = createItem.getItemMeta(); - - createMeta.setDisplayName("\u00A7aCreate new conflict"); - createMeta.setLore(Arrays.asList( - "\u00A77Create a new anvil restriction.", - "\u00A77You will be asked to name the conflict in chat.", - "\u00A77Then, you should edit the conflict config as you need" - )); - - createItem.setItemMeta(createMeta); - - return new GuiItem(createItem, (clickEvent) -> { - clickEvent.setCancelled(true); - HumanEntity player = clickEvent.getWhoClicked(); + protected EnchantConflictGroup createAndSaveNewEmptyGeneric(String name){ + // Create new empty conflict and display it to the admin + EnchantConflictGroup conflict = new EnchantConflictGroup( + name, + new IncludeGroup("new_group"), + 0); - // check permission - if (!player.hasPermission(CustomAnvil.editConfigPermission)) { - player.closeInventory(); - player.sendMessage(GuiGlobalActions.NO_EDIT_PERM); - return; - } - player.closeInventory(); + ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList().add(conflict); - player.sendMessage("\u00A7eWrite the conflict you want to create in the chat.\n" + - "\u00A7eOr write \u00A7ccancel \u00A7eto go back to conflict config menu"); + // save empty conflict in config + String[] emptyStringArray = new String[0]; - CustomAnvil.Companion.getChatListener().setListenedCallback(player, prepareCreateItemConsumer(player)); + FileConfiguration config = ConfigHolder.CONFLICT_HOLDER.getConfig(); + config.set(name + ".enchantments", emptyStringArray); + config.set(name + ".notAffectedGroups", emptyStringArray); + config.set(name + ".maxEnchantmentBeforeConflict", 0); - }, CustomAnvil.instance); - } - - private Consumer prepareCreateItemConsumer(HumanEntity player) { - AtomicReference> selfRef = new AtomicReference<>(); - Consumer selfCallback = (message) -> { - if (message == null) return; - - // check permission - if (!player.hasPermission(CustomAnvil.editConfigPermission)) { - player.sendMessage(GuiGlobalActions.NO_EDIT_PERM); - return; - } - - message = message.toLowerCase(Locale.ROOT); - if ("cancel".equalsIgnoreCase(message)) { - player.sendMessage("conflict creation cancelled..."); - show(player); - return; - } - - message = message.replace(' ', '_'); - - // Try to find if it already exists in a for loop - // Not the most efficient on large number of conflict, but it should not run often. - for (EnchantConflictGroup conflict : ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList()) { - if (conflict.getName().equalsIgnoreCase(message)) { - player.sendMessage("\u00A7cPlease enter a conflict name that do not already exist..."); - // wait next message. - CustomAnvil.Companion.getChatListener().setListenedCallback(player, selfRef.get()); - return; - } - } - - // Create new empty conflict and display it to the admin - EnchantConflictGroup conflict = new EnchantConflictGroup( - message, - new IncludeGroup("new_group"), - 0); - - ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList().add(conflict); - updateValueForGeneric(conflict, true); - - // save empty conflict in config - String[] emptyStringArray = new String[0]; - - FileConfiguration config = ConfigHolder.CONFLICT_HOLDER.getConfig(); - config.set(message + ".enchantments", emptyStringArray); - config.set(message + ".notAffectedGroups", emptyStringArray); - config.set(message + ".maxEnchantmentBeforeConflict", 0); - - if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) { - ConfigHolder.CONFLICT_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE); - } - - // show the new conflict config to the player - this.conflictGuiMap.get(conflict).show(player); - - }; - - selfRef.set(selfCallback); - return selfCallback; - } - - @Override - public void reloadValues() { - this.conflictGuiMap.forEach((conflict, gui) -> gui.cleanUnused()); - this.conflictGuiMap.clear(); + if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) { + ConfigHolder.CONFLICT_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE); + } - super.reloadValues(); + return conflict; } @Override @@ -159,35 +69,13 @@ public ItemStack createItemForGeneric(EnchantConflictGroup conflict) { } @Override - protected void updateGeneric(EnchantConflictGroup conflict, ItemStack usedItem) { - EnchantConflictSubSettingGui gui = this.conflictGuiMap.get(conflict); - - GuiItem guiItem; - if (gui == null) { - // Create new sub setting gui - guiItem = new GuiItem(usedItem, CustomAnvil.instance); - gui = new EnchantConflictSubSettingGui(this, conflict, guiItem); - - guiItem.setAction(GuiGlobalActions.openGuiAction(gui)); - - this.conflictGuiMap.put(conflict, gui); - addToPage(guiItem); - } else { - // Replace item with the updated one - guiItem = gui.getParentItemForThisGui(); - guiItem.setItem(usedItem); - } - gui.updateLocal(); - + protected EnchantConflictSubSettingGui newInstanceOfGui(EnchantConflictGroup conflict, GuiItem item) { + return new EnchantConflictSubSettingGui(this, conflict, item); } @Override - protected GuiItem findGuiItemForRemoval(EnchantConflictGroup conflict) { - EnchantConflictSubSettingGui gui = this.conflictGuiMap.get(conflict); - if (gui == null) return null; - - this.conflictGuiMap.remove(conflict); - return gui.getParentItemForThisGui(); + protected String genericDisplayedName() { + return "conflict"; } @Override diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/MainConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/MainConfigGui.java index dce3ff7..a69cc7a 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/MainConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/MainConfigGui.java @@ -29,7 +29,7 @@ private MainConfigGui() { private void init() { Pattern pattern = new Pattern( "I00000000", - "012304560", + "012304567", "Q00000000" ); PatternPane pane = new PatternPane(0, 0, 9, 3, pattern); @@ -70,7 +70,7 @@ private void init() { GuiItem enchantCostItem = GuiGlobalItems.goToGuiItem(enchantCostItemstack, EnchantCostConfigGui.INSTANCE); pane.bindItem('3', enchantCostItem); - // Enchantment Conflicts + // Enchantment Conflicts item ItemStack EnchantConflictItemstack = new ItemStack(Material.OAK_FENCE); ItemMeta enchantConflictMeta = EnchantConflictItemstack.getItemMeta(); @@ -93,6 +93,17 @@ private void init() { pane.bindItem('5', wip5); pane.bindItem('6', wip6); + // Custom recipe item + ItemStack customRecipeItemstack = new ItemStack(Material.CRAFTING_TABLE); + ItemMeta customRecipeMeta = EnchantConflictItemstack.getItemMeta(); + + customRecipeMeta.setDisplayName("\u00A7aCustom recipes"); + customRecipeMeta.setLore(Collections.singletonList("\u00A77Click here to open anvil custom recipe menu")); + customRecipeItemstack.setItemMeta(customRecipeMeta); + + GuiItem customRecipeItem = GuiGlobalItems.goToGuiItem(customRecipeItemstack, CustomRecipeConfigGui.INSTANCE); + pane.bindItem('7', customRecipeItem); + // quit item ItemStack quitItemstack = new ItemStack(Material.BARRIER); ItemMeta quitMeta = quitItemstack.getItemMeta(); diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/MappedElementListConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/MappedElementListConfigGui.java new file mode 100644 index 0000000..7349dca --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/MappedElementListConfigGui.java @@ -0,0 +1,156 @@ +package xyz.alexcrea.cuanvil.gui.config.global; + +import com.github.stefvanschie.inventoryframework.gui.GuiItem; +import io.delilaheve.CustomAnvil; +import org.bukkit.Material; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import xyz.alexcrea.cuanvil.gui.config.settings.subsetting.MappedToListSubSettingGui; +import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions; +import xyz.alexcrea.cuanvil.interfaces.Named; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Locale; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +public abstract class MappedElementListConfigGui< T extends Named, S extends MappedToListSubSettingGui> extends ElementListGlobalConfigGui< T > { + + + protected final HashMap elementGuiMap; + public MappedElementListConfigGui(@NotNull String title) { + super(title); + this.elementGuiMap = new HashMap<>(); + + } + + @Override + protected GuiItem prepareCreateNewItem(){ + // Create new conflict item + ItemStack createItem = new ItemStack(Material.PAPER); + ItemMeta createMeta = createItem.getItemMeta(); + + createMeta.setDisplayName("\u00A7aCreate new "+genericDisplayedName()); + createMeta.setLore(Arrays.asList( + "\u00A77Create a new "+genericDisplayedName()+".", + "\u00A77You will be asked to name the "+genericDisplayedName()+" in chat.", + "\u00A77Then, you should edit the "+genericDisplayedName()+" config as you need" + )); + + createItem.setItemMeta(createMeta); + + return new GuiItem(createItem, (clickEvent) -> { + clickEvent.setCancelled(true); + HumanEntity player = clickEvent.getWhoClicked(); + + // check permission + if (!player.hasPermission(CustomAnvil.editConfigPermission)) { + player.closeInventory(); + player.sendMessage(GuiGlobalActions.NO_EDIT_PERM); + return; + } + player.closeInventory(); + + player.sendMessage("\u00A7eWrite the "+genericDisplayedName()+" name you want to create in the chat.\n" + + "\u00A7eOr write \u00A7ccancel \u00A7eto go back to "+genericDisplayedName()+" config menu"); + + CustomAnvil.Companion.getChatListener().setListenedCallback(player, prepareCreateItemConsumer(player)); + + }, CustomAnvil.instance); + } + + @Override + public void reloadValues() { + this.elementGuiMap.forEach((conflict, gui) -> gui.cleanUnused()); + this.elementGuiMap.clear(); + + super.reloadValues(); + } + + @Override + protected void updateGeneric(T generic, ItemStack usedItem) { + S gui = this.elementGuiMap.get(generic); + + GuiItem guiItem; + if (gui == null) { + // Create new sub setting gui + guiItem = new GuiItem(usedItem, CustomAnvil.instance); + gui = newInstanceOfGui(generic, guiItem); + + guiItem.setAction(GuiGlobalActions.openGuiAction(gui)); + + this.elementGuiMap.put(generic, gui); + addToPage(guiItem); + } else { + // Replace item with the updated one + guiItem = gui.getParentItemForThisGui(); + guiItem.setItem(usedItem); + } + gui.updateLocal(); + + } + + @Override + protected GuiItem findGuiItemForRemoval(T generic) { + S gui = this.elementGuiMap.get(generic); + if (gui == null) return null; + + this.elementGuiMap.remove(generic); + return gui.getParentItemForThisGui(); + } + + protected Consumer prepareCreateItemConsumer(HumanEntity player){ + AtomicReference> selfRef = new AtomicReference<>(); + Consumer selfCallback = (message) -> { + if (message == null) return; + + // check permission + if (!player.hasPermission(CustomAnvil.editConfigPermission)) { + player.sendMessage(GuiGlobalActions.NO_EDIT_PERM); + return; + } + + message = message.toLowerCase(Locale.ROOT); + if ("cancel".equalsIgnoreCase(message)) { + player.sendMessage(genericDisplayedName()+" creation cancelled..."); + show(player); + return; + } + + message = message.replace(' ', '_'); + + // Try to find if it already exists in a for loop + // Not the most efficient on large number of conflict, but it should not run often. + for (T generic : getEveryDisplayableInstanceOfGeneric()) { + if (generic.getName().equalsIgnoreCase(message)) { + player.sendMessage("\u00A7cPlease enter a "+genericDisplayedName()+" name that do not already exist..."); + // wait next message. + CustomAnvil.Companion.getChatListener().setListenedCallback(player, selfRef.get()); + return; + } + } + + T generic = createAndSaveNewEmptyGeneric(message); + + updateValueForGeneric(generic, true); + + // show the new conflict config to the player + this.elementGuiMap.get(generic).show(player); + + update(); + }; + + selfRef.set(selfCallback); + return selfCallback; + } + + protected abstract S newInstanceOfGui(T generic, GuiItem item); + + protected abstract String genericDisplayedName(); + + protected abstract T createAndSaveNewEmptyGeneric(String name); + +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java new file mode 100644 index 0000000..7cea19d --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java @@ -0,0 +1,241 @@ +package xyz.alexcrea.cuanvil.gui.config.settings.subsetting; + +import com.github.stefvanschie.inventoryframework.gui.GuiItem; +import com.github.stefvanschie.inventoryframework.pane.PatternPane; +import com.github.stefvanschie.inventoryframework.pane.util.Pattern; +import io.delilaheve.CustomAnvil; +import kotlin.ranges.IntRange; +import org.bukkit.Material; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import xyz.alexcrea.cuanvil.config.ConfigHolder; +import xyz.alexcrea.cuanvil.gui.config.ConfirmActionGui; +import xyz.alexcrea.cuanvil.gui.config.global.CustomRecipeConfigGui; +import xyz.alexcrea.cuanvil.gui.config.settings.BoolSettingsGui; +import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui; +import xyz.alexcrea.cuanvil.gui.config.settings.ItemSettingGui; +import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions; +import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; +import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant; +import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe; +import xyz.alexcrea.cuanvil.recipe.CustomAnvilRecipeManager; +import xyz.alexcrea.cuanvil.util.CasedStringUtil; + +import java.util.Collections; +import java.util.function.Supplier; + +public class CustomRecipeSubSettingGui extends MappedToListSubSettingGui { + + private final CustomRecipeConfigGui parent; + private final AnvilCustomRecipe anvilRecipe; + private final PatternPane pane; + private boolean shouldWork = true; + + public CustomRecipeSubSettingGui( + @NotNull CustomRecipeConfigGui parent, + @NotNull AnvilCustomRecipe anvilRecipe, + @NotNull GuiItem parentItemForThisGui) { + super(parentItemForThisGui, 3, "title"); + this.parent = parent; + this.anvilRecipe = anvilRecipe; + + Pattern pattern = new Pattern( + GuiSharedConstant.EMPTY_GUI_FULL_LINE, + "01230450D", + "B00000000" + ); + this.pane = new PatternPane(0, 0, 9, 3, pattern); + addPane(this.pane); + + prepareStaticValues(); + } + + BoolSettingsGui.BoolSettingFactory exactCountFactory; + IntSettingsGui.IntSettingFactory xpCostFactory; + ItemSettingGui.ItemSettingFactory leftItemFactory; + ItemSettingGui.ItemSettingFactory rightItemFactory; + ItemSettingGui.ItemSettingFactory resultItemFactory; + + private void prepareStaticValues() { + + GuiGlobalItems.addBackItem(this.pane, this.parent); + GuiGlobalItems.addBackgroundItem(this.pane); + + // Delete item + ItemStack deleteItem = new ItemStack(Material.RED_TERRACOTTA); + ItemMeta deleteMeta = deleteItem.getItemMeta(); + + deleteMeta.setDisplayName("\u00A74DELETE RECIPE"); + deleteMeta.setLore(Collections.singletonList("\u00A7cCaution with this button !")); + + deleteItem.setItemMeta(deleteMeta); + this.pane.bindItem('D', new GuiItem(deleteItem, GuiGlobalActions.openGuiAction(createDeleteGui()), CustomAnvil.instance)); + + // Displayed item will be updated later + + IntRange costRange = AnvilCustomRecipe.Companion.getXP_COST_CONFIG_RANGE(); + exactCountFactory = BoolSettingsGui.boolFactory("title", this, + this.anvilRecipe.getName()+"."+AnvilCustomRecipe.EXACT_COUNT_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, + AnvilCustomRecipe.Companion.getDEFAULT_EXACT_COUNT_CONFIG()); + + xpCostFactory = IntSettingsGui.intFactory("title", this, + this.anvilRecipe.getName()+"."+AnvilCustomRecipe.XP_COST_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, + costRange.getFirst(), costRange.getLast(), AnvilCustomRecipe.Companion.getDEFAULT_XP_COST_CONFIG(), 1, 5, 10); + + + leftItemFactory = ItemSettingGui.itemFactory("title", this, + this.anvilRecipe.getName()+"."+AnvilCustomRecipe.LEFT_ITEM_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, + AnvilCustomRecipe.Companion.getDEFAULT_LEFT_ITEM_CONFIG()); + + rightItemFactory = ItemSettingGui.itemFactory("title", this, + this.anvilRecipe.getName()+"."+AnvilCustomRecipe.EXACT_COUNT_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, + AnvilCustomRecipe.Companion.getDEFAULT_RIGHT_ITEM_CONFIG()); + + resultItemFactory = ItemSettingGui.itemFactory("title", this, + this.anvilRecipe.getName()+"."+AnvilCustomRecipe.EXACT_COUNT_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, + AnvilCustomRecipe.Companion.getDEFAULT_RESULT_ITEM_CONFIG()); + } + + private ConfirmActionGui createDeleteGui() { + Supplier deleteSupplier = () -> { + CustomAnvilRecipeManager manager = ConfigHolder.CUSTOM_RECIPE_HOLDER.getRecipeManager(); + + // Remove from manager + manager.cleanRemove(this.anvilRecipe); + + // Remove from parent + this.parent.removeGeneric(this.anvilRecipe); + + // Remove self + cleanUnused(); + + // Update config file storage + ConfigHolder.CUSTOM_RECIPE_HOLDER.getConfig().set(this.anvilRecipe.getName(), null); + + // Save + boolean success = true; + if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) { + success = ConfigHolder.CONFLICT_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE); + } + + return success; + }; + + return new ConfirmActionGui("\u00A7cDelete \u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(this.anvilRecipe.getName()) + "\u00A7c?", + "\u00A77Confirm that you want to delete this conflict.", + this, this.parent, deleteSupplier + ); + } + + @Override + public void updateGuiValues() { + this.parent.updateValueForGeneric(this.anvilRecipe, true); + // Parent should call updateLocal + } + + public void updateLocal() { + if (!this.shouldWork) return; + + /*// Prepare enchantment lore + ArrayList enchantLore = new ArrayList<>(); + enchantLore.add("\u00A77Allow you to select a list of \u00A75Enchantments \u00A77that this conflict should include"); + Set enchants = getSelectedEnchantments(); + if (enchants.isEmpty()) { + enchantLore.add("\u00A77There is no included enchantment for this conflict."); + } else { + enchantLore.add("\u00A77List of included enchantment for this conflict:"); + Iterator enchantIterator = enchants.iterator(); + + boolean greaterThanMax = enchants.size() > 5; + int maxindex = (greaterThanMax ? 4 : enchants.size()); + for (int i = 0; i < maxindex; i++) { + // format string like "- Fire Protection" + String formattedName = CasedStringUtil.snakeToUpperSpacedCase(enchantIterator.next().getKey().getKey()); + enchantLore.add("\u00A77- \u00A75" + formattedName); + } + if (greaterThanMax) { + enchantLore.add("\u00A77And " + (enchants.size() - 4) + " more..."); + } + + } + + // Prepare group lore + ArrayList groupLore = new ArrayList<>(); + groupLore.add("\u00A77Allow you to select a list of \u00A73Groups \u00A77that this conflict should include"); + Set grouos = getSelectedGroups(); + if (grouos.isEmpty()) { + groupLore.add("\u00A77There is no excluded groups for this conflict."); + } else { + groupLore.add("\u00A77List of excluded groups for this conflict:"); + Iterator groupIterator = grouos.iterator(); + + boolean greaterThanMax = grouos.size() > 5; + int maxindex = (greaterThanMax ? 4 : grouos.size()); + for (int i = 0; i < maxindex; i++) { + // format string like "- Melee Weapons" + String formattedName = CasedStringUtil.snakeToUpperSpacedCase(groupIterator.next().getName()); + groupLore.add("\u00A77- \u00A73" + formattedName); + + } + if (greaterThanMax) { + groupLore.add("\u00A77And " + (grouos.size() - 4) + " more..."); + } + } + + // Configure enchant setting item + ItemStack enchantItem = this.enchantSettingItem.getItem(); + ItemMeta enchantMeta = enchantItem.getItemMeta(); + + enchantMeta.setDisplayName("\u00A7aSelect included \u00A75Enchantments \u00A7aSettings"); + enchantMeta.setLore(enchantLore); + + enchantItem.setItemMeta(enchantMeta); + + this.enchantSettingItem.setItem(enchantItem); // Just in case + + // Configure group setting item + ItemStack groupItem = this.groupSettingItem.getItem(); + ItemMeta groupMeta = groupItem.getItemMeta(); + + groupMeta.setDisplayName("\u00A7aSelect excluded \u00A73Groups \u00A7aSettings"); + groupMeta.setLore(groupLore); + + groupItem.setItemMeta(groupMeta); + + this.groupSettingItem.setItem(groupItem); // Just in case + + + this.pane.bindItem('M', GuiGlobalItems.intSettingGuiItem(this.minBeforeActiveSettingFactory, Material.COMMAND_BLOCK));*/ + update(); + } + + public void cleanUnused() { + for (HumanEntity viewer : getViewers()) { + this.parent.show(viewer); + } + this.shouldWork = false; + + // Just in case something is extremely wrong + GuiItem background = GuiGlobalItems.backgroundItem(); + this.pane.bindItem('1', background); + this.pane.bindItem('2', background); + this.pane.bindItem('3', background); + this.pane.bindItem('4', background); + this.pane.bindItem('5', background); + + this.pane.bindItem('D', background); + } + + @Override + public void show(@NotNull HumanEntity humanEntity) { + if (this.shouldWork) { + super.show(humanEntity); + } else { + this.parent.show(humanEntity); + } + } + + +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java index d6f243f..0acaa8c 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java @@ -14,7 +14,6 @@ import xyz.alexcrea.cuanvil.group.AbstractMaterialGroup; import xyz.alexcrea.cuanvil.group.EnchantConflictGroup; import xyz.alexcrea.cuanvil.group.EnchantConflictManager; -import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.config.ConfirmActionGui; import xyz.alexcrea.cuanvil.gui.config.SelectEnchantmentContainer; import xyz.alexcrea.cuanvil.gui.config.SelectGroupContainer; @@ -34,24 +33,22 @@ import java.util.function.Supplier; import java.util.logging.Level; -public class EnchantConflictSubSettingGui extends ValueUpdatableGui implements SelectEnchantmentContainer, SelectGroupContainer { +public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui implements SelectEnchantmentContainer, SelectGroupContainer { private final EnchantConflictGui parent; private final EnchantConflictGroup enchantConflict; - private final GuiItem parentItemForThisGui; private final PatternPane pane; - private boolean shouldWorld = true; + private boolean shouldWork = true; public EnchantConflictSubSettingGui( @NotNull EnchantConflictGui parent, @NotNull EnchantConflictGroup enchantConflict, @NotNull GuiItem parentItemForThisGui) { - super(3, - "\u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(enchantConflict.getName()) + " \u00A78Config", - CustomAnvil.instance); + super(parentItemForThisGui, + 3, + "\u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(enchantConflict.getName()) + " \u00A78Config"); this.parent = parent; this.enchantConflict = enchantConflict; - this.parentItemForThisGui = parentItemForThisGui; Pattern pattern = new Pattern( GuiSharedConstant.EMPTY_GUI_FULL_LINE, @@ -126,7 +123,7 @@ private ConfirmActionGui createDeleteGui() { manager.conflictList.remove(this.enchantConflict); // Remove from parent - this.parent.removeConflict(this.enchantConflict); + this.parent.removeGeneric(this.enchantConflict); // Remove self cleanUnused(); @@ -143,7 +140,7 @@ private ConfirmActionGui createDeleteGui() { return success; }; - return new ConfirmActionGui("\u00A7cDelete \u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(enchantConflict.getName()) + "\u00A7c?", + return new ConfirmActionGui("\u00A7cDelete \u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(this.enchantConflict.getName()) + "\u00A7c?", "\u00A77Confirm that you want to delete this conflict.", this, this.parent, deleteSupplier ); @@ -155,8 +152,9 @@ public void updateGuiValues() { // Parent should call updateLocal } + @Override public void updateLocal() { - if (!this.shouldWorld) return; + if (!this.shouldWork) return; // Prepare enchantment lore ArrayList enchantLore = new ArrayList<>(); @@ -231,11 +229,12 @@ public void updateLocal() { update(); } + @Override public void cleanUnused() { for (HumanEntity viewer : getViewers()) { this.parent.show(viewer); } - this.shouldWorld = false; + this.shouldWork = false; // Just in case something is extremely wrong GuiItem background = GuiGlobalItems.backgroundItem(); @@ -247,17 +246,13 @@ public void cleanUnused() { @Override public void show(@NotNull HumanEntity humanEntity) { - if (this.shouldWorld) { + if (this.shouldWork) { super.show(humanEntity); } else { this.parent.show(humanEntity); } } - public GuiItem getParentItemForThisGui() { - return parentItemForThisGui; - } - // Select enchantment container methods @Override @@ -267,7 +262,7 @@ public Set getSelectedEnchantments() { @Override public boolean setSelectedEnchantments(Set enchantments) { - if (!this.shouldWorld) { + if (!this.shouldWork) { CustomAnvil.instance.getLogger().info("Trying to save " + enchantConflict.getName() + " enchants but sub config is destroyed"); return false; } @@ -312,7 +307,7 @@ public Set getSelectedGroups() { @Override public boolean setSelectedGroups(Set groups) { - if (!this.shouldWorld) { + if (!this.shouldWork) { CustomAnvil.instance.getLogger().info("Trying to save " + enchantConflict.getName() + " groups but sub config is destroyed"); return false; } @@ -347,4 +342,5 @@ public Set illegalGroups() { return Collections.emptySet(); } + } diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/MappedToListSubSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/MappedToListSubSettingGui.java new file mode 100644 index 0000000..bcadc73 --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/MappedToListSubSettingGui.java @@ -0,0 +1,28 @@ +package xyz.alexcrea.cuanvil.gui.config.settings.subsetting; + +import com.github.stefvanschie.inventoryframework.gui.GuiItem; +import io.delilaheve.CustomAnvil; +import org.jetbrains.annotations.NotNull; +import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; + +public abstract class MappedToListSubSettingGui extends ValueUpdatableGui { + + private final GuiItem item; + public MappedToListSubSettingGui( + GuiItem item, + int rows, + @NotNull String title) { + super(rows, title, CustomAnvil.instance); + this.item = item; + } + + + public GuiItem getParentItemForThisGui() { + return item; + } + + + public abstract void updateLocal(); // TODO + + public abstract void cleanUnused(); // TODO +} diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt index 3e5c5d0..7acf857 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt @@ -3,12 +3,13 @@ package xyz.alexcrea.cuanvil.group import io.delilaheve.CustomAnvil import org.bukkit.Material import org.bukkit.enchantments.Enchantment +import xyz.alexcrea.cuanvil.interfaces.Named class EnchantConflictGroup( - val name: String, + private val name: String, private val cantConflict: AbstractMaterialGroup, val minBeforeBlock: Int -) { +): Named { private val enchantments = HashSet() @@ -62,4 +63,8 @@ class EnchantConflictGroup( return Material.ENCHANTED_BOOK } + override fun getName(): String { + return name + } + } \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt index 80aebf7..45a9f36 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt @@ -139,9 +139,9 @@ class EnchantConflictManager { var result = ConflictType.NO_CONFLICT for (conflict in conflictList) { - CustomAnvil.verboseLog("Is against ${conflict.name}") + CustomAnvil.verboseLog("Is against ${conflict.getName()}") val conflicting = conflict.allowed(base, mat) - CustomAnvil.verboseLog("Was against ${conflict.name} and conflicting: $conflicting ") + CustomAnvil.verboseLog("Was against ${conflict.getName()} and conflicting: $conflicting ") if (!conflicting) { if (conflict.getEnchants().size <= 1) { result = ConflictType.SMALL_CONFLICT diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/interfaces/Named.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/interfaces/Named.kt new file mode 100644 index 0000000..e3cd288 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/interfaces/Named.kt @@ -0,0 +1,7 @@ +package xyz.alexcrea.cuanvil.interfaces + +interface Named { + + fun getName(): String + +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt index 697c3d0..edb1a18 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt @@ -4,9 +4,10 @@ import org.bukkit.configuration.ConfigurationSection import org.bukkit.inventory.ItemStack import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant +import xyz.alexcrea.cuanvil.interfaces.Named class AnvilCustomRecipe( - val name: String, + private val name: String, var exactCount: Boolean, //var exactLeft: Boolean, //var exactRight: Boolean, @@ -16,7 +17,7 @@ class AnvilCustomRecipe( var leftItem: ItemStack?, var rightItem: ItemStack?, var resultItem: ItemStack?, -) { +): Named { // Static config name companion object { @@ -37,9 +38,9 @@ class AnvilCustomRecipe( val DEFAULT_XP_COST_CONFIG = 1 - val DEFAULT_LEFT_ITEM_CONFIG = null - val DEFAULT_RIGHT_ITEM_CONFIG = null - val DEFAULT_RESULT_ITEM_CONFIG = null + val DEFAULT_LEFT_ITEM_CONFIG: ItemStack? = null + val DEFAULT_RIGHT_ITEM_CONFIG: ItemStack? = null + val DEFAULT_RESULT_ITEM_CONFIG: ItemStack? = null; val XP_COST_CONFIG_RANGE = 0..255 @@ -115,5 +116,9 @@ class AnvilCustomRecipe( return true } + override fun getName(): String { + return name + } + } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/CustomAnvilRecipeManager.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/CustomAnvilRecipeManager.kt index 82f80be..8f9dece 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/CustomAnvilRecipeManager.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/CustomAnvilRecipeManager.kt @@ -4,34 +4,37 @@ import io.delilaheve.CustomAnvil import org.bukkit.Material import org.bukkit.configuration.file.FileConfiguration import org.bukkit.inventory.ItemStack -import java.util.LinkedHashMap class CustomAnvilRecipeManager { - lateinit var recipeMap: LinkedHashMap + lateinit var recipeList: ArrayList lateinit var recipeByMat: LinkedHashMap> fun prepareRecipes(config: FileConfiguration) { - recipeMap = LinkedHashMap() + recipeList = ArrayList() recipeByMat = LinkedHashMap() // read all configs val keys = config.getKeys(false) for (key in keys) { - if (recipeMap.containsKey(key)) - continue val recipe = AnvilCustomRecipe.getFromConfig(key) if(recipe == null){ CustomAnvil.log("Can't load recipe $key") continue } - recipeMap[key] = recipe - val leftItem = recipe.leftItem - if(leftItem != null){ - addToMap(recipe, leftItem) - } + cleanAddNew(recipe) + } + + } + + + fun cleanAddNew(recipe: AnvilCustomRecipe){ + recipeList.add(recipe) + val leftItem = recipe.leftItem + if(leftItem != null){ + addToMatMap(recipe, leftItem) } } @@ -46,13 +49,13 @@ class CustomAnvilRecipeManager { test!!.remove(recipe) } if(leftItem != null){ - addToMap(recipe, leftItem) + addToMatMap(recipe, leftItem) } recipe.leftItem = leftItem } - fun addToMap(recipe: AnvilCustomRecipe, leftItem: ItemStack){ + private fun addToMatMap(recipe: AnvilCustomRecipe, leftItem: ItemStack){ var recipeList = recipeByMat[leftItem.type] if(recipeList == null){ recipeList = ArrayList() @@ -62,4 +65,11 @@ class CustomAnvilRecipeManager { } + fun cleanRemove(recipe: AnvilCustomRecipe) { + + recipeList.remove(recipe) + cleanSetLeftItem(recipe, null) + + } + } \ No newline at end of file From c55c1c8c6a1f29276c46df3b5ed53cade64c5ebc Mon Sep 17 00:00:00 2001 From: alexcrea Date: Sat, 6 Apr 2024 16:49:46 +0200 Subject: [PATCH 08/12] Update items and inventory names. Fix some value not updating after config changed. --- .../alexcrea/cuanvil/config/ConfigHolder.java | 2 + .../config/global/CustomRecipeConfigGui.java | 10 ++- .../global/ElementListGlobalConfigGui.java | 9 +- .../subsetting/CustomRecipeSubSettingGui.java | 88 +++---------------- .../EnchantConflictSubSettingGui.java | 6 +- .../cuanvil/group/EnchantConflictGroup.kt | 2 +- .../cuanvil/recipe/AnvilCustomRecipe.kt | 30 ++++++- 7 files changed, 67 insertions(+), 80 deletions(-) diff --git a/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java b/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java index 6fafded..eb74480 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java +++ b/src/main/java/xyz/alexcrea/cuanvil/config/ConfigHolder.java @@ -89,6 +89,7 @@ protected File getLastBackup() { // Save logic public boolean saveToDisk(boolean doBackup) { + CustomAnvil.Companion.log("Saving "+getConfigFileName()); if (doBackup) { if (!saveBackup()) { CustomAnvil.instance.getLogger().severe("Could not save backup. see above."); @@ -110,6 +111,7 @@ public boolean saveToDisk(boolean doBackup) { return false; } + CustomAnvil.Companion.log(getConfigFileName()+" saved successfully"); return true; } diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java index ed00af6..0663347 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java @@ -22,7 +22,7 @@ public class CustomRecipeConfigGui extends MappedElementListConfigGui extends ValueUpdatableGui { + private final String namePrefix; public ElementListGlobalConfigGui(@NotNull String title) { super(6, title, CustomAnvil.instance); + this.namePrefix = title; } @@ -229,7 +231,12 @@ public void show(@NotNull HumanEntity humanEntity) { addPane(page); // set title - setTitle("Conflict Config (" + (pageID + 1) + "/" + (pages.size()) + ")"); + StringBuilder title = new StringBuilder(this.namePrefix); + int pagesSize = this.pages.size(); + if(pagesSize > 1){ + title.append(" (").append(pageID + 1).append('/').append(pagesSize).append(')'); + } + setTitle(title.toString()); super.show(humanEntity); diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java index 7cea19d..9465968 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java @@ -37,7 +37,7 @@ public CustomRecipeSubSettingGui( @NotNull CustomRecipeConfigGui parent, @NotNull AnvilCustomRecipe anvilRecipe, @NotNull GuiItem parentItemForThisGui) { - super(parentItemForThisGui, 3, "title"); + super(parentItemForThisGui, 3, "\u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(anvilRecipe.getName()) + " \u00A78Config"); this.parent = parent; this.anvilRecipe = anvilRecipe; @@ -76,24 +76,24 @@ private void prepareStaticValues() { // Displayed item will be updated later IntRange costRange = AnvilCustomRecipe.Companion.getXP_COST_CONFIG_RANGE(); - exactCountFactory = BoolSettingsGui.boolFactory("title", this, + this.exactCountFactory = BoolSettingsGui.boolFactory("\u00A78Exact count ?", this, this.anvilRecipe.getName()+"."+AnvilCustomRecipe.EXACT_COUNT_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, AnvilCustomRecipe.Companion.getDEFAULT_EXACT_COUNT_CONFIG()); - xpCostFactory = IntSettingsGui.intFactory("title", this, + this.xpCostFactory = IntSettingsGui.intFactory("\u00A78Recipe Xp Cost", this, this.anvilRecipe.getName()+"."+AnvilCustomRecipe.XP_COST_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, costRange.getFirst(), costRange.getLast(), AnvilCustomRecipe.Companion.getDEFAULT_XP_COST_CONFIG(), 1, 5, 10); - leftItemFactory = ItemSettingGui.itemFactory("title", this, + this.leftItemFactory = ItemSettingGui.itemFactory("\u00A78Recipe \u00A7eLeft \u00A78Item", this, this.anvilRecipe.getName()+"."+AnvilCustomRecipe.LEFT_ITEM_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, AnvilCustomRecipe.Companion.getDEFAULT_LEFT_ITEM_CONFIG()); - rightItemFactory = ItemSettingGui.itemFactory("title", this, + this.rightItemFactory = ItemSettingGui.itemFactory("\u00A78Recipe \u00A7eLeft \u00A78Item", this, this.anvilRecipe.getName()+"."+AnvilCustomRecipe.EXACT_COUNT_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, AnvilCustomRecipe.Companion.getDEFAULT_RIGHT_ITEM_CONFIG()); - resultItemFactory = ItemSettingGui.itemFactory("title", this, + this.resultItemFactory = ItemSettingGui.itemFactory("\u00A78Recipe \u00A7aResult \u00A78Item", this, this.anvilRecipe.getName()+"."+AnvilCustomRecipe.EXACT_COUNT_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, AnvilCustomRecipe.Companion.getDEFAULT_RESULT_ITEM_CONFIG()); } @@ -131,83 +131,23 @@ private ConfirmActionGui createDeleteGui() { @Override public void updateGuiValues() { + // update value from config to conflict + this.anvilRecipe.updateFromFile(); + + // Parent should call updateLocal with this call this.parent.updateValueForGeneric(this.anvilRecipe, true); - // Parent should call updateLocal } public void updateLocal() { if (!this.shouldWork) return; - /*// Prepare enchantment lore - ArrayList enchantLore = new ArrayList<>(); - enchantLore.add("\u00A77Allow you to select a list of \u00A75Enchantments \u00A77that this conflict should include"); - Set enchants = getSelectedEnchantments(); - if (enchants.isEmpty()) { - enchantLore.add("\u00A77There is no included enchantment for this conflict."); - } else { - enchantLore.add("\u00A77List of included enchantment for this conflict:"); - Iterator enchantIterator = enchants.iterator(); - - boolean greaterThanMax = enchants.size() > 5; - int maxindex = (greaterThanMax ? 4 : enchants.size()); - for (int i = 0; i < maxindex; i++) { - // format string like "- Fire Protection" - String formattedName = CasedStringUtil.snakeToUpperSpacedCase(enchantIterator.next().getKey().getKey()); - enchantLore.add("\u00A77- \u00A75" + formattedName); - } - if (greaterThanMax) { - enchantLore.add("\u00A77And " + (enchants.size() - 4) + " more..."); - } - - } - - // Prepare group lore - ArrayList groupLore = new ArrayList<>(); - groupLore.add("\u00A77Allow you to select a list of \u00A73Groups \u00A77that this conflict should include"); - Set grouos = getSelectedGroups(); - if (grouos.isEmpty()) { - groupLore.add("\u00A77There is no excluded groups for this conflict."); - } else { - groupLore.add("\u00A77List of excluded groups for this conflict:"); - Iterator groupIterator = grouos.iterator(); - - boolean greaterThanMax = grouos.size() > 5; - int maxindex = (greaterThanMax ? 4 : grouos.size()); - for (int i = 0; i < maxindex; i++) { - // format string like "- Melee Weapons" - String formattedName = CasedStringUtil.snakeToUpperSpacedCase(groupIterator.next().getName()); - groupLore.add("\u00A77- \u00A73" + formattedName); - - } - if (greaterThanMax) { - groupLore.add("\u00A77And " + (grouos.size() - 4) + " more..."); - } - } - - // Configure enchant setting item - ItemStack enchantItem = this.enchantSettingItem.getItem(); - ItemMeta enchantMeta = enchantItem.getItemMeta(); - - enchantMeta.setDisplayName("\u00A7aSelect included \u00A75Enchantments \u00A7aSettings"); - enchantMeta.setLore(enchantLore); - - enchantItem.setItemMeta(enchantMeta); - - this.enchantSettingItem.setItem(enchantItem); // Just in case - - // Configure group setting item - ItemStack groupItem = this.groupSettingItem.getItem(); - ItemMeta groupMeta = groupItem.getItemMeta(); - - groupMeta.setDisplayName("\u00A7aSelect excluded \u00A73Groups \u00A7aSettings"); - groupMeta.setLore(groupLore); - - groupItem.setItemMeta(groupMeta); + GuiItem exactCountItem = GuiGlobalItems.boolSettingGuiItem(this.exactCountFactory); + pane.bindItem('1', exactCountItem); - this.groupSettingItem.setItem(groupItem); // Just in case + GuiItem xpCostItem = GuiGlobalItems.intSettingGuiItem(this.xpCostFactory, Material.EXPERIENCE_BOTTLE); + pane.bindItem('2', xpCostItem); - this.pane.bindItem('M', GuiGlobalItems.intSettingGuiItem(this.minBeforeActiveSettingFactory, Material.COMMAND_BLOCK));*/ update(); } diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java index 0acaa8c..b9cfefa 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/EnchantConflictSubSettingGui.java @@ -148,8 +148,12 @@ private ConfirmActionGui createDeleteGui() { @Override public void updateGuiValues() { + // update value from config to conflict + int minBeforeBlock = ConfigHolder.CONFLICT_HOLDER.getConfig().getInt(this.enchantConflict.getName()+'.'+EnchantConflictManager.ENCH_MAX_PATH, 0); + this.enchantConflict.setMinBeforeBlock(minBeforeBlock); + + // Parent should call updateLocal with this call this.parent.updateValueForGeneric(this.enchantConflict, true); - // Parent should call updateLocal } @Override diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt index 7acf857..44a4bef 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt @@ -8,7 +8,7 @@ import xyz.alexcrea.cuanvil.interfaces.Named class EnchantConflictGroup( private val name: String, private val cantConflict: AbstractMaterialGroup, - val minBeforeBlock: Int + var minBeforeBlock: Int ): Named { private val enchantments = HashSet() diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt index edb1a18..41b7b09 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt @@ -89,10 +89,38 @@ class AnvilCustomRecipe( if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) { - ConfigHolder.CONFLICT_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE); + ConfigHolder.CUSTOM_RECIPE_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE); } } + fun updateFromFile(){ + this.exactCount = ConfigHolder.CUSTOM_RECIPE_HOLDER.config.getBoolean( + "$name.$EXACT_COUNT_CONFIG", + DEFAULT_EXACT_COUNT_CONFIG + ) + + this.xpCostPerCraft = ConfigHolder.CUSTOM_RECIPE_HOLDER.config.getInt( + "$name.$XP_COST_CONFIG", + DEFAULT_XP_COST_CONFIG + ) + + // Update items + this.leftItem = ConfigHolder.CUSTOM_RECIPE_HOLDER.config.getItemStack( + "$name.$LEFT_ITEM_CONFIG", + DEFAULT_LEFT_ITEM_CONFIG + ) + + this.rightItem = ConfigHolder.CUSTOM_RECIPE_HOLDER.config.getItemStack( + "$name.$RIGHT_ITEM_CONFIG", + DEFAULT_RIGHT_ITEM_CONFIG + ) + + this.resultItem = ConfigHolder.CUSTOM_RECIPE_HOLDER.config.getItemStack( + "$name.$RESULT_ITEM_CONFIG", + DEFAULT_RESULT_ITEM_CONFIG + ) + } + fun testItem(item1: ItemStack, item2: ItemStack?): Boolean { // We assume this function can be call only if leftItem != null From 81a965e52304fa94c07a5948eb7be9319e142dd9 Mon Sep 17 00:00:00 2001 From: alexcrea Date: Sun, 7 Apr 2024 02:31:19 +0200 Subject: [PATCH 09/12] Finish custom recipe config gui. --- .../config/global/CustomRecipeConfigGui.java | 2 + .../gui/config/settings/ItemSettingGui.java | 4 +- .../subsetting/CustomRecipeSubSettingGui.java | 24 ++++++---- .../cuanvil/gui/util/GuiGlobalItems.java | 44 +++++++++++++++++++ 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java index 0663347..11cbaed 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java @@ -2,6 +2,7 @@ import com.github.stefvanschie.inventoryframework.gui.GuiItem; import org.bukkit.Material; +import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import xyz.alexcrea.cuanvil.config.ConfigHolder; @@ -41,6 +42,7 @@ protected ItemStack createItemForGeneric(AnvilCustomRecipe recipe) { ItemMeta meta = displaydItem.getItemMeta(); meta.setDisplayName("\u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(recipe.getName()) + " \u00A7fCustom recipe"); + meta.addItemFlags(ItemFlag.values()); boolean shouldWork = recipe.validate(); diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java index 95c4f43..1c5e758 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java @@ -71,7 +71,7 @@ public void prepareStaticItems(){ CustomAnvil.Companion.getChatListener().setListenedCallback(player, (message) ->{ - if(message != null) return; + if(message == null) return; show(player); }); @@ -152,7 +152,7 @@ protected Consumer setItemAsCursor() { //TODO redo consumer if(cursor.getType().isAir()) return; - now = cursor; + this.now = cursor; updateValueDisplay(); update(); diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java index 9465968..148330c 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/subsetting/CustomRecipeSubSettingGui.java @@ -43,7 +43,7 @@ public CustomRecipeSubSettingGui( Pattern pattern = new Pattern( GuiSharedConstant.EMPTY_GUI_FULL_LINE, - "01230450D", + "01203450D", "B00000000" ); this.pane = new PatternPane(0, 0, 9, 3, pattern); @@ -85,16 +85,16 @@ private void prepareStaticValues() { costRange.getFirst(), costRange.getLast(), AnvilCustomRecipe.Companion.getDEFAULT_XP_COST_CONFIG(), 1, 5, 10); - this.leftItemFactory = ItemSettingGui.itemFactory("\u00A78Recipe \u00A7eLeft \u00A78Item", this, + this.leftItemFactory = ItemSettingGui.itemFactory("\u00A7eRecipe Left \u00A78Item", this, this.anvilRecipe.getName()+"."+AnvilCustomRecipe.LEFT_ITEM_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, AnvilCustomRecipe.Companion.getDEFAULT_LEFT_ITEM_CONFIG()); - this.rightItemFactory = ItemSettingGui.itemFactory("\u00A78Recipe \u00A7eLeft \u00A78Item", this, - this.anvilRecipe.getName()+"."+AnvilCustomRecipe.EXACT_COUNT_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, + this.rightItemFactory = ItemSettingGui.itemFactory("\u00A7eRecipe Right \u00A78Item", this, + this.anvilRecipe.getName()+"."+AnvilCustomRecipe.RIGHT_ITEM_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, AnvilCustomRecipe.Companion.getDEFAULT_RIGHT_ITEM_CONFIG()); - this.resultItemFactory = ItemSettingGui.itemFactory("\u00A78Recipe \u00A7aResult \u00A78Item", this, - this.anvilRecipe.getName()+"."+AnvilCustomRecipe.EXACT_COUNT_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, + this.resultItemFactory = ItemSettingGui.itemFactory("\u00A7aRecipe Result \u00A78Item", this, + this.anvilRecipe.getName()+"."+AnvilCustomRecipe.RESULT_ITEM_CONFIG, ConfigHolder.CUSTOM_RECIPE_HOLDER, AnvilCustomRecipe.Companion.getDEFAULT_RESULT_ITEM_CONFIG()); } @@ -142,12 +142,20 @@ public void updateLocal() { if (!this.shouldWork) return; GuiItem exactCountItem = GuiGlobalItems.boolSettingGuiItem(this.exactCountFactory); - pane.bindItem('1', exactCountItem); + this.pane.bindItem('1', exactCountItem); GuiItem xpCostItem = GuiGlobalItems.intSettingGuiItem(this.xpCostFactory, Material.EXPERIENCE_BOTTLE); - pane.bindItem('2', xpCostItem); + this.pane.bindItem('2', xpCostItem); + + GuiItem leftGuiItem = GuiGlobalItems.itemSettingGuiItem(this.leftItemFactory); + this.pane.bindItem('3', leftGuiItem); + GuiItem rightGuiItem = GuiGlobalItems.itemSettingGuiItem(this.rightItemFactory); + this.pane.bindItem('4', rightGuiItem); + GuiItem resultGuiItem = GuiGlobalItems.itemSettingGuiItem(this.resultItemFactory); + this.pane.bindItem('5', resultGuiItem); + update(); } diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiGlobalItems.java b/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiGlobalItems.java index fb10605..f8b4656 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiGlobalItems.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiGlobalItems.java @@ -12,8 +12,10 @@ import xyz.alexcrea.cuanvil.gui.config.settings.AbstractSettingGui; import xyz.alexcrea.cuanvil.gui.config.settings.BoolSettingsGui; import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui; +import xyz.alexcrea.cuanvil.gui.config.settings.ItemSettingGui; import xyz.alexcrea.cuanvil.util.CasedStringUtil; +import java.nio.charset.MalformedInputException; import java.util.Collections; /** @@ -264,6 +266,48 @@ public static GuiItem intSettingGuiItem( return intSettingGuiItem(factory, itemMat, CasedStringUtil.detectToUpperSpacedCase(configPath)); } + /** + * Create a new item setting GuiItem. + * This item will create and open an item setting GUI from the factory. + * Item's name will be the factory set title. + * + * @param factory The setting's GUI factory. + * @param name Name of the item. + * @return A formatted GuiItem that will create and open a GUI for the item setting. + */ + public static GuiItem itemSettingGuiItem( + @NotNull ItemSettingGui.ItemSettingFactory factory, + @NotNull String name + ) { + ItemStack item = factory.getConfiguredValue(); + if(item == null || item.getType().isAir()){ + item = new ItemStack(Material.BARRIER); + }else{ + item = item.clone(); + } + ItemMeta meta = item.getItemMeta(); + meta.setDisplayName("\u00A7a" + name); + + item.setItemMeta(meta); + + return openSettingGuiItem(item, factory); + } + + /** + * Create a new item setting GuiItem. + * This item will create and open an item setting GUI from the factory. + * Item's name will be the factory set title. + * + * @param factory The setting's GUI factory. + * @return A formatted GuiItem that will create and open a GUI for the item setting. + */ + public static GuiItem itemSettingGuiItem( + @NotNull ItemSettingGui.ItemSettingFactory factory + ) { + String configPath = getConfigNameFromPath(factory.getConfigPath()); + return itemSettingGuiItem(factory, CasedStringUtil.detectToUpperSpacedCase(configPath)); + } + /** * Create an arbitrary GuiItem from a unique setting and item's property. * From a646d5ab02c940382fca605401b752565e205ad7 Mon Sep 17 00:00:00 2001 From: alexcrea Date: Sun, 7 Apr 2024 04:20:07 +0200 Subject: [PATCH 10/12] Fix multiple issue about custom recipes - Gui item not using a clone of the result item. - Every recipe item being removed even if there was leftover --- .../gui/config/settings/ItemSettingGui.java | 10 ++- .../io/delilaheve/AnvilEventListener.kt | 84 ++++++++++++++++--- .../cuanvil/recipe/AnvilCustomRecipe.kt | 30 +++++-- 3 files changed, 105 insertions(+), 19 deletions(-) diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java index 1c5e758..8f44e5e 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/ItemSettingGui.java @@ -115,7 +115,7 @@ protected void updateValueDisplay() { // Get displayed value for this config. ItemStack displayedItem; if(this.now != null){ - displayedItem = this.now; + displayedItem = this.now.clone(); }else{ displayedItem = new ItemStack(Material.BARRIER); ItemMeta valueMeta = displayedItem.getItemMeta(); @@ -161,7 +161,7 @@ protected Consumer setItemAsCursor() { //TODO redo consumer @Override public boolean onSave() { - holder.config.getConfig().set(holder.configPath, now); + holder.config.getConfig().set(holder.configPath, this.now); MetricsUtil.INSTANCE.notifyChange(this.holder.config, this.holder.configPath); if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) { @@ -172,7 +172,11 @@ public boolean onSave() { @Override public boolean hadChange() { - return now != before; + if(now == null) { + return before != null; + } + + return !now.equals(before); } /** diff --git a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt index 0718d81..dca6723 100644 --- a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt +++ b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt @@ -11,7 +11,6 @@ import io.delilaheve.util.ItemUtil.setEnchantmentsUnsafe import io.delilaheve.util.ItemUtil.unitRepair import org.bukkit.GameMode import org.bukkit.Material -import org.bukkit.entity.Item import org.bukkit.entity.Player import org.bukkit.event.Event import org.bukkit.event.EventHandler @@ -62,16 +61,12 @@ class AnvilEventListener : Listener { // Test custom recipe val recipe = getCustomRecipe(first, second) + CustomAnvil.verboseLog("custom recipe not null? ${recipe != null}") if(recipe != null){ val amount = getCustomRecipeAmount(recipe, first, second) - val resultItem: ItemStack - if(amount <= 1){ - resultItem = recipe.resultItem!! - }else{ - resultItem = recipe.resultItem!!.clone() - resultItem.amount *= amount - } + val resultItem: ItemStack = recipe.resultItem!!.clone() + resultItem.amount *= amount event.result = resultItem handleAnvilXp(inventory, event, recipe.xpCostPerCraft * amount, true) @@ -190,10 +185,13 @@ class AnvilEventListener : Listener { val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT) - // Test custom craft + // Test custom recipe val recipe = getCustomRecipe(leftItem, rightItem) if(recipe != null){ event.result = Event.Result.ALLOW + onCustomCraft( + event, recipe, player, + leftItem, rightItem, output, inventory) return } @@ -227,6 +225,69 @@ class AnvilEventListener : Listener { } } + private fun onCustomCraft(event: InventoryClickEvent, + recipe: AnvilCustomRecipe, + player: Player, + leftItem: ItemStack, + rightItem: ItemStack?, + output: ItemStack, + inventory: AnvilInventory) { + event.result = Event.Result.DENY + + if(recipe.leftItem == null) return // in case it changed + + val amount = getCustomRecipeAmount(recipe, leftItem, rightItem) + val xpCost = amount * recipe.xpCostPerCraft + + if ((player.gameMode != GameMode.CREATIVE) && (player.level < xpCost)) return + + // We give the item manually + // But first we check if we should give the item + val slotDestination = getActionSlot(event, player) + if (slotDestination.type == SlotType.NO_SLOT) return + + // If not creative middle click... + if (event.click != ClickType.MIDDLE) { + // We remove what should be removed + leftItem.amount -= amount * recipe.leftItem!!.amount + inventory.setItem(ANVIL_INPUT_LEFT, leftItem) + + if(rightItem != null){ + if(recipe.rightItem == null) return // in case it changed + + rightItem.amount -= amount * recipe.rightItem!!.amount + inventory.setItem(ANVIL_INPUT_RIGHT, rightItem) + } + player.level -= amount + + // Then we try to find the new values for the anvil + val newAmount = getCustomRecipeAmount(recipe, leftItem, rightItem) + + if(newAmount <= 0){ + inventory.setItem(ANVIL_OUTPUT_SLOT, null) + }else{ + val resultItem: ItemStack = recipe.resultItem!!.clone() + resultItem.amount *= newAmount + + val newXp = newAmount * newAmount + + inventory.repairCost = newXp + event.view.setProperty(REPAIR_COST, newXp) + + inventory.setItem(ANVIL_OUTPUT_SLOT, resultItem) + } + } + + // Finally, we add the item to the player + if (slotDestination.type == SlotType.CURSOR) { + player.setItemOnCursor(output) + } else {// We assume SlotType == SlotType.INVENTORY + player.inventory.setItem(slotDestination.slot, output) + } + + + } + private fun onUnitRepairExtract( leftItem: ItemStack, rightItem: ItemStack, @@ -405,6 +466,7 @@ class AnvilEventListener : Listener { val recipeList = ConfigHolder.CUSTOM_RECIPE_HOLDER.recipeManager.recipeByMat[leftItem.type] ?: return null + CustomAnvil.verboseLog("Testing " + recipeList.size+" recipe...") for (recipe in recipeList) { if(recipe.testItem(leftItem, rightItem)){ return recipe @@ -425,7 +487,9 @@ class AnvilEventListener : Listener { val resultItem = recipe.resultItem!! // we know exist as the recipe was returned to us val maxResultAmount = resultItem.type.maxStackSize/resultItem.amount val maxLeftAmount = leftItem.amount/recipe.leftItem!!.amount - val maxRightAmount = if(rightItem == null){ 1 } else{ rightItem.amount/recipe.rightItem!!.amount } + val maxRightAmount = if(rightItem == null){ maxLeftAmount } else{ rightItem.amount/recipe.rightItem!!.amount } + + CustomAnvil.verboseLog("resultItem: $resultItem, maxResultAmount: $maxResultAmount, maxLeftAmount: $maxLeftAmount, maxRightAmount: $maxRightAmount") min(min(maxResultAmount, maxLeftAmount), maxRightAmount) } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt index 41b7b09..fbd2866 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/recipe/AnvilCustomRecipe.kt @@ -1,5 +1,6 @@ package xyz.alexcrea.cuanvil.recipe +import io.delilaheve.CustomAnvil import org.bukkit.configuration.ConfigurationSection import org.bukkit.inventory.ItemStack import xyz.alexcrea.cuanvil.config.ConfigHolder @@ -105,7 +106,7 @@ class AnvilCustomRecipe( ) // Update items - this.leftItem = ConfigHolder.CUSTOM_RECIPE_HOLDER.config.getItemStack( + val leftItem = ConfigHolder.CUSTOM_RECIPE_HOLDER.config.getItemStack( "$name.$LEFT_ITEM_CONFIG", DEFAULT_LEFT_ITEM_CONFIG ) @@ -119,27 +120,44 @@ class AnvilCustomRecipe( "$name.$RESULT_ITEM_CONFIG", DEFAULT_RESULT_ITEM_CONFIG ) + + // Update material map + ConfigHolder.CUSTOM_RECIPE_HOLDER.recipeManager.cleanSetLeftItem(this, leftItem) + } fun testItem(item1: ItemStack, item2: ItemStack?): Boolean { + CustomAnvil.verboseLog("Testing $name $leftItem") // We assume this function can be call only if leftItem != null // Test is valid if(!validate()) return false + val leftSimilar = leftItem!!.isSimilar(item1) + CustomAnvil.verboseLog("Validated test !") + // test of left item - if(!leftItem!!.isSimilar(item1)) return false // Test similar + if(!leftSimilar) return false // Test similar if(exactCount){ if((leftItem!!.amount != item1.amount)) return false // test exact amount }else if(item1.amount < leftItem!!.amount) return false // test if it has at least the amount we ask + CustomAnvil.verboseLog("Left item passed !") + // we don't know if right item can be if(rightItem == null){ // null test if(item2 != null) return false - }else if(!rightItem!!.isSimilar(item2)) return false // test if similar when not null - else if(exactCount) { - if (rightItem!!.amount != item2!!.amount) return false // test exact amount - }else if(item2!!.amount < rightItem!!.amount) return false // test if it has at least the amount we ask + }else { + val rightSimilar = rightItem!!.isSimilar(item2) + CustomAnvil.verboseLog("Right similar: $rightSimilar") + if(!rightSimilar) return false // test if similar when not null + + if(exactCount) { + if (rightItem!!.amount != item2!!.amount) return false // test exact amount + }else if(item2!!.amount < rightItem!!.amount) return false // test if it has at least the amount we ask + } + + CustomAnvil.verboseLog("Right item passed !") return true } From fe28e272850c9377b4df46a75fc4fc77c378b914 Mon Sep 17 00:00:00 2001 From: alexcrea Date: Sun, 7 Apr 2024 04:29:40 +0200 Subject: [PATCH 11/12] Fix dupe on exact count custom recipe. --- src/main/kotlin/io/delilaheve/AnvilEventListener.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt index dca6723..4de60f4 100644 --- a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt +++ b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt @@ -263,7 +263,8 @@ class AnvilEventListener : Listener { // Then we try to find the new values for the anvil val newAmount = getCustomRecipeAmount(recipe, leftItem, rightItem) - if(newAmount <= 0){ + CustomAnvil.verboseLog("new amount is $newAmount") + if(newAmount <= 0 || recipe.exactCount){ inventory.setItem(ANVIL_OUTPUT_SLOT, null) }else{ val resultItem: ItemStack = recipe.resultItem!!.clone() @@ -481,7 +482,15 @@ class AnvilEventListener : Listener { leftItem: ItemStack, rightItem: ItemStack? ): Int{ - return if(recipe.exactCount) { 1 } + return if(recipe.exactCount) { + if(leftItem.amount != recipe.leftItem!!.amount){ + 0 + }else if(rightItem != null && rightItem.amount != recipe.rightItem!!.amount){ + 0 + }else{ + 1 + } + } else { // test amount val resultItem = recipe.resultItem!! // we know exist as the recipe was returned to us From 30095e32684ed309bec66d8a4a717b71a2c012e9 Mon Sep 17 00:00:00 2001 From: alexcrea Date: Sun, 7 Apr 2024 04:35:20 +0200 Subject: [PATCH 12/12] version up. --- build.gradle.kts | 2 +- src/main/resources/plugin.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 0a71e7f..fbb6d02 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "xyz.alexcrea" -version = "1.3.2-A2" +version = "1.4.0a" repositories { mavenCentral() diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 52fe71d..d372cbb 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ main: io.delilaheve.CustomAnvil name: CustomAnvil prefix: "Custom Anvil" -version: 1.3.2-A2 +version: 1.4.0a description: Allow to customise anvil mechanics api-version: 1.18 load: POSTWORLD