Added custom anvil recipe api & builder.

Fixed Conflict not being registered.
Build conflict on the builder instance instead of the ConflictAPI class.
This commit is contained in:
alexcrea 2024-07-09 13:56:19 +02:00
parent bcd8b6ae6e
commit a40d2c6530
No known key found for this signature in database
GPG key ID: 43FD265DB0DBF91F
6 changed files with 386 additions and 82 deletions

View file

@ -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.
* <p>
* 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.
* <p>
* 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);
}
}

View file

@ -5,10 +5,8 @@ import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment; import xyz.alexcrea.cuanvil.group.EnchantConflictGroup;
import xyz.alexcrea.cuanvil.group.*;
import xyz.alexcrea.cuanvil.gui.config.global.EnchantConflictGui; import xyz.alexcrea.cuanvil.gui.config.global.EnchantConflictGui;
import java.util.Collections; import java.util.Collections;
@ -31,7 +29,7 @@ public class ConflictAPI {
* Write and add a conflict. * Write and add a conflict.
* Will not write the conflict if it already exists. * 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. * @return True if successful.
*/ */
public static boolean addConflict(@NotNull ConflictBuilder builder){ public static boolean addConflict(@NotNull ConflictBuilder builder){
@ -40,75 +38,17 @@ public class ConflictAPI {
if(!writeConflict(builder, false)) return false; if(!writeConflict(builder, false)) return false;
AbstractMaterialGroup materials = extractGroup(builder); EnchantConflictGroup conflict = builder.build();
EnchantConflictGroup conflict = new EnchantConflictGroup(builder.getName(), materials, builder.getMaxBeforeConflict());
appendEnchantments(builder, conflict);
// Register conflict
ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList().add(conflict);
// Add conflict to gui
EnchantConflictGui.INSTANCE.updateValueForGeneric(conflict, true); EnchantConflictGui.INSTANCE.updateValueForGeneric(conflict, true);
return 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. * Write a conflict to the config file and plan an update of conflicts.
* <p> * <p>
@ -135,7 +75,7 @@ public class ConflictAPI {
String name = builder.getName(); String name = builder.getName();
if(name.contains(".")) { 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); logConflictOrigin(builder);
return false; return false;
} }
@ -170,8 +110,9 @@ public class ConflictAPI {
return result; return result;
} }
/** /**
* Prepare a task to reload every conflict. * Prepare a task to save conflict configuration.
*/ */
private static void prepareSaveTask() { private static void prepareSaveTask() {
if(saveChangeTask != -1) return; 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() { private static void prepareUpdateTask() {
if(reloadChangeTask != -1) return; 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() + "."); CustomAnvil.instance.getLogger().warning("Conflict " + builder.getName() +" came from " + builder.getSourceName() + ".");
} }

View file

@ -1,11 +1,13 @@
package xyz.alexcrea.cuanvil.api; package xyz.alexcrea.cuanvil.api;
import io.delilaheve.CustomAnvil;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment; import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
import xyz.alexcrea.cuanvil.group.AbstractMaterialGroup; import xyz.alexcrea.cuanvil.group.*;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -342,9 +344,20 @@ public class ConflictBuilder {
return clone; 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)} * Equivalent to {@link ConflictAPI#addConflict(ConflictBuilder)}
* @return True if successful. * @return True if successful.
*/ */
@ -352,4 +365,62 @@ public class ConflictBuilder {
return ConflictAPI.addConflict(this); 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;
}
} }

View file

@ -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<AnvilCustomRecipe> getRegisteredRecipes(){
List<AnvilCustomRecipe> mutableList = ConfigHolder.CUSTOM_RECIPE_HOLDER.getRecipeManager().getRecipeList();
return Collections.unmodifiableList(mutableList);
}
}

View file

@ -170,7 +170,7 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin)
conflict.addEnchantment(enchantment1).addEnchantment(enchantment2) conflict.addEnchantment(enchantment1).addEnchantment(enchantment2)
conflict.setMaxBeforeConflict(1); conflict.setMaxBeforeConflict(1)
conflict.registerIfAbsent() conflict.registerIfAbsent()
} }

View file

@ -74,25 +74,30 @@ class AnvilCustomRecipe(
} }
fun saveToFile(){ fun saveToFile(writeFile: Boolean, doBackup: Boolean){
val fileConfig = ConfigHolder.CUSTOM_RECIPE_HOLDER.config val fileConfig = ConfigHolder.CUSTOM_RECIPE_HOLDER.config
fileConfig.set("$name.$EXACT_COUNT_CONFIG", exactCount) fileConfig["$name.$EXACT_COUNT_CONFIG"] = exactCount
//fileConfig.set("$name.$EXACT_LEFT_CONFIG", exactLeft) //fileConfig.set("$name.$EXACT_LEFT_CONFIG", exactLeft)
//fileConfig.set("$name.$EXACT_RIGHT_CONFIG", exactRight) //fileConfig.set("$name.$EXACT_RIGHT_CONFIG", exactRight)
fileConfig.set("$name.$XP_COST_CONFIG", xpCostPerCraft) fileConfig["$name.$XP_COST_CONFIG"] = xpCostPerCraft
fileConfig.set("$name.$LEFT_ITEM_CONFIG", leftItem) fileConfig["$name.$LEFT_ITEM_CONFIG"] = leftItem
fileConfig.set("$name.$RIGHT_ITEM_CONFIG", rightItem) fileConfig["$name.$RIGHT_ITEM_CONFIG"] = rightItem
fileConfig.set("$name.$RESULT_ITEM_CONFIG", resultItem) fileConfig["$name.$RESULT_ITEM_CONFIG"] = resultItem
if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) { if (writeFile) {
ConfigHolder.CUSTOM_RECIPE_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE) ConfigHolder.CUSTOM_RECIPE_HOLDER.saveToDisk(doBackup)
} }
} }
@Deprecated("Should use saveToFile(Boolean, Boolean) instead") //TODO determine when an where to save/do backup and remove use of variable like TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE
fun saveToFile(){
saveToFile(GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE, GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE)
}
fun updateFromFile(){ fun updateFromFile(){
this.exactCount = ConfigHolder.CUSTOM_RECIPE_HOLDER.config.getBoolean( this.exactCount = ConfigHolder.CUSTOM_RECIPE_HOLDER.config.getBoolean(
"$name.$EXACT_COUNT_CONFIG", "$name.$EXACT_COUNT_CONFIG",