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

View file

@ -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;
}
}

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);
}
}