From a40d2c6530de75044cec3c9b2c6e91abc32f3d37 Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Tue, 9 Jul 2024 13:56:19 +0200 Subject: [PATCH] Added custom anvil recipe api & builder. Fixed Conflict not being registered. Build conflict on the builder instance instead of the ConflictAPI class. --- .../cuanvil/api/AnvilRecipeBuilder.java | 205 ++++++++++++++++++ .../xyz/alexcrea/cuanvil/api/ConflictAPI.java | 83 +------ .../alexcrea/cuanvil/api/ConflictBuilder.java | 75 ++++++- .../cuanvil/api/CustomAnvilRecipeApi.java | 82 +++++++ .../EnchantmentSquaredDependency.kt | 2 +- .../cuanvil/recipe/AnvilCustomRecipe.kt | 21 +- 6 files changed, 386 insertions(+), 82 deletions(-) create mode 100644 src/main/java/xyz/alexcrea/cuanvil/api/AnvilRecipeBuilder.java create mode 100644 src/main/java/xyz/alexcrea/cuanvil/api/CustomAnvilRecipeApi.java diff --git a/src/main/java/xyz/alexcrea/cuanvil/api/AnvilRecipeBuilder.java b/src/main/java/xyz/alexcrea/cuanvil/api/AnvilRecipeBuilder.java new file mode 100644 index 0000000..74e8118 --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/api/AnvilRecipeBuilder.java @@ -0,0 +1,205 @@ +package xyz.alexcrea.cuanvil.api; + +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe; + +/** + * A Builder for custom craft using anvil. + */ +@SuppressWarnings("unused") +public class AnvilRecipeBuilder { + + private @NotNull String name; + private boolean exactCount; + + private int xpCostPerCraft; + + private @Nullable ItemStack leftItem; + private @Nullable ItemStack rightItem; + private @Nullable ItemStack resultItem; + + /** + * Instantiates a new Anvil recipe builder. + * exact count default to true. + * xp cost per craft default to 1. + * + * @param name The recipe name + */ + public AnvilRecipeBuilder(@NotNull String name) { + this.name = name; + + this.exactCount = true; + this.xpCostPerCraft = 1; + + this.leftItem = null; + this.rightItem = null; + this.resultItem = null; + } + + /** + * Gets the recipe name. + * + * @return This recipe builder instance. + */ + @NotNull + public String getName() { + return name; + } + + /** + * Sets the recipe name. + * + * @param name The recipe name + * @return This recipe builder instance. + */ + public AnvilRecipeBuilder setName(String name) { + this.name = name; + return this; + } + + /** + * Get if the recipe is exact count. + *
+ * Exact count mean the recipe can only be crafted 1 by 1. + * If set to false, then it will craft as much as possible in 1 go and will keep unused material onto the anvil inventory. + * + * @return If the recipe is exact count. + */ + public boolean isExactCount() { + return exactCount; + } + + /** + * Sets if the recipe is exact count. + *
+ * Exact count mean the recipe can only be crafted 1 by 1. + * If set to false, then it will craft as much as possible in 1 go and will keep unused material onto the anvil inventory. + * + * @param exactCount If the recipe is exact count + * @return This recipe builder instance. + */ + public AnvilRecipeBuilder setExactCount(boolean exactCount) { + this.exactCount = exactCount; + return this; + } + + /** + * Get the xp level cost per craft. + * + * @return The xp level cost per craft + */ + public int getXpCostPerCraft() { + return xpCostPerCraft; + } + + /** + * Sets the xp level cost per craft. + * + * @param xpCostPerCraft The xp level cost per craft + * @return This recipe builder instance. + */ + public AnvilRecipeBuilder setXpCostPerCraft(int xpCostPerCraft) { + this.xpCostPerCraft = xpCostPerCraft; + return this; + } + + /** + * Get the left item of the recipe. + * If null (default) then the recipe will not be able to be registered. + * + * @return The left item + */ + @Nullable + public ItemStack getLeftItem() { + return leftItem; + } + + /** + * Set the left item. + * If null (default) then the recipe will not be able to be registered. + * + * @param leftItem the left item + * @return This recipe builder instance. + */ + public AnvilRecipeBuilder setLeftItem(ItemStack leftItem) { + this.leftItem = leftItem; + return this; + } + + /** + * Get the recipe right item. + * null on default new instance. + * + * @return The right item + */ + @Nullable + public ItemStack getRightItem() { + return rightItem; + } + + /** + * Set the recipe right item. + * null on default new instance. + * + * @param rightItem the right item + * @return This recipe builder instance. + */ + public AnvilRecipeBuilder setRightItem(ItemStack rightItem) { + this.rightItem = rightItem; + return this; + } + + /** + * Get the recipe result item. + * If null (default) then the recipe will not be able to be registered. + * + * @return The result item + */ + @Nullable + public ItemStack getResultItem() { + return resultItem; + } + + /** + * Set the recipe result item. + * If null (default) then the recipe will not be able to be registered. + * + * @param resultItem The result item + * @return This recipe builder instance. + */ + public AnvilRecipeBuilder setResultItem(ItemStack resultItem) { + this.resultItem = resultItem; + return this; + } + + /** + * Build the anvil custom recipe. + * Should probably use {@link #registerIfAbsent() registerIfAbsent} or {@link ConflictAPI#addConflict(ConflictBuilder) addConflict}. + * + * @return A new anvil custom recipe base on this builder. + */ + @Nullable // null if missing argument + public AnvilCustomRecipe build() { + if(leftItem == null || rightItem == null) return null; + + return new AnvilCustomRecipe( + this.name, + this.exactCount, + this.xpCostPerCraft, + this.leftItem, this.rightItem, this.resultItem + ); + } + + /** + * Register this recipe if absent. + * Equivalent to {@link ConflictAPI#addConflict(ConflictBuilder)} + * + * @return True if successful. + */ + public boolean registerIfAbsent(){ + return CustomAnvilRecipeApi.addRecipe(this); + } + +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/api/ConflictAPI.java b/src/main/java/xyz/alexcrea/cuanvil/api/ConflictAPI.java index 0444403..bab98b8 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/api/ConflictAPI.java +++ b/src/main/java/xyz/alexcrea/cuanvil/api/ConflictAPI.java @@ -5,10 +5,8 @@ import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.configuration.file.FileConfiguration; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import xyz.alexcrea.cuanvil.config.ConfigHolder; -import xyz.alexcrea.cuanvil.enchant.CAEnchantment; -import xyz.alexcrea.cuanvil.group.*; +import xyz.alexcrea.cuanvil.group.EnchantConflictGroup; import xyz.alexcrea.cuanvil.gui.config.global.EnchantConflictGui; import java.util.Collections; @@ -31,7 +29,7 @@ public class ConflictAPI { * Write and add a conflict. * Will not write the conflict if it already exists. * - * @param builder The conflict builder to base on + * @param builder The conflict builder to be based on * @return True if successful. */ public static boolean addConflict(@NotNull ConflictBuilder builder){ @@ -40,75 +38,17 @@ public class ConflictAPI { if(!writeConflict(builder, false)) return false; - AbstractMaterialGroup materials = extractGroup(builder); - EnchantConflictGroup conflict = new EnchantConflictGroup(builder.getName(), materials, builder.getMaxBeforeConflict()); - appendEnchantments(builder, conflict); + EnchantConflictGroup conflict = builder.build(); + // Register conflict + ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList().add(conflict); + + // Add conflict to gui EnchantConflictGui.INSTANCE.updateValueForGeneric(conflict, true); return true; } - /** - * Append builders stored enchantments into conflict. - * - * @param builder The builder source - * @param conflict The conflict target - */ - protected static void appendEnchantments(@NotNull ConflictBuilder builder, @NotNull EnchantConflictGroup conflict){ - for (String enchantmentName : builder.getEnchantmentNames()){ - if(appendEnchantment(conflict, EnchantmentApi.getByName(enchantmentName))){ - CustomAnvil.instance.getLogger().warning("Could not find enchantment " + enchantmentName + " for conflict " + builder.getName()); - logConflictOrigin(builder); - } - } - for (NamespacedKey enchantmentKey : builder.getEnchantmentKeys()){ - if(!appendEnchantment(conflict, EnchantmentApi.getByKey(enchantmentKey))){ - CustomAnvil.instance.getLogger().warning("Could not find enchantment " + enchantmentKey + " for conflict " + builder.getName()); - logConflictOrigin(builder); - } - } - } - - /** - * Append an enchantment. - * - * @param conflict The conflict target - * @param enchantment The enchantment - * @return True if successful. - */ - protected static boolean appendEnchantment(@NotNull EnchantConflictGroup conflict, @Nullable CAEnchantment enchantment){ - if(enchantment == null) - return false; - conflict.addEnchantment(enchantment); - return true; - } - - /** - * Extract group abstract material group. - * - * @param builder The builder source - * @return The abstract material group from the builder. - */ - protected static AbstractMaterialGroup extractGroup(@NotNull ConflictBuilder builder){ - ItemGroupManager itemGroupManager = ConfigHolder.ITEM_GROUP_HOLDER.getItemGroupsManager(); - IncludeGroup group = new IncludeGroup(EnchantConflictManager.DEFAULT_GROUP_NAME); - - for (String groupName : builder.getExcludedGroupNames()) { - AbstractMaterialGroup materialGroup = itemGroupManager.get(groupName); - - if(materialGroup == null){ - CustomAnvil.instance.getLogger().warning("Material group " + groupName + " do not exist but is ask by conflict " + builder.getName()); - logConflictOrigin(builder); - continue; - } - - group.addToPolicy(materialGroup); - } - - return group; - } - /** * Write a conflict to the config file and plan an update of conflicts. *
@@ -135,7 +75,7 @@ public class ConflictAPI {
String name = builder.getName();
if(name.contains(".")) {
- CustomAnvil.instance.getLogger().warning("Conflict " + name +" contain . in its name but should not. this conflict is ignored.");
+ CustomAnvil.instance.getLogger().warning("Conflict " + name +" contain \".\" in its name but should not. this conflict is ignored.");
logConflictOrigin(builder);
return false;
}
@@ -170,8 +110,9 @@ public class ConflictAPI {
return result;
}
+
/**
- * Prepare a task to reload every conflict.
+ * Prepare a task to save conflict configuration.
*/
private static void prepareSaveTask() {
if(saveChangeTask != -1) return;
@@ -183,7 +124,7 @@ public class ConflictAPI {
}
/**
- * Prepare a task to save configuration.
+ * Prepare a task to reload every conflict.
*/
private static void prepareUpdateTask() {
if(reloadChangeTask != -1) return;
@@ -196,7 +137,7 @@ public class ConflictAPI {
}
- private static void logConflictOrigin(@NotNull ConflictBuilder builder){
+ static void logConflictOrigin(@NotNull ConflictBuilder builder){
CustomAnvil.instance.getLogger().warning("Conflict " + builder.getName() +" came from " + builder.getSourceName() + ".");
}
diff --git a/src/main/java/xyz/alexcrea/cuanvil/api/ConflictBuilder.java b/src/main/java/xyz/alexcrea/cuanvil/api/ConflictBuilder.java
index fa03b8c..2786dd9 100644
--- a/src/main/java/xyz/alexcrea/cuanvil/api/ConflictBuilder.java
+++ b/src/main/java/xyz/alexcrea/cuanvil/api/ConflictBuilder.java
@@ -1,11 +1,13 @@
package xyz.alexcrea.cuanvil.api;
+import io.delilaheve.CustomAnvil;
import org.bukkit.NamespacedKey;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
-import xyz.alexcrea.cuanvil.group.AbstractMaterialGroup;
+import xyz.alexcrea.cuanvil.group.*;
import java.util.HashSet;
import java.util.Set;
@@ -342,9 +344,20 @@ public class ConflictBuilder {
return clone;
}
+ /**
+ * Build a new Enchant conflict group by this builder.
+ * @return An Enchant conflict group with this builder parameters.
+ */
+ public EnchantConflictGroup build(){
+ AbstractMaterialGroup materials = extractGroups();
+ EnchantConflictGroup conflict = new EnchantConflictGroup(getName(), materials, getMaxBeforeConflict());
+ appendEnchantments(conflict);
+
+ return conflict;
+ }
/**
- * Register this conflict.
+ * Register this conflict if not yet registered.
* Equivalent to {@link ConflictAPI#addConflict(ConflictBuilder)}
* @return True if successful.
*/
@@ -352,4 +365,62 @@ public class ConflictBuilder {
return ConflictAPI.addConflict(this);
}
+ /**
+ * Append builders stored enchantments into conflict.
+ *
+ * @param conflict The conflict target
+ */
+ protected void appendEnchantments(@NotNull EnchantConflictGroup conflict){
+ for (String enchantmentName : getEnchantmentNames()){
+ if(appendEnchantment(conflict, EnchantmentApi.getByName(enchantmentName))){
+ CustomAnvil.instance.getLogger().warning("Could not find enchantment " + enchantmentName + " for conflict " + getName());
+ ConflictAPI.logConflictOrigin(this);
+ }
+ }
+ for (NamespacedKey enchantmentKey : getEnchantmentKeys()){
+ if(!appendEnchantment(conflict, EnchantmentApi.getByKey(enchantmentKey))){
+ CustomAnvil.instance.getLogger().warning("Could not find enchantment " + enchantmentKey + " for conflict " + getName());
+ ConflictAPI.logConflictOrigin(this);
+ }
+ }
+ }
+
+ /**
+ * Append an enchantment.
+ *
+ * @param conflict The conflict target
+ * @param enchantment The enchantment
+ * @return True if successful.
+ */
+ protected static boolean appendEnchantment(@NotNull EnchantConflictGroup conflict, @Nullable CAEnchantment enchantment){
+ if(enchantment == null)
+ return false;
+ conflict.addEnchantment(enchantment);
+ return true;
+ }
+
+ /**
+ * Extract group abstract material group.
+ *
+ * @return The abstract material group from the builder.
+ */
+ protected AbstractMaterialGroup extractGroups(){
+ ItemGroupManager itemGroupManager = ConfigHolder.ITEM_GROUP_HOLDER.getItemGroupsManager();
+ IncludeGroup group = new IncludeGroup(EnchantConflictManager.DEFAULT_GROUP_NAME);
+
+ for (String groupName : getExcludedGroupNames()) {
+ AbstractMaterialGroup materialGroup = itemGroupManager.get(groupName);
+
+ if(materialGroup == null){
+ CustomAnvil.instance.getLogger().warning("Material group " + groupName + " do not exist but is ask by conflict " + getName());
+ ConflictAPI.logConflictOrigin(this);
+ continue;
+ }
+
+ group.addToPolicy(materialGroup);
+ }
+
+ return group;
+ }
+
}
diff --git a/src/main/java/xyz/alexcrea/cuanvil/api/CustomAnvilRecipeApi.java b/src/main/java/xyz/alexcrea/cuanvil/api/CustomAnvilRecipeApi.java
new file mode 100644
index 0000000..01682e6
--- /dev/null
+++ b/src/main/java/xyz/alexcrea/cuanvil/api/CustomAnvilRecipeApi.java
@@ -0,0 +1,82 @@
+package xyz.alexcrea.cuanvil.api;
+
+import io.delilaheve.CustomAnvil;
+import org.bukkit.Bukkit;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.jetbrains.annotations.NotNull;
+import xyz.alexcrea.cuanvil.config.ConfigHolder;
+import xyz.alexcrea.cuanvil.gui.config.global.CustomRecipeConfigGui;
+import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe;
+
+import java.util.Collections;
+import java.util.List;
+
+@SuppressWarnings("unused")
+public class CustomAnvilRecipeApi {
+
+ private CustomAnvilRecipeApi(){}
+
+ private static int saveChangeTask = -1;
+
+ /**
+ * Write and add a custom anvil recipe.
+ * Will not write the recipe if it already exists.
+ *
+ * @param builder The recipe builder to be based on
+ * @return True if successful.
+ */
+ public static boolean addRecipe(@NotNull AnvilRecipeBuilder builder){
+ FileConfiguration config = ConfigHolder.CUSTOM_RECIPE_HOLDER.getConfig();
+ String name = builder.getName();
+
+ if(config.contains(builder.getName())) return false;
+ if(builder.getName().contains(".")) {
+ CustomAnvil.instance.getLogger().warning("Custom anvil recipe " + name + " contain \".\" in its name but should not. this recipe is ignored.");
+ return false;
+ }
+
+ AnvilCustomRecipe recipe = builder.build();
+ if(recipe == null){
+ CustomAnvil.instance.getLogger().warning("Custom anvil recipe " + name + " could not be parsed.");
+ if(builder.getLeftItem() == null){
+ CustomAnvil.instance.getLogger().warning("It look like left item of the recipe is null.");
+ }
+ if(builder.getResultItem() == null){
+ CustomAnvil.instance.getLogger().warning("It look like result item of the recipe is null.");
+ }
+ return false;
+ }
+
+ // Save to file
+ recipe.saveToFile(false, false);
+ prepareSaveTask();
+
+ // Update gui
+ CustomRecipeConfigGui.INSTANCE.updateValueForGeneric(recipe, true);
+
+ return true;
+ }
+
+ /**
+ * Prepare a task to save custom recipe configuration.
+ */
+ private static void prepareSaveTask() {
+ if(saveChangeTask != -1) return;
+
+ saveChangeTask = Bukkit.getScheduler().scheduleSyncDelayedTask(CustomAnvil.instance, ()->{
+ ConfigHolder.CONFLICT_HOLDER.saveToDisk(true);
+ saveChangeTask = -1;
+ }, 0L);
+ }
+
+ /**
+ * Get every registered recipes.
+ * @return An immutable collection of recipes.
+ */
+ @NotNull
+ public static List