Add an api (#14)

This allows developers of custom enchantment plugins to be compatible or
use functionality of Custom Anvil.
This commit is contained in:
alexcrea 2024-07-11 16:53:32 +02:00 committed by GitHub
commit de5fa240a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
40 changed files with 1885 additions and 327 deletions

View file

@ -1,6 +1,7 @@
plugins { plugins {
kotlin("jvm") version "1.9.24" kotlin("jvm") version "1.9.24"
java java
id("org.jetbrains.dokka").version("1.9.20")
id("com.github.johnrengelman.shadow").version("7.1.2") id("com.github.johnrengelman.shadow").version("7.1.2")
} }

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

@ -0,0 +1,170 @@
package xyz.alexcrea.cuanvil.api;
import io.delilaheve.CustomAnvil;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.group.EnchantConflictGroup;
import xyz.alexcrea.cuanvil.gui.config.global.EnchantConflictGui;
import java.util.*;
/**
* Custom Anvil api for conflict registry.
*/
@SuppressWarnings("unused")
public class ConflictAPI {
private ConflictAPI() {}
private static int saveChangeTask = -1;
private static int reloadChangeTask = -1;
/**
* Write and add a conflict.
* Will not write the conflict if it already exists.
*
* @param builder The conflict builder to be based on
* @return True if successful.
*/
public static boolean addConflict(@NotNull ConflictBuilder builder){
FileConfiguration config = ConfigHolder.CONFLICT_HOLDER.getConfig();
if(config.contains(builder.getName())) return false;
if(!writeConflict(builder, false)) return false;
EnchantConflictGroup conflict = builder.build();
// Register conflict
ConfigHolder.CONFLICT_HOLDER.getConflictManager().addConflict(conflict);
// Add conflict to gui
EnchantConflictGui.INSTANCE.updateValueForGeneric(conflict, true);
return true;
}
/**
* Write a conflict to the config file and plan an update of conflicts.
* <p>
* You may want to use {@link #addConflict(ConflictBuilder)} instead as it is more performance in most case as this function will reload every conflict.
*
* @param builder The builder
* @return True if successful.
*/
public static boolean writeConflict(@NotNull ConflictBuilder builder){
return writeConflict(builder, true);
}
/**
* Write a conflict to the config file.
* <p>
* You should use {@link #addConflict(ConflictBuilder)} or {@link #writeConflict(ConflictBuilder)} instead
*
* @param builder The builder
* @param updatePlanned If we should plan a global update for conflicts
* @return True if successful.
*/
public static boolean writeConflict(@NotNull ConflictBuilder builder, boolean updatePlanned){
FileConfiguration config = ConfigHolder.CONFLICT_HOLDER.getConfig();
String name = builder.getName();
if(name.contains(".")) {
CustomAnvil.instance.getLogger().warning("Conflict " + name +" contain \".\" in its name but should not. this conflict is ignored.");
logConflictOrigin(builder);
return false;
}
String basePath = name + ".";
List<String> enchantments = extractEnchantments(builder);
List<String> excludedGroups = new ArrayList<>(builder.getExcludedGroupNames());
if(!enchantments.isEmpty()) config.set(basePath + "enchantments", enchantments);
if(!excludedGroups.isEmpty()) config.set(basePath + "notAffectedGroups", excludedGroups);
if(builder.getMaxBeforeConflict() > 0) config.set(basePath + "maxEnchantmentBeforeConflict", builder.getMaxBeforeConflict());
prepareSaveTask();
if(updatePlanned) prepareUpdateTask();
return true;
}
/**
* Extract every enchantment names from a builder.
* @param builder The builder storing the enchantments
* @return Builder's stored enchantment.
*/
@NotNull
private static List<String> extractEnchantments(@NotNull ConflictBuilder builder){
List<String> result = new ArrayList<>(builder.getEnchantmentNames());
for (NamespacedKey enchantmentKey : builder.getEnchantmentKeys()) {
result.add(enchantmentKey.getKey());
}
return result;
}
/**
* Remove a conflict.
*
* @param conflict The conflict to remove
* @return True if successful.
*/
public static boolean removeConflict(@NotNull EnchantConflictGroup conflict){
// Remove from registry
ConfigHolder.CONFLICT_HOLDER.getConflictManager().removeConflict(conflict);
// Write as null and save to file
ConfigHolder.CONFLICT_HOLDER.getConfig().set(conflict.getName(), null);
prepareSaveTask();
// Remove from gui
EnchantConflictGui.INSTANCE.removeGeneric(conflict);
return true;
}
/**
* Prepare a task to save conflict configuration.
*/
private static void prepareSaveTask() {
if(saveChangeTask != -1) return;
saveChangeTask = Bukkit.getScheduler().scheduleSyncDelayedTask(CustomAnvil.instance, ()->{
ConfigHolder.CONFLICT_HOLDER.saveToDisk(true);
saveChangeTask = -1;
}, 0L);
}
/**
* Prepare a task to reload every conflict.
*/
private static void prepareUpdateTask() {
if(reloadChangeTask != -1) return;
reloadChangeTask = Bukkit.getScheduler().scheduleSyncDelayedTask(CustomAnvil.instance, ()->{
ConfigHolder.CONFLICT_HOLDER.reload();
EnchantConflictGui.INSTANCE.reloadValues();
reloadChangeTask = -1;
}, 0L);
}
static void logConflictOrigin(@NotNull ConflictBuilder builder){
CustomAnvil.instance.getLogger().warning("Conflict " + builder.getName() +" came from " + builder.getSourceName() + ".");
}
/**
* Get every registered conflict.
* @return An immutable collection of conflict.
*/
@NotNull
public static List<EnchantConflictGroup> getRegisteredConflict(){
List<EnchantConflictGroup> mutableList = ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList();
return Collections.unmodifiableList(mutableList);
}
}

View file

@ -0,0 +1,426 @@
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.*;
import java.util.HashSet;
import java.util.Set;
/**
* A Builder for material conflict.
*/
@SuppressWarnings("unused")
public class ConflictBuilder {
private final @Nullable Plugin source;
private @NotNull String name;
private final @NotNull Set<String> enchantmentNames;
private final @NotNull Set<NamespacedKey> enchantmentKeys;
private final @NotNull Set<String> excludedGroupNames;
private int maxBeforeConflict;
/**
* Instantiates a new Conflict builder.
*
* @param name The conflict name
* @param maxBeforeConflict Maximum number of conflicting enchantment before conflict is active
* @param source The conflict source
*/
public ConflictBuilder(@NotNull String name, int maxBeforeConflict, @Nullable Plugin source){
this.source = source;
this.name = name;
this.enchantmentNames = new HashSet<>();
this.enchantmentKeys = new HashSet<>();
this.excludedGroupNames = new HashSet<>();
this.maxBeforeConflict = maxBeforeConflict;
}
/**
* Instantiates a new Conflict builder.
*
* @param name The conflict name
* @param source The conflict source
*/
public ConflictBuilder(@NotNull String name, @Nullable Plugin source){
this(name, 0, source);
}
/**
* Instantiates a new Conflict builder.
*
* @param name The conflict name
*/
public ConflictBuilder(@NotNull String name){
this(name, null);
}
/**
* Gets conflict source.
*
* @return The conflict source.
*/
@Nullable
public Plugin getSource() {
return source;
}
/**
* Gets conflict source name.
*
* @return The conflict source name.
*/
@NotNull
public String getSourceName() {
if(source == null) return "an unknown source";
return source.getName();
}
/**
* Gets conflict name.
*
* @return The conflict name.
*/
@NotNull
public String getName() {
return name;
}
/**
* Gets stored conflicting enchantment names.
*
* @return The stored enchantment names.
*/
@NotNull
public Set<String> getEnchantmentNames() {
return enchantmentNames;
}
/**
* Gets stored conflicting enchantment keys.
*
* @return The stored enchantment keys.
*/
@NotNull
public Set<NamespacedKey> getEnchantmentKeys() {
return enchantmentKeys;
}
/**
* Gets stored excluded group names.
*
* @return The stored group names.
*/
@NotNull
public Set<String> getExcludedGroupNames() {
return excludedGroupNames;
}
/**
* Gets maximum number of conflicting enchantment before conflict is active.
* <p>
* This value represent how many enchantment contained on this conflict can be applied to before conflict is considered active.
* That mean new enchantment will not be able to be added to the item and present enchantment will not have its level upgraded.
* <p>
* In vanilla. material restriction have this value set to 0 and enchantment conflict set to 1.
*
* @return the max number of conflicting enchantment before conflict. 0 by default.
*/
public int getMaxBeforeConflict() {
return maxBeforeConflict;
}
/**
* Sets conflict name.
*
* @param name The name
* @return This conflict builder instance.
*/
public ConflictBuilder setName(String name) {
this.name = name;
return this;
}
/**
* Sets maximum number of conflicting enchantment before conflict is active.
* <p>
* This value represent how many enchantment contained on this conflict can be applied to before conflict is considered active.
* That mean new enchantment will not be able to be added to the item and present enchantment will not have its level upgraded.
* <p>
* In vanilla. material restriction have this value set to 0 and enchantment conflict set to 1.
*
* @param maxBeforeConflict The max before conflict
* @return This conflict builder instance.
*/
public ConflictBuilder setMaxBeforeConflict(int maxBeforeConflict) {
this.maxBeforeConflict = maxBeforeConflict;
return this;
}
/**
* Add a conflicting enchantment by name.
*
* @param enchantmentName The enchantment name
* @return This conflict builder instance.
*/
@NotNull
public ConflictBuilder addEnchantment(@NotNull String enchantmentName){
enchantmentNames.add(enchantmentName);
return this;
}
/**
* Add a conflicting enchantment by key.
*
* @param enchantmentKey The enchantment key
* @return This conflict builder instance.
*/
@NotNull
public ConflictBuilder addEnchantment(@NotNull NamespacedKey enchantmentKey){
enchantmentKeys.add(enchantmentKey);
return this;
}
/**
* Add a conflicting enchantment by instance.
*
* @param enchantment The enchantment
* @return This conflict builder instance.
*/
@NotNull
public ConflictBuilder addEnchantment(@NotNull CAEnchantment enchantment){
addEnchantment(enchantment.getKey());
return this;
}
/**
* Remove conflicting enchantment by name.
*
* @param enchantmentName The enchantment name
* @return This conflict builder instance.
*/
@NotNull
public ConflictBuilder removeEnchantment(@NotNull String enchantmentName){
enchantmentNames.remove(enchantmentName);
return this;
}
/**
* Remove conflicting enchantment by key.
*
* @param enchantmentKey The enchantment key
* @return This conflict builder instance.
*/
@NotNull
public ConflictBuilder removeEnchantment(@NotNull NamespacedKey enchantmentKey){
enchantmentKeys.remove(enchantmentKey);
return removeEnchantment(enchantmentKey.getKey());
}
/**
* Remove enchantment by instance.
*
* @param enchantment The enchantment
* @return This conflict builder instance.
*/
@NotNull
public ConflictBuilder removeEnchantment(@NotNull CAEnchantment enchantment){
return removeEnchantment(enchantment.getKey());
}
/**
* Add an excluded group by name.
* <p>
* If left item of an anvil craft is included on one of the excluded group it will ignore this conflict.
* <p>
* This allows to create conflict only for some item. Material restriction can be written like that.
* <p>
* For example: If we exclude a material group containing every pickaxe and add efficiency enchantment
* with {@link #setMaxBeforeConflict(int) maxBeforeConflict} set to 0.
* Then only pickaxe will be able to have efficiency.
*
* @param groupName The group name
* @return This conflict builder instance.
*/
@NotNull
public ConflictBuilder addExcludedGroup(@NotNull String groupName){
excludedGroupNames.add(groupName);
return this;
}
/**
* Add an excluded group by instance.
* <p>
* If left item of an anvil craft is included on one of the excluded group it will ignore this conflict.
* <p>
* This allows to create conflict only for some item. Material restriction can be written like that.
* <p>
* For example: If we exclude a material group containing every pickaxe and add efficiency enchantment
* with {@link #setMaxBeforeConflict(int) maxBeforeConflict} set to 0.
* Then only pickaxe will be able to have efficiency.
*
* @param group The group
* @return this conflict builder instance.
*/
@NotNull
public ConflictBuilder addExcludedGroup(@NotNull AbstractMaterialGroup group){
return addExcludedGroup(group.getName());
}
/**
* Remove an excluded group by name.
* <p>
* If left item of an anvil craft is included on one of the excluded group it will ignore this conflict.
* <p>
* This allows to create conflict only for some item. Material restriction can be written like that.
* <p>
* For example: If we exclude a material group containing every pickaxe and add efficiency enchantment
* with {@link #setMaxBeforeConflict(int) maxBeforeConflict} set to 0.
* Then only pickaxe will be able to have efficiency.
*
* @param groupName The group name
* @return This conflict builder instance.
*/
@NotNull
public ConflictBuilder removeExcludedGroup(@NotNull String groupName){
excludedGroupNames.remove(groupName);
return this;
}
/**
* Remove an excluded group by instance.
* <p>
* If left item of an anvil craft is included on one of the excluded group it will ignore this conflict.
* <p>
* This allows to create conflict only for some item. Material restriction can be written like that.
* <p>
* For example: If we exclude a material group containing every pickaxe and add efficiency enchantment
* with {@link #setMaxBeforeConflict(int) maxBeforeConflict} set to 0.
* Then only pickaxe will be able to have efficiency.
*
* @param group The group
* @return This conflict builder instance.
*/
@NotNull
public ConflictBuilder removeExcludedGroup(@NotNull AbstractMaterialGroup group){
return removeExcludedGroup(group.getName());
}
/**
* Copy this conflict builder.
*
* @return A copy of this conflict builder.
*/
@NotNull
public ConflictBuilder copy() {
ConflictBuilder copy = new ConflictBuilder(this.name, this.source);
setMaxBeforeConflict(this.maxBeforeConflict);
// Set Enchantments
for (NamespacedKey key : this.enchantmentKeys) {
copy.addEnchantment(key);
}
for (String enchantName : this.enchantmentNames) {
copy.addEnchantment(enchantName);
}
// Set Groups
for (String groupName : this.excludedGroupNames) {
copy.addExcludedGroup(groupName);
}
return copy;
}
/**
* 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 if not yet registered.
* Equivalent to {@link ConflictAPI#addConflict(ConflictBuilder)}
* @return True if successful.
*/
public boolean registerIfAbsent(){
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,108 @@
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;
/**
* Custom Anvil api for custom anvil recipes.
*/
@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;
}
// Add to registry
ConfigHolder.CUSTOM_RECIPE_HOLDER.getRecipeManager().cleanAddNew(recipe);
// Save to file
recipe.saveToFile(false, false);
prepareSaveTask();
// Add from gui
CustomRecipeConfigGui.INSTANCE.updateValueForGeneric(recipe, true);
return true;
}
/**
* Remove a custom anvil recipe.
*
* @param recipe The recipe to remove
* @return True if successful.
*/
public static boolean removeRecipe(@NotNull AnvilCustomRecipe recipe){
// Remove from registry
ConfigHolder.CUSTOM_RECIPE_HOLDER.getRecipeManager().cleanRemove(recipe);
// Write as null and save to file
ConfigHolder.CUSTOM_RECIPE_HOLDER.getConfig().set(recipe.getName(), null);
prepareSaveTask();
// Remove from gui
CustomRecipeConfigGui.INSTANCE.removeGeneric(recipe);
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

@ -0,0 +1,207 @@
package xyz.alexcrea.cuanvil.api;
import io.delilaheve.CustomAnvil;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.enchantments.Enchantment;
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.enchant.CAEnchantmentRegistry;
import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity;
import xyz.alexcrea.cuanvil.enchant.bulk.BulkCleanEnchantOperation;
import xyz.alexcrea.cuanvil.enchant.bulk.BulkGetEnchantOperation;
import xyz.alexcrea.cuanvil.enchant.wrapped.CAVanillaEnchantment;
import xyz.alexcrea.cuanvil.gui.config.global.EnchantCostConfigGui;
import xyz.alexcrea.cuanvil.gui.config.global.EnchantLimitConfigGui;
import java.util.Collections;
import java.util.Map;
/**
* Custom Anvil api for enchantment registry.
*/
@SuppressWarnings("unused")
public class EnchantmentApi {
private static int saveChangeTask = -1;
private EnchantmentApi() {}
/**
* Register an enchantment.
*
* @param enchantment The enchantment to register
* @return True if successful.
*/
public static boolean registerEnchantment(@NotNull CAEnchantment enchantment){
if(!CAEnchantmentRegistry.getInstance().register(enchantment)) return false;
// Add enchantment to gui.
if(EnchantCostConfigGui.getInstance() != null){
EnchantCostConfigGui.getInstance().updateValueForGeneric(enchantment, true);
}
if(EnchantLimitConfigGui.getInstance() != null){
EnchantLimitConfigGui.getInstance().updateValueForGeneric(enchantment, true);
}
// Write default if do not exist
writeDefaultConfig(enchantment, false);
return true;
}
/**
* Register an enchantment by minecraft registered enchantment instance.
*
* @param enchantment The enchantment to register
* @param defaultRarity The default rarity of the provided enchantment
* @return True if successful.
*/
public static boolean registerEnchantment(@NotNull Enchantment enchantment, @Nullable EnchantmentRarity defaultRarity){
if(defaultRarity == null)
return registerEnchantment(new CAVanillaEnchantment(enchantment));
return registerEnchantment(new CAVanillaEnchantment(enchantment, defaultRarity));
}
/**
* Register an enchantment by minecraft registered enchantment instance.
* <p>
* Please note that this function assume the provided enchantment is registered into minecraft registry.
*
* @param enchantment The enchantment to register
* @return True if successful.
*/
public static boolean registerEnchantment(@NotNull Enchantment enchantment){
return registerEnchantment(new CAVanillaEnchantment(enchantment));
}
/**
* Unregister an enchantment.
*
* @param enchantment The enchantment to unregister
* @return True if successful.
*/
public static boolean unregisterEnchantment(@Nullable CAEnchantment enchantment){
// Remove from gui
if(EnchantCostConfigGui.getInstance() != null){
EnchantCostConfigGui.getInstance().removeGeneric(enchantment);
}
if(EnchantLimitConfigGui.getInstance() != null){
EnchantLimitConfigGui.getInstance().removeGeneric(enchantment);
}
return CAEnchantmentRegistry.getInstance().unregister(enchantment);
}
/**
* Unregister an enchantment by its key.
*
* @param key The enchantment key to unregister
* @return True if successful.
*/
public static boolean unregisterEnchantment(@NotNull NamespacedKey key){
CAEnchantment enchantment = CAEnchantmentRegistry.getInstance().getByKey(key);
return unregisterEnchantment(enchantment);
}
/**
* Unregister an enchantment by his bukkit enchantment.
*
* @param enchantment The enchantment to unregister
* @return True if successful.
*/
public static boolean unregisterEnchantment(@NotNull Enchantment enchantment){
return unregisterEnchantment(enchantment.getKey());
}
/**
* Get by key an enchantment.
*
* @param key The key used to fetch
* @return The custom anvil enchantment of this key. null if not found.
*/
@Nullable
public static CAEnchantment getByKey(@NotNull NamespacedKey key){
return CAEnchantmentRegistry.getInstance().getByKey(key);
}
/**
* Get by name an enchantment.
*
* @param name The name used to fetch
* @return The custom anvil enchantment of this name. null if not found.
*/
@Nullable
public static CAEnchantment getByName(@NotNull String name){
return CAEnchantmentRegistry.getInstance().getByName(name);
}
/**
* Get every registered custom anvil enchantments.
* @return An immutable map of enchantment key as map key and custom anvil enchantment as value.
*/
@NotNull
public static Map<NamespacedKey, CAEnchantment> getRegisteredEnchantments(){
return Collections.unmodifiableMap(CAEnchantmentRegistry.getInstance().registeredEnchantments());
}
/**
* Write the default level and rarity configuration of the enchantment.
* @param enchantment The enchantment to write default configuration
* @param override If it should override old configuration
* @return Return false if override is false and a configuration exist. true otherwise.
*/
public static boolean writeDefaultConfig(CAEnchantment enchantment, boolean override){
FileConfiguration config = ConfigHolder.DEFAULT_CONFIG.getConfig();
if(!override && config.contains(enchantment.getName())) return false;
writeDefaultConfig(config, enchantment);
prepareSaveTask();
return true;
}
private static void writeDefaultConfig(FileConfiguration defaultConfig, CAEnchantment enchantment) {
defaultConfig.set("enchant_limits." + enchantment.getKey().getKey(), enchantment.defaultMaxLevel());
String basePath = "enchant_values." + enchantment.getKey().getKey();
EnchantmentRarity rarity = enchantment.defaultRarity();
defaultConfig.set(basePath + ".item", rarity.getItemValue());
defaultConfig.set(basePath + ".book", rarity.getBookValue());
}
/**
* Prepare a task to save custom recipe configuration.
*/
private static void prepareSaveTask() {
if(saveChangeTask != -1) return;
saveChangeTask = Bukkit.getScheduler().scheduleSyncDelayedTask(CustomAnvil.instance, ()->{
ConfigHolder.DEFAULT_CONFIG.saveToDisk(true);
saveChangeTask = -1;
}, 0L);
}
/**
* Add a bulk get operator.
* @param operation An optimised get enchantments operation
*/
public static void addBulkGet(@NotNull BulkGetEnchantOperation operation){
CAEnchantmentRegistry.getInstance().getOptimisedGetOperators().add(operation);
}
/**
* Add a bulk clean operator.
* @param operation An optimised clean enchantments operation
*/
public static void addBulkClean(@NotNull BulkCleanEnchantOperation operation){
CAEnchantmentRegistry.getInstance().getOptimisedCleanOperators().add(operation);
}
}

View file

@ -0,0 +1,205 @@
package xyz.alexcrea.cuanvil.api;
import io.delilaheve.CustomAnvil;
import io.delilaheve.util.ConfigOptions;
import org.bukkit.Bukkit;
import org.bukkit.Material;
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.group.AbstractMaterialGroup;
import xyz.alexcrea.cuanvil.group.ExcludeGroup;
import xyz.alexcrea.cuanvil.group.IncludeGroup;
import xyz.alexcrea.cuanvil.group.ItemGroupManager;
import xyz.alexcrea.cuanvil.gui.config.global.GroupConfigGui;
import java.util.*;
/**
* Custom Anvil api for material group registry.
*/
@SuppressWarnings("unused")
public class MaterialGroupApi {
private MaterialGroupApi(){}
private static int saveChangeTask = -1;
private static int reloadChangeTask = -1;
/**
* Write and add a group.
* Will not write the group if it already exists.
*
* @param group the group to add
* @return true if successful.
*/
public static boolean addMaterialGroup(@NotNull AbstractMaterialGroup group){
ItemGroupManager itemGroupManager = ConfigHolder.ITEM_GROUP_HOLDER.getItemGroupsManager();
if(itemGroupManager.get(group.getName()) != null) return false;
itemGroupManager.getGroupMap().put(group.getName(), group);
if(!writeMaterialGroup(group, false)) return false;
if(group instanceof IncludeGroup includeGroup){
GroupConfigGui.INSTANCE.updateValueForGeneric(includeGroup, true);
}
if(ConfigOptions.INSTANCE.getVerboseDebugLog()){
CustomAnvil.instance.getLogger().info("Registered group " + group.getName());
}
return true;
}
/**
* Write a material group to the config file and plan an update of groups.
* <p>
* You may want to use {@link #addMaterialGroup(AbstractMaterialGroup)} instead as it is more performance in most case as this function will reload every conflict.
*
* @param group the group to write
* @return true if successful.
*/
public static boolean writeMaterialGroup(@NotNull AbstractMaterialGroup group){
return writeMaterialGroup(group, true);
}
/**
* Write a material group to the config file.
* <p>
* You should use {@link #addMaterialGroup(AbstractMaterialGroup)} or {@link #writeMaterialGroup(AbstractMaterialGroup)} instead
*
* @param group the group to write
* @param updatePlanned if we should plan a global update for material groups
* @return true if successful.
*/
public static boolean writeMaterialGroup(@NotNull AbstractMaterialGroup group, boolean updatePlanned){
String name = group.getName();
if(name.contains(".")) {
CustomAnvil.instance.getLogger().warning("Group " + name +" contain . in its name but should not. this material group is ignored.");
return false;
}
if(group instanceof IncludeGroup includeGroup){
writeKnownGroup("include", includeGroup);
}else if(group instanceof ExcludeGroup excludeGroup){
writeKnownGroup("exclude", excludeGroup);
}else{
writeUnknownGroup(group);
}
prepareSaveTask();
if(updatePlanned) prepareUpdateTask();
return true;
}
private static void writeKnownGroup(@NotNull String groupType, @NotNull AbstractMaterialGroup group){
FileConfiguration config = ConfigHolder.ITEM_GROUP_HOLDER.getConfig();
String basePath = group.getName() + ".";
Set<Material> materialSet = group.getNonGroupInheritedMaterials();
Set<AbstractMaterialGroup> groupSet = group.getGroups();
config.set(basePath + ItemGroupManager.GROUP_TYPE_PATH, groupType);
if(!materialSet.isEmpty()){
config.set(basePath + ItemGroupManager.MATERIAL_LIST_PATH, materialSetToStringList(materialSet));
}
if(!groupSet.isEmpty()){
config.set(basePath + ItemGroupManager.GROUP_LIST_PATH, materialGroupSEtToStringList(groupSet));
}
}
private static void writeUnknownGroup(@NotNull AbstractMaterialGroup group) {
FileConfiguration config = ConfigHolder.ITEM_GROUP_HOLDER.getConfig();
String basePath = group.getName() + ".";
EnumSet<Material> materials = group.getMaterials();
config.set(basePath + ItemGroupManager.GROUP_TYPE_PATH, "include");
if(!materials.isEmpty()){
config.set(basePath + ItemGroupManager.MATERIAL_LIST_PATH, materialSetToStringList(materials));
}
}
public static List<String> materialSetToStringList(@NotNull Set<Material> materials){
return materials.stream().map(material -> material.getKey().getKey().toLowerCase()).toList();
}
public static List<String> materialGroupSEtToStringList(@NotNull Set<AbstractMaterialGroup> groups){
return groups.stream().map(AbstractMaterialGroup::getName).toList();
}
/**
* Remove a material group.
* Caution ! It will not be removed from depending conflict or other material group at runtime.
* For that reason, it is not recommended to use this function.
*
* @param group The recipe to remove
* @return True if successful.
*/
public static boolean removeGroup(@NotNull AbstractMaterialGroup group){
// Remove from registry
ConfigHolder.ITEM_GROUP_HOLDER.getItemGroupsManager().groupMap.remove(group.getName());
// Write as null and save to file
ConfigHolder.ITEM_GROUP_HOLDER.getConfig().set(group.getName(), null);
prepareSaveTask();
// Remove from gui
if(group instanceof IncludeGroup includeGroup){
GroupConfigGui.INSTANCE.removeGeneric(includeGroup);
}
return true;
}
/**
* Prepare a task to reload every conflict.
*/
private static void prepareSaveTask() {
if(saveChangeTask != -1) return;
saveChangeTask = Bukkit.getScheduler().scheduleSyncDelayedTask(CustomAnvil.instance, ()->{
ConfigHolder.ITEM_GROUP_HOLDER.saveToDisk(true);
saveChangeTask = -1;
}, 0L);
}
/**
* Prepare a task to save configuration.
*/
private static void prepareUpdateTask() {
if(reloadChangeTask != -1) return;
reloadChangeTask = Bukkit.getScheduler().scheduleSyncDelayedTask(CustomAnvil.instance, ()->{
ConfigHolder.ITEM_GROUP_HOLDER.reload();
GroupConfigGui.INSTANCE.reloadValues();
reloadChangeTask = -1;
}, 0L);
}
/**
* Get by name a group.
*
* @param groupName the group name used to fetch
* @return the abstract group of this name. null if not found.
*/
@Nullable
public static AbstractMaterialGroup getGroup(@NotNull String groupName){
return ConfigHolder.ITEM_GROUP_HOLDER.getItemGroupsManager().get(groupName);
}
/**
* Get every registered material groups.
* @return An immutable map of group name as its key and group as mapped value.
*/
@NotNull
public static Map<String, AbstractMaterialGroup> getRegisteredGroups(){
return Collections.unmodifiableMap(ConfigHolder.ITEM_GROUP_HOLDER.getItemGroupsManager().getGroupMap());
}
}

View file

@ -0,0 +1,19 @@
package xyz.alexcrea.cuanvil.api.event;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class CAConfigReadyEvent extends Event {
private static final HandlerList HANDLERS = new HandlerList();
public static HandlerList getHandlerList() {
return HANDLERS;
}
@Override
public HandlerList getHandlers() {
return HANDLERS;
}
}

View file

@ -0,0 +1,18 @@
package xyz.alexcrea.cuanvil.api.event;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class CAEnchantRegistryReadyEvent extends Event {
private static final HandlerList HANDLERS = new HandlerList();
public static HandlerList getHandlerList() {
return HANDLERS;
}
@Override
public HandlerList getHandlers() {
return HANDLERS;
}
}

View file

@ -20,21 +20,38 @@ public abstract class ConfigHolder {
public static UnitRepairHolder UNIT_REPAIR_HOLDER; public static UnitRepairHolder UNIT_REPAIR_HOLDER;
public static CustomAnvilCraftHolder CUSTOM_RECIPE_HOLDER; public static CustomAnvilCraftHolder CUSTOM_RECIPE_HOLDER;
public static boolean loadConfig() { /**
* Load default configuration.
* @return True if successful.
*/
public static boolean loadDefaultConfig() {
DEFAULT_CONFIG = new DefaultConfigHolder(); DEFAULT_CONFIG = new DefaultConfigHolder();
return DEFAULT_CONFIG.reloadFromDisk(true);
}
/**
* Load non default configuration.
* @return True if successful.
*/
public static boolean loadNonDefaultConfig() {
ITEM_GROUP_HOLDER = new ItemGroupConfigHolder(); ITEM_GROUP_HOLDER = new ItemGroupConfigHolder();
CONFLICT_HOLDER = new ConflictConfigHolder(); CONFLICT_HOLDER = new ConflictConfigHolder();
UNIT_REPAIR_HOLDER = new UnitRepairHolder(); UNIT_REPAIR_HOLDER = new UnitRepairHolder();
CUSTOM_RECIPE_HOLDER = new CustomAnvilCraftHolder(); CUSTOM_RECIPE_HOLDER = new CustomAnvilCraftHolder();
return reloadAllFromDisk(true); return removeNonDefaultFromDisk(true);
} }
public static boolean reloadAllFromDisk(boolean hardfail) { public static boolean reloadAllFromDisk(boolean hardfail) {
boolean sucess = DEFAULT_CONFIG.reloadFromDisk(hardfail); boolean sucess = DEFAULT_CONFIG.reloadFromDisk(hardfail);
if (!sucess) return false; if (!sucess) return false;
sucess = ITEM_GROUP_HOLDER.reloadFromDisk(hardfail);
return removeNonDefaultFromDisk(hardfail);
}
private static boolean removeNonDefaultFromDisk(boolean hardfail){
boolean sucess = ITEM_GROUP_HOLDER.reloadFromDisk(hardfail);
if (!sucess) return false; if (!sucess) return false;
sucess = CONFLICT_HOLDER.reloadFromDisk(hardfail); sucess = CONFLICT_HOLDER.reloadFromDisk(hardfail);
if (!sucess) return false; if (!sucess) return false;
@ -192,7 +209,7 @@ public abstract class ConfigHolder {
// Class for itemGroupsManager config // Class for itemGroupsManager config
public static class ItemGroupConfigHolder extends ResourceConfigHolder { public static class ItemGroupConfigHolder extends ResourceConfigHolder {
private final static String FILE_NAME = "item_groups"; private static final String FILE_NAME = "item_groups";
ItemGroupManager itemGroupsManager; ItemGroupManager itemGroupsManager;
@ -219,7 +236,7 @@ public abstract class ConfigHolder {
// Class for enchant conflict config // Class for enchant conflict config
public static class ConflictConfigHolder extends ResourceConfigHolder { public static class ConflictConfigHolder extends ResourceConfigHolder {
private final static String FILE_NAME = "enchant_conflict"; private static final String FILE_NAME = "enchant_conflict";
EnchantConflictManager conflictManager; EnchantConflictManager conflictManager;
@ -243,7 +260,7 @@ public abstract class ConfigHolder {
// Class for unit repair config // Class for unit repair config
public static class UnitRepairHolder extends ResourceConfigHolder { public static class UnitRepairHolder extends ResourceConfigHolder {
private final static String ITEM_GROUP_FILE_NAME = "unit_repair_item"; private static final String ITEM_GROUP_FILE_NAME = "unit_repair_item";
private UnitRepairHolder() { private UnitRepairHolder() {
@ -259,7 +276,7 @@ public abstract class ConfigHolder {
// Class for custom anvil craft // Class for custom anvil craft
public static class CustomAnvilCraftHolder extends ResourceConfigHolder { public static class CustomAnvilCraftHolder extends ResourceConfigHolder {
private final static String CUSTOM_RECIPE_FILE_NAME = "custom_recipes"; private static final String CUSTOM_RECIPE_FILE_NAME = "custom_recipes";
CustomAnvilRecipeManager recipeManager; CustomAnvilRecipeManager recipeManager;
private CustomAnvilCraftHolder() { private CustomAnvilCraftHolder() {

View file

@ -1,28 +1,25 @@
package xyz.alexcrea.cuanvil.enchant; package xyz.alexcrea.cuanvil.enchant;
import io.delilaheve.util.ItemUtil;
import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.dependency.DependencyManager; import xyz.alexcrea.cuanvil.enchant.bulk.BulkCleanEnchantOperation;
import xyz.alexcrea.cuanvil.dependency.EnchantmentSquaredDependency; import xyz.alexcrea.cuanvil.enchant.bulk.BulkGetEnchantOperation;
import xyz.alexcrea.cuanvil.group.ConflictType;
import xyz.alexcrea.cuanvil.group.EnchantConflictGroup; import xyz.alexcrea.cuanvil.group.EnchantConflictGroup;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier;
/** /**
* Represent an enchantment compatible with Custom Anvil. * Represent an enchantment compatible with Custom Anvil.
* One issue with custom anvil is: it does not handle well duplicate key name (ignoring namespace) as the plugin was coded with vanilla enchantment in head * One issue with custom anvil is: it does not handle well duplicate key name (ignoring namespace)
* as the plugin was initially coded with vanilla enchantment in head
*/ */
@SuppressWarnings("unused")
public interface CAEnchantment { public interface CAEnchantment {
@ -54,10 +51,16 @@ public interface CAEnchantment {
int defaultMaxLevel(); int defaultMaxLevel();
/** /**
* Check if the enchantment have specialised group operation. * Check if the enchantment have specialised get bulk operation.
* @return If the enchantment is optimised for group operation. * @return If the enchantment is optimised for get bulk operation.
*/ */
boolean isOptimised(); boolean isGetOptimised();
/**
* Check if the enchantment have specialised clean bulk operation.
* @return If the enchantment is optimised for clean bulk operation.
*/
boolean isCleanOptimised();
/** /**
* Check if the player is allowed to use this enchantment. * Check if the player is allowed to use this enchantment.
@ -91,14 +94,20 @@ public interface CAEnchantment {
/** /**
* Get current level of the enchantment. * Get current level of the enchantment.
* @param item Item to search the level for. * @param item Item to search the level for. Should not get changed.
* @return Current leve of this enchantment on item. or 0 if absent.
*/ */
int getLevel(@NotNull ItemStack item); default int getLevel(@NotNull ItemStack item){
ItemMeta meta = item.getItemMeta();
if(meta == null) return 0;
return getLevel(item, meta);
}
/** /**
* Get current level of the enchantment. * Get current level of the enchantment.
* @param item Item to search the level for. * @param item Item to search the level for. Should not get changed.
* @param meta Meta of the provided item. It will not be changed and not be set on the item. * @param meta Meta of the provided item. Should not get changed.
* @return Current leve of this enchantment on item. or 0 if absent. * @return Current leve of this enchantment on item. or 0 if absent.
*/ */
int getLevel(@NotNull ItemStack item, @NotNull ItemMeta meta); int getLevel(@NotNull ItemStack item, @NotNull ItemMeta meta);
@ -137,29 +146,23 @@ public interface CAEnchantment {
* @param item Item to be cleared from enchantments. * @param item Item to be cleared from enchantments.
*/ */
static void clearEnchants(@NotNull ItemStack item){ static void clearEnchants(@NotNull ItemStack item){
// Optimised enchantment clean using item stack
for (BulkCleanEnchantOperation cleanOperator : CAEnchantmentRegistry.getInstance().getOptimisedCleanOperators()) {
cleanOperator.bulkClear(item);
}
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
if(meta == null) return; if(meta == null) return;
// Clean Vanilla enchants // Optimised enchantment clean using item meta
if (ItemUtil.INSTANCE.isEnchantedBook(item)) { for (BulkCleanEnchantOperation cleanOperator : CAEnchantmentRegistry.getInstance().getOptimisedCleanOperators()) {
EnchantmentStorageMeta bookMeta = (EnchantmentStorageMeta) meta; cleanOperator.bulkClear(item, meta);
bookMeta.getStoredEnchants().forEach(
(enchantment, leve) -> bookMeta.removeStoredEnchant(enchantment)
);
} else {
item.getEnchantments().forEach(
(enchantment, leve) -> item.removeEnchantment(enchantment)
);
} }
// Clean Enchant Squared enchants item.setItemMeta(meta);
EnchantmentSquaredDependency enchantmentSquared = DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility();
if(enchantmentSquared != null){
enchantmentSquared.clearEnchantments(item);
}
// Clean unoptimised enchants // Clean unoptimised enchants
for (CAEnchantment enchant : CAEnchantmentRegistry.getInstance().unoptimisedValues()) { for (CAEnchantment enchant : CAEnchantmentRegistry.getInstance().unoptimisedCleanValues()) {
if(enchant.isEnchantmentPresent(item)){ if(enchant.isEnchantmentPresent(item)){
enchant.removeFrom(item); enchant.removeFrom(item);
} }
@ -179,25 +182,13 @@ public interface CAEnchantment {
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
if(meta == null) return enchantments; if(meta == null) return enchantments;
// Vanilla optimised get // Optimised enchantment get
if (ItemUtil.INSTANCE.isEnchantedBook(item)) { for (BulkGetEnchantOperation getOperator : CAEnchantmentRegistry.getInstance().getOptimisedGetOperators()) {
((EnchantmentStorageMeta)meta).getStoredEnchants().forEach( getOperator.bulkGet(enchantments, item, meta);
(enchantment, level) -> enchantments.put(registry.getByKey(enchantment.getKey()), level)
);
} else {
item.getEnchantments().forEach(
(enchantment, level) -> enchantments.put(registry.getByKey(enchantment.getKey()), level)
);
}
// Enchants Squared get
EnchantmentSquaredDependency enchantmentSquared = DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility();
if(enchantmentSquared != null){
enchantmentSquared.getEnchantmentsSquared(item, enchantments);
} }
// Unoptimised enchantment get // Unoptimised enchantment get
findEnchantsFromSelectedList(item, meta, enchantments, registry.unoptimisedValues()); findEnchantsFromSelectedList(item, meta, enchantments, registry.unoptimisedGetValues());
return enchantments; return enchantments;
} }
@ -226,6 +217,8 @@ public interface CAEnchantment {
/** /**
* Gets an array of all the registered enchantments. * Gets an array of all the registered enchantments.
*
* @param key The enchantment key
* @return Array of enchantment. * @return Array of enchantment.
*/ */
static @Nullable CAEnchantment getByKey(@NotNull NamespacedKey key){ static @Nullable CAEnchantment getByKey(@NotNull NamespacedKey key){
@ -234,6 +227,7 @@ public interface CAEnchantment {
/** /**
* Gets a list of all the unoptimised enchantments. * Gets a list of all the unoptimised enchantments.
* @param name The enchantment name
* @return List of enchantment. * @return List of enchantment.
*/ */
static @Nullable CAEnchantment getByName(@NotNull String name){ static @Nullable CAEnchantment getByName(@NotNull String name){

View file

@ -1,21 +1,22 @@
package xyz.alexcrea.cuanvil.enchant; package xyz.alexcrea.cuanvil.enchant;
import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.group.ConflictType;
import xyz.alexcrea.cuanvil.group.EnchantConflictGroup; import xyz.alexcrea.cuanvil.group.EnchantConflictGroup;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Supplier;
/**
* Default implementation of an enchantment compatible with Custom Anvil.
* One issue with custom anvil is: it does not handle well duplicate key name (ignoring namespace)
* as the plugin was initially coded with vanilla enchantment in head
*/
public abstract class CAEnchantmentBase implements CAEnchantment { public abstract class CAEnchantmentBase implements CAEnchantment {
@NotNull @NotNull
@ -71,7 +72,12 @@ public abstract class CAEnchantmentBase implements CAEnchantment {
} }
@Override @Override
public boolean isOptimised(){ public boolean isGetOptimised(){
return false;
}
@Override
public boolean isCleanOptimised(){
return false; return false;
} }
@ -80,12 +86,6 @@ public abstract class CAEnchantmentBase implements CAEnchantment {
return true; return true;
} }
public int getLevel(@NotNull ItemStack item){
ItemMeta meta = item.getItemMeta();
if(meta == null) return 0;
return getLevel(item, meta);
}
public boolean isEnchantmentPresent(@NotNull ItemStack item){ public boolean isEnchantmentPresent(@NotNull ItemStack item){
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
if(meta == null) return false; if(meta == null) return false;

View file

@ -5,13 +5,12 @@ import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.dependency.DependencyManager; import xyz.alexcrea.cuanvil.enchant.bulk.BukkitEnchantBulkOperation;
import xyz.alexcrea.cuanvil.enchant.bulk.BulkCleanEnchantOperation;
import xyz.alexcrea.cuanvil.enchant.bulk.BulkGetEnchantOperation;
import xyz.alexcrea.cuanvil.enchant.wrapped.CAVanillaEnchantment; import xyz.alexcrea.cuanvil.enchant.wrapped.CAVanillaEnchantment;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
public class CAEnchantmentRegistry { public class CAEnchantmentRegistry {
@ -24,29 +23,38 @@ public class CAEnchantmentRegistry {
// Register enchantment functions // Register enchantment functions
private final HashMap<NamespacedKey, CAEnchantment> byKeyMap; private final HashMap<NamespacedKey, CAEnchantment> byKeyMap;
private final HashMap<String, CAEnchantment> byNameMap; private final HashMap<String, CAEnchantment> byNameMap;
private final List<CAEnchantment> unoptimisedValues;
private final List<CAEnchantment> unoptimisedGetValues;
private final List<CAEnchantment> unoptimisedCleanValues;
private final List<BulkGetEnchantOperation> optimisedGetOperators;
private final List<BulkCleanEnchantOperation> optimisedCleanOperators;
private CAEnchantmentRegistry() { private CAEnchantmentRegistry() {
byKeyMap = new HashMap<>(); byKeyMap = new HashMap<>();
byNameMap = new HashMap<>(); byNameMap = new HashMap<>();
unoptimisedValues = new ArrayList<>();
unoptimisedGetValues = new ArrayList<>();
unoptimisedCleanValues = new ArrayList<>();
optimisedGetOperators = new ArrayList<>();
optimisedCleanOperators = new ArrayList<>();
} }
/** /**
* This should only be called on main of custom anvil. * This should only be called on main of custom anvil.
* If called more than one time, chance of thing being broken will be high. * If called more than one time, chance of thing being broken will be high.
*/ */
public void registerStartupEnchantments(){ public void registerBukkit(){
// Register enchantment
for (Enchantment enchantment : Enchantment.values()) { for (Enchantment enchantment : Enchantment.values()) {
register(new CAVanillaEnchantment(enchantment)); register(new CAVanillaEnchantment(enchantment));
} }
if(DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility() != null){ // Add bukkit enchantment bulk operation
DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility().registerEnchantments(); BukkitEnchantBulkOperation bukkitOperation = new BukkitEnchantBulkOperation();
} optimisedGetOperators.add(bukkitOperation);
if(DependencyManager.INSTANCE.getEcoEnchantCompatibility() != null){ optimisedCleanOperators.add(bukkitOperation);
DependencyManager.INSTANCE.getEcoEnchantCompatibility().registerEnchantments();
}
} }
@ -56,13 +64,14 @@ public class CAEnchantmentRegistry {
* No guarantee that the enchantment will be present on the config gui if registered late. * No guarantee that the enchantment will be present on the config gui if registered late.
* (By late I mean after custom anvil startup.) * (By late I mean after custom anvil startup.)
* @param enchantment The enchantment to be registered. * @param enchantment The enchantment to be registered.
* @return If the operation was successful.
*/ */
public void register(@NotNull CAEnchantment enchantment){ public boolean register(@NotNull CAEnchantment enchantment){
if(byKeyMap.containsKey(enchantment.getKey())){ if(byKeyMap.containsKey(enchantment.getKey())){
CustomAnvil.instance.getLogger().log(Level.WARNING, CustomAnvil.instance.getLogger().log(Level.WARNING,
"Duplicate registered enchantment. This should NOT happen.", "Duplicate registered enchantment. This should NOT happen.",
new IllegalStateException(enchantment.getKey()+" enchantment was already registered")); new IllegalStateException(enchantment.getKey()+" enchantment was already registered"));
return; return false;
} }
if(byNameMap.containsKey(enchantment.getName())){ if(byNameMap.containsKey(enchantment.getName())){
CustomAnvil.instance.getLogger().log(Level.WARNING, CustomAnvil.instance.getLogger().log(Level.WARNING,
@ -74,9 +83,14 @@ public class CAEnchantmentRegistry {
byKeyMap.put(enchantment.getKey(), enchantment); byKeyMap.put(enchantment.getKey(), enchantment);
byNameMap.put(enchantment.getName(), enchantment); byNameMap.put(enchantment.getName(), enchantment);
if(!enchantment.isOptimised()){ if(!enchantment.isGetOptimised()){
unoptimisedValues.add(enchantment); unoptimisedGetValues.add(enchantment);
} }
if(!enchantment.isCleanOptimised()){
unoptimisedCleanValues.add(enchantment);
}
return true;
} }
/** /**
@ -87,13 +101,17 @@ public class CAEnchantmentRegistry {
* No guarantee that the enchantment will absent if the config guis if unregistered late. * No guarantee that the enchantment will absent if the config guis if unregistered late.
* (By late I mean after custom anvil startup.) * (By late I mean after custom anvil startup.)
* @param enchantment The enchantment to be unregistered. * @param enchantment The enchantment to be unregistered.
* @return If the operation was successful.
*/ */
public void unregister(CAEnchantment enchantment){
if(enchantment == null) return; public boolean unregister(@Nullable CAEnchantment enchantment){
if(enchantment == null) return false;
byKeyMap.remove(enchantment.getKey()); byKeyMap.remove(enchantment.getKey());
byNameMap.remove(enchantment.getName()); byNameMap.remove(enchantment.getName());
unoptimisedValues.remove(enchantment); unoptimisedGetValues.remove(enchantment);
unoptimisedCleanValues.remove(enchantment);
return true;
} }
/** /**
@ -101,7 +119,8 @@ public class CAEnchantmentRegistry {
* @param key Key to fetch. * @param key Key to fetch.
* @return Registered enchantment. null if absent. * @return Registered enchantment. null if absent.
*/ */
public @Nullable CAEnchantment getByKey(@NotNull NamespacedKey key){ @Nullable
public CAEnchantment getByKey(@NotNull NamespacedKey key){
return byKeyMap.get(key); return byKeyMap.get(key);
} }
@ -110,13 +129,14 @@ public class CAEnchantmentRegistry {
* @param name Name to fetch. * @param name Name to fetch.
* @return Registered enchantment. null if absent. * @return Registered enchantment. null if absent.
*/ */
public @Nullable CAEnchantment getByName(@NotNull String name){ @Nullable
public CAEnchantment getByName(@NotNull String name){
return byNameMap.get(name); return byNameMap.get(name);
} }
/** /**
* Gets an array of all the registered enchantments. * Gets an array of all the registered enchantments.
* @return Array of enchantment. * @return Array of enchantments.
*/ */
@NotNull @NotNull
public Collection<CAEnchantment> values() { public Collection<CAEnchantment> values() {
@ -124,12 +144,45 @@ public class CAEnchantmentRegistry {
} }
/** /**
* Gets a list of all the unoptimised enchantments. * Gets a map of all the registered enchantments.
* @return List of enchantment. * @return Map of enchantments.
*/
public Map<NamespacedKey, CAEnchantment> registeredEnchantments() {
return byKeyMap;
}
/**
* Gets a list of all the unoptimised get operation enchantments.
* @return List of unoptimised enchantments.
*/ */
@NotNull @NotNull
public List<CAEnchantment> unoptimisedValues() { public List<CAEnchantment> unoptimisedGetValues() {
return unoptimisedValues; return unoptimisedGetValues;
}
/**
* Gets a list of all the unoptimised clean operation enchantments.
* @return List of unoptimised enchantments.
*/
@NotNull
public List<CAEnchantment> unoptimisedCleanValues() {
return unoptimisedCleanValues;
}
/**
* Get "clean optimised operation" for get enchantments.
* @return Get mutable "clean enchantments optimised operation" list.
*/
public List<BulkCleanEnchantOperation> getOptimisedCleanOperators() {
return optimisedCleanOperators;
}
/**
* Get "get optimised operation" for get enchantments.
* @return Get mutable "get enchantments optimised operation" list.
*/
public List<BulkGetEnchantOperation> getOptimisedGetOperators() {
return optimisedGetOperators;
} }
} }

View file

@ -1,31 +1,31 @@
package xyz.alexcrea.cuanvil.enchant; package xyz.alexcrea.cuanvil.enchant;
// because spigot (1.18) do not support enchantment rarity, I need to do it myself... // because spigot (1.18) do not look like to provide access to enchantment rarity I need to do it myself...
public enum EnchantmentRarity { public class EnchantmentRarity {
NO_RARITY(0, 0), public static final EnchantmentRarity NO_RARITY = new EnchantmentRarity(0, 0);
COMMON(1), public static final EnchantmentRarity COMMON = new EnchantmentRarity(1);
UNCOMMON(2), public static final EnchantmentRarity UNCOMMON = new EnchantmentRarity(2);
RARE(4), public static final EnchantmentRarity RARE = new EnchantmentRarity(4);
VERY_RARE(8); public static final EnchantmentRarity VERY_RARE = new EnchantmentRarity(8);
private final int itemValue; private final int itemValue;
private final int bookValue; private final int bookValue;
EnchantmentRarity(int itemValue, int bookValue) { public EnchantmentRarity(int itemValue, int bookValue) {
this.itemValue = itemValue; this.itemValue = itemValue;
this.bookValue = bookValue; this.bookValue = bookValue;
} }
EnchantmentRarity(int itemValue) { public EnchantmentRarity(int itemValue) {
this(itemValue, Math.max(1, itemValue / 2)); this(itemValue, Math.max(1, itemValue / 2));
} }
public int getBookValue() { public final int getBookValue() {
return bookValue; return bookValue;
} }
public int getItemValue() { public final int getItemValue() {
return itemValue; return itemValue;
} }

View file

@ -0,0 +1,47 @@
package xyz.alexcrea.cuanvil.enchant.bulk;
import io.delilaheve.util.ItemUtil;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.api.EnchantmentApi;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
import java.util.Map;
public class BukkitEnchantBulkOperation implements BulkGetEnchantOperation, BulkCleanEnchantOperation {
@Override
public void bulkGet(@NotNull Map<CAEnchantment, Integer> enchantmentList, @NotNull ItemStack item, @NotNull ItemMeta meta) {
if (ItemUtil.INSTANCE.isEnchantedBook(item)) {
((EnchantmentStorageMeta)meta).getStoredEnchants().forEach((enchantment, level) ->
enchantmentList.put(EnchantmentApi.getByKey(enchantment.getKey()), level)
);
} else {
item.getEnchantments().forEach((enchantment, level) ->
enchantmentList.put(EnchantmentApi.getByKey(enchantment.getKey()), level)
);
}
}
@Override
public void bulkClear(@NotNull ItemStack item) {
if (item.getType() != Material.ENCHANTED_BOOK) {
item.getEnchantments().forEach((enchantment, leve) ->
item.removeEnchantment(enchantment)
);
}
}
@Override
public void bulkClear(@NotNull ItemStack item, @NotNull ItemMeta meta) {
if (item.getType() == Material.ENCHANTED_BOOK) {
EnchantmentStorageMeta bookMeta = (EnchantmentStorageMeta) meta;
bookMeta.getStoredEnchants().forEach((enchantment, leve) ->
bookMeta.removeStoredEnchant(enchantment)
);
}
}
}

View file

@ -0,0 +1,28 @@
package xyz.alexcrea.cuanvil.enchant.bulk;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
/**
* Bulk operation for clean enchantments operations.
*/
public interface BulkCleanEnchantOperation {
/**
* Bulk clear part of the enchantments from this item.
* The item can be edited freely. If you need the meta it is preferred to use {@link #bulkClear(ItemStack, ItemMeta)} if possible
* @param item The item to clear enchantment from.
*/
void bulkClear(@NotNull ItemStack item);
/**
* Bulk clear part of the enchantments from this item meta.
* Item should not be edited as meta will be applied later.
* If you need to edit the item and do not need the meta use {@link #bulkClear(ItemStack)}
* @param item The item source of the item meta. should not be edited.
* @param meta The item meta to clear enchantment from.
*/
void bulkClear(@NotNull ItemStack item, @NotNull ItemMeta meta);
}

View file

@ -0,0 +1,23 @@
package xyz.alexcrea.cuanvil.enchant.bulk;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
import java.util.Map;
/**
* Bulk operation for get enchantments operations.
*/
public interface BulkGetEnchantOperation {
/**
* Bulk get part of the stored enchantment of this item.
* @param enchantmentList Mutable map of collected enchantment. should b
* @param item The item to get enchantment from. Should not get edited.
* @param meta The item meta to get enchantment from. Should not get edited.
*/
void bulkGet(@NotNull Map<CAEnchantment, Integer> enchantmentList, @NotNull ItemStack item, @NotNull ItemMeta meta);
}

View file

@ -0,0 +1,37 @@
package xyz.alexcrea.cuanvil.enchant.bulk;
import me.athlaeos.enchantssquared.managers.CustomEnchantManager;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.dependency.DependencyManager;
import xyz.alexcrea.cuanvil.dependency.EnchantmentSquaredDependency;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
import java.util.Collections;
import java.util.Map;
public class EnchantSquaredBulkOperation implements BulkGetEnchantOperation, BulkCleanEnchantOperation {
@Override
public void bulkGet(@NotNull Map<CAEnchantment, Integer> enchantmentList, @NotNull ItemStack item, @NotNull ItemMeta meta) {
EnchantmentSquaredDependency enchantmentSquared = DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility();
if(enchantmentSquared != null){
enchantmentSquared.getEnchantmentsSquared(item, enchantmentList);
}
}
@Override
public void bulkClear(@NotNull ItemStack item) {
EnchantmentSquaredDependency enchantmentSquared = DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility();
if(enchantmentSquared != null){
CustomEnchantManager.getInstance().setItemEnchants(item, Collections.emptyMap());
}
}
@Override
public void bulkClear(@NotNull ItemStack item, @NotNull ItemMeta meta) {
// item meta is not preferred for enchantment squared clear
}
}

View file

@ -5,13 +5,11 @@ import com.willfp.ecoenchants.target.EnchantmentTarget;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment; import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity; import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity;
import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment;
import xyz.alexcrea.cuanvil.group.ConflictType;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier;
public class CAEcoEnchant extends CAVanillaEnchantment implements AdditionalTestEnchantment { public class CAEcoEnchant extends CAVanillaEnchantment implements AdditionalTestEnchantment {

View file

@ -27,14 +27,19 @@ public class CAEnchantSquaredEnchantment extends CAEnchantmentBase {
} }
@Override @Override
public boolean isOptimised() { public boolean isGetOptimised() {
return true;
}
@Override
public boolean isCleanOptimised() {
return true; return true;
} }
@Override @Override
public boolean isAllowed(@NotNull HumanEntity human) { public boolean isAllowed(@NotNull HumanEntity human) {
if(human instanceof Player){ if(human instanceof Player player){
return this.enchant.hasPermission((Player) human); return this.enchant.hasPermission(player);
} }
// Not really ideal for maintainability but will probably never be executed. (At least I hope) // Not really ideal for maintainability but will probably never be executed. (At least I hope)
boolean required = CustomEnchantManager.getInstance().isRequirePermissions(); boolean required = CustomEnchantManager.getInstance().isRequirePermissions();

View file

@ -13,6 +13,9 @@ import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity;
import java.util.Locale; import java.util.Locale;
/**
* Custom Anvil enchantment implementation for vanilla registered enchantment.
*/
public class CAVanillaEnchantment extends CAEnchantmentBase { public class CAVanillaEnchantment extends CAEnchantmentBase {
private final @NotNull Enchantment enchantment; private final @NotNull Enchantment enchantment;
@ -29,7 +32,12 @@ public class CAVanillaEnchantment extends CAEnchantmentBase {
} }
@Override @Override
public boolean isOptimised() { public boolean isGetOptimised() {
return true;
}
@Override
public boolean isCleanOptimised() {
return true; return true;
} }

View file

@ -16,7 +16,7 @@ import java.util.Collections;
public class MainConfigGui extends ChestGui { public class MainConfigGui extends ChestGui {
private final static MainConfigGui INSTANCE = new MainConfigGui(); private static final MainConfigGui INSTANCE = new MainConfigGui();
public static MainConfigGui getInstance() { public static MainConfigGui getInstance() {
return INSTANCE; return INSTANCE;
@ -58,7 +58,7 @@ public class MainConfigGui extends ChestGui {
enchantLimitMeta.setLore(Collections.singletonList("\u00A77Click here to open enchantment level limit menu")); enchantLimitMeta.setLore(Collections.singletonList("\u00A77Click here to open enchantment level limit menu"));
enchantLimitItemstack.setItemMeta(enchantLimitMeta); enchantLimitItemstack.setItemMeta(enchantLimitMeta);
GuiItem enchantLimitItem = GuiGlobalItems.goToGuiItem(enchantLimitItemstack, EnchantLimitConfigGui.INSTANCE); GuiItem enchantLimitItem = GuiGlobalItems.goToGuiItem(enchantLimitItemstack, new EnchantLimitConfigGui());
pane.bindItem('2', enchantLimitItem); pane.bindItem('2', enchantLimitItem);
// enchant cost item // enchant cost item
@ -70,7 +70,7 @@ public class MainConfigGui extends ChestGui {
enchantCostMeta.setLore(Collections.singletonList("\u00A77Click here to open enchantment costs menu")); enchantCostMeta.setLore(Collections.singletonList("\u00A77Click here to open enchantment costs menu"));
enchantCostItemstack.setItemMeta(enchantCostMeta); enchantCostItemstack.setItemMeta(enchantCostMeta);
GuiItem enchantCostItem = GuiGlobalItems.goToGuiItem(enchantCostItemstack, EnchantCostConfigGui.INSTANCE); GuiItem enchantCostItem = GuiGlobalItems.goToGuiItem(enchantCostItemstack, new EnchantCostConfigGui());
pane.bindItem('3', enchantCostItem); pane.bindItem('3', enchantCostItem);
// Enchantment Conflicts item // Enchantment Conflicts item

View file

@ -12,6 +12,7 @@ import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
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.dependency.protocolib.PacketManager; import xyz.alexcrea.cuanvil.dependency.protocolib.PacketManager;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
@ -31,8 +32,9 @@ import java.util.Collections;
*/ */
public class BasicConfigGui extends ChestGui implements ValueUpdatableGui { public class BasicConfigGui extends ChestGui implements ValueUpdatableGui {
private static BasicConfigGui INSTANCE; private static BasicConfigGui INSTANCE = null;
@Nullable
public static BasicConfigGui getInstance() { public static BasicConfigGui getInstance() {
return INSTANCE; return INSTANCE;
} }
@ -43,7 +45,7 @@ public class BasicConfigGui extends ChestGui implements ValueUpdatableGui {
*/ */
public BasicConfigGui(PacketManager packetManager) { public BasicConfigGui(PacketManager packetManager) {
super(4, "\u00A78Basic Config", CustomAnvil.instance); super(4, "\u00A78Basic Config", CustomAnvil.instance);
INSTANCE = this; if(INSTANCE == null) INSTANCE = this;
this.packetManager = packetManager; this.packetManager = packetManager;
init(); init();

View file

@ -18,7 +18,7 @@ import java.util.Collection;
public class EnchantConflictGui extends MappedGuiListConfigGui<EnchantConflictGroup, EnchantConflictSubSettingGui> { public class EnchantConflictGui extends MappedGuiListConfigGui<EnchantConflictGroup, EnchantConflictSubSettingGui> {
public final static EnchantConflictGui INSTANCE = new EnchantConflictGui(); public static final EnchantConflictGui INSTANCE = new EnchantConflictGui();
static { static {
INSTANCE.init(); INSTANCE.init();
@ -36,7 +36,7 @@ public class EnchantConflictGui extends MappedGuiListConfigGui<EnchantConflictGr
new IncludeGroup("new_group"), new IncludeGroup("new_group"),
0); 0);
ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList().add(conflict); ConfigHolder.CONFLICT_HOLDER.getConflictManager().addConflict(conflict);
// save empty conflict in config // save empty conflict in config
String[] emptyStringArray = new String[0]; String[] emptyStringArray = new String[0];

View file

@ -4,6 +4,7 @@ import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
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.enchant.CAEnchantment;
import xyz.alexcrea.cuanvil.enchant.EnchantmentProperties; import xyz.alexcrea.cuanvil.enchant.EnchantmentProperties;
@ -24,18 +25,21 @@ public class EnchantCostConfigGui extends AbstractEnchantConfigGui<EnchantCostSe
private static final String SECTION_NAME = "enchant_values"; private static final String SECTION_NAME = "enchant_values";
public static final EnchantCostConfigGui INSTANCE = new EnchantCostConfigGui(); private static EnchantCostConfigGui INSTANCE = null;
static { @Nullable
INSTANCE.init(); public static EnchantCostConfigGui getInstance() {
return INSTANCE;
} }
/** /**
* Constructor of this Global gui for enchantment cost settings. * Constructor of this Global gui for enchantment cost settings.
*/ */
private EnchantCostConfigGui() { public EnchantCostConfigGui() {
super("\u00A78Enchantment Level Cost"); super("\u00A78Enchantment Level Cost");
if(INSTANCE == null) INSTANCE = this;
init();
} }
@Override @Override

View file

@ -2,6 +2,7 @@ package xyz.alexcrea.cuanvil.gui.config.global;
import com.github.stefvanschie.inventoryframework.gui.GuiItem; import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import org.bukkit.Material; import org.bukkit.Material;
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.enchant.CAEnchantment;
import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui; import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui;
@ -17,18 +18,21 @@ public class EnchantLimitConfigGui extends AbstractEnchantConfigGui<IntSettingsG
private static final String SECTION_NAME = "enchant_limits"; private static final String SECTION_NAME = "enchant_limits";
public static final EnchantLimitConfigGui INSTANCE = new EnchantLimitConfigGui(); private static EnchantLimitConfigGui INSTANCE = null;
static { @Nullable
INSTANCE.init(); public static EnchantLimitConfigGui getInstance() {
return INSTANCE;
} }
/** /**
* Constructor of this Global gui for enchantment level limit settings. * Constructor of this Global gui for enchantment level limit settings.
*/ */
private EnchantLimitConfigGui() { public EnchantLimitConfigGui() {
super("\u00A78Enchantment Level Limit"); super("\u00A78Enchantment Level Limit");
if(INSTANCE == null) INSTANCE = this;
init();
} }
@Override @Override

View file

@ -13,7 +13,7 @@ import java.util.function.Consumer;
public abstract class MappedGuiListConfigGui< T, S extends ElementMappedToListGui> extends MappedElementListConfigGui< T, S > { public abstract class MappedGuiListConfigGui< T, S extends ElementMappedToListGui> extends MappedElementListConfigGui< T, S > {
public MappedGuiListConfigGui(@NotNull String title) { protected MappedGuiListConfigGui(@NotNull String title) {
super(title); super(title);
} }

View file

@ -118,10 +118,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
EnchantConflictManager manager = ConfigHolder.CONFLICT_HOLDER.getConflictManager(); EnchantConflictManager manager = ConfigHolder.CONFLICT_HOLDER.getConflictManager();
// Remove from enchantment // Remove from enchantment
for (CAEnchantment enchantment : this.enchantConflict.getEnchants()) { manager.removeConflict(this.enchantConflict);
enchantment.removeConflict(this.enchantConflict);
}
manager.conflictList.remove(this.enchantConflict);
// Remove from parent // Remove from parent
this.parent.removeGeneric(this.enchantConflict); this.parent.removeGeneric(this.enchantConflict);

View file

@ -4,6 +4,8 @@ import io.delilaheve.util.ConfigOptions
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.configuration.file.YamlConfiguration
import org.bukkit.plugin.java.JavaPlugin import org.bukkit.plugin.java.JavaPlugin
import xyz.alexcrea.cuanvil.api.event.CAConfigReadyEvent
import xyz.alexcrea.cuanvil.api.event.CAEnchantRegistryReadyEvent
import xyz.alexcrea.cuanvil.command.EditConfigExecutor import xyz.alexcrea.cuanvil.command.EditConfigExecutor
import xyz.alexcrea.cuanvil.command.ReloadExecutor import xyz.alexcrea.cuanvil.command.ReloadExecutor
import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.config.ConfigHolder
@ -80,8 +82,6 @@ class CustomAnvil : JavaPlugin() {
override fun onEnable() { override fun onEnable() {
instance = this instance = this
val pluginManager = Bukkit.getPluginManager();
// Disable old plugin name if exist // Disable old plugin name if exist
val potentialPlugin = Bukkit.getPluginManager().getPlugin("UnsafeEnchantsPlus") val potentialPlugin = Bukkit.getPluginManager().getPlugin("UnsafeEnchantsPlus")
if (potentialPlugin != null) { if (potentialPlugin != null) {
@ -90,40 +90,53 @@ class CustomAnvil : JavaPlugin() {
logger.warning("Please note CustomAnvil is a more recent version of UnsafeEnchantsPlus") logger.warning("Please note CustomAnvil is a more recent version of UnsafeEnchantsPlus")
} }
// Load dependency // Add commands
DependencyManager.loadDependency() prepareCommand()
// Register enchantments
CAEnchantmentRegistry.getInstance().registerStartupEnchantments()
// Load chat listener // Load chat listener
chatListener = ChatEventListener() chatListener = ChatEventListener()
pluginManager.registerEvents(chatListener, this) server.pluginManager.registerEvents(chatListener, this)
// Load dependency
DependencyManager.loadDependency()
// Register anvil events
server.pluginManager.registerEvents(AnvilEventListener(DependencyManager.packetManager), this)
// Load metrics
Metrics(this, bstatsPluginId)
// Load other thing later.
// It is so other dependent plugins can implement there event listener before we fire them.
Bukkit.getScheduler().scheduleSyncDelayedTask(this, {loadEnchantmentSystem()}, 0L)
}
private fun loadEnchantmentSystem(){
// Load default configuration
if (!ConfigHolder.loadDefaultConfig()) return
// Register enchantments
CAEnchantmentRegistry.getInstance().registerBukkit()
DependencyManager.registerEnchantments()
val enchantReadyEvent = CAEnchantRegistryReadyEvent()
server.pluginManager.callEvent(enchantReadyEvent)
// Load config // Load config
val success = ConfigHolder.loadConfig() if (!ConfigHolder.loadNonDefaultConfig()) return
if (!success) return
// temporary: handle 1.21 update // temporary: handle 1.21 update
Update_1_21.handleUpdate() Update_1_21.handleUpdate()
// Handle custom enchant config val configReadyEvent = CAConfigReadyEvent()
DependencyManager.handleConfigChanges(this) server.pluginManager.callEvent(configReadyEvent)
// Load gui constants //TODO maybe something better later // Load gui constants //TODO maybe something better later
MainConfigGui.getInstance().init(DependencyManager.packetManager) MainConfigGui.getInstance().init(DependencyManager.packetManager)
GuiSharedConstant.loadConstants() GuiSharedConstant.loadConstants()
// Load metrics // Register enchantment of compatible plugin and load configuration change.
Metrics(this, bstatsPluginId) DependencyManager.handleCompatibilityConfig()
// Add commands to reload the plugin
prepareCommand()
server.pluginManager.registerEvents(
AnvilEventListener(DependencyManager.packetManager),
this
)
} }
fun reloadResource( fun reloadResource(

View file

@ -29,7 +29,6 @@ object ItemUtil {
fun ItemStack.setEnchantmentsUnsafe(enchantments: Map<CAEnchantment, Int>) { fun ItemStack.setEnchantmentsUnsafe(enchantments: Map<CAEnchantment, Int>) {
CAEnchantment.clearEnchants(this) CAEnchantment.clearEnchants(this)
//TODO maybe faster methode to add vanilla enchantment. maybe move this function to wrapped enchantment
enchantments.forEach { (enchantment, level) -> enchantments.forEach { (enchantment, level) ->
enchantment.addEnchantmentUnsafe(this, level) enchantment.addEnchantmentUnsafe(this, level)
} }

View file

@ -36,8 +36,8 @@ class ReloadExecutor : CommandExecutor {
// Then update all global gui containing value from config // Then update all global gui containing value from config
BasicConfigGui.getInstance()?.updateGuiValues() BasicConfigGui.getInstance()?.updateGuiValues()
EnchantCostConfigGui.INSTANCE.updateGuiValues() EnchantCostConfigGui.getInstance()?.updateGuiValues()
EnchantLimitConfigGui.INSTANCE.updateGuiValues() EnchantLimitConfigGui.getInstance()?.updateGuiValues()
EnchantConflictGui.INSTANCE.reloadValues() EnchantConflictGui.INSTANCE.reloadValues()
GroupConfigGui.INSTANCE.reloadValues() GroupConfigGui.INSTANCE.reloadValues()

View file

@ -1,11 +1,9 @@
package xyz.alexcrea.cuanvil.dependency package xyz.alexcrea.cuanvil.dependency
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.plugin.Plugin
import xyz.alexcrea.cuanvil.dependency.protocolib.NoProtocoLib import xyz.alexcrea.cuanvil.dependency.protocolib.NoProtocoLib
import xyz.alexcrea.cuanvil.dependency.protocolib.PacketManager import xyz.alexcrea.cuanvil.dependency.protocolib.PacketManager
import xyz.alexcrea.cuanvil.dependency.protocolib.ProtocoLibWrapper import xyz.alexcrea.cuanvil.dependency.protocolib.ProtocoLibWrapper
import java.io.File
object DependencyManager { object DependencyManager {
@ -19,7 +17,7 @@ object DependencyManager {
// ProtocolLib dependency // ProtocolLib dependency
packetManager = packetManager =
if(pluginManager.isPluginEnabled("ProtocolLib")) ProtocoLibWrapper() if(pluginManager.isPluginEnabled("ProtocolLib")) ProtocoLibWrapper()
else NoProtocoLib() else NoProtocoLib()
// Enchantment Squared dependency // Enchantment Squared dependency
if(pluginManager.isPluginEnabled("EnchantsSquared")){ if(pluginManager.isPluginEnabled("EnchantsSquared")){
@ -35,11 +33,14 @@ object DependencyManager {
} }
fun handleConfigChanges(plugin: Plugin) { fun handleCompatibilityConfig() {
val folder = File(plugin.dataFolder, "compatibility")
enchantmentSquaredCompatibility?.registerPluginConfiguration() enchantmentSquaredCompatibility?.registerPluginConfiguration()
ecoEnchantCompatibility?.registerPluginConfiguration(folder)
}
fun registerEnchantments() {
enchantmentSquaredCompatibility?.registerEnchantments()
ecoEnchantCompatibility?.registerEnchantments()
} }

View file

@ -2,14 +2,10 @@ package xyz.alexcrea.cuanvil.dependency
import com.willfp.ecoenchants.enchant.EcoEnchants import com.willfp.ecoenchants.enchant.EcoEnchants
import io.delilaheve.CustomAnvil import io.delilaheve.CustomAnvil
import org.bukkit.configuration.file.YamlConfiguration
import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.event.inventory.PrepareAnvilEvent
import org.bukkit.plugin.Plugin import org.bukkit.plugin.Plugin
import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.api.EnchantmentApi
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEcoEnchant import xyz.alexcrea.cuanvil.enchant.wrapped.CAEcoEnchant
import java.io.File
class EcoEnchantDependency(private val ecoEnchantPlugin: Plugin) { class EcoEnchantDependency(private val ecoEnchantPlugin: Plugin) {
@ -22,57 +18,14 @@ class EcoEnchantDependency(private val ecoEnchantPlugin: Plugin) {
} }
fun registerEnchantments() { fun registerEnchantments() {
val registery = CAEnchantmentRegistry.getInstance() CustomAnvil.instance.logger.info("Preparing Eco Enchant compatibility...")
for (ecoEnchant in EcoEnchants.values()) {
val enchantments: CAEnchantment = CAEcoEnchant(ecoEnchant)
registery.unregister(registery.getByKey(ecoEnchant.enchantment.key)) // As eco enchants are considered real enchantment, we need to unregister it.
registery.register(enchantments)
}
}
fun registerPluginConfiguration(folder: File){
val compatibilityFile = File(folder, "ecoEnchant.yml")
if(compatibilityFile.exists()){
folder.mkdirs()
compatibilityFile.createNewFile()
}
val config = YamlConfiguration.loadConfiguration(compatibilityFile)
val defaultConfig = ConfigHolder.DEFAULT_CONFIG.config
var doSave = false
for (ecoEnchant in EcoEnchants.values()) { for (ecoEnchant in EcoEnchants.values()) {
val enchantment = CAEnchantmentRegistry.getInstance().getByKey(ecoEnchant.enchantmentKey) EnchantmentApi.unregisterEnchantment(ecoEnchant.enchantment) // As eco enchants is loaded before custom anvil and register enchantment to registry, we need to unregister old "vanilla" enchant.
EnchantmentApi.registerEnchantment(CAEcoEnchant(ecoEnchant))
if(enchantment == null){
CustomAnvil.instance.logger.warning("Could not find " + ecoEnchant.enchantmentKey + "testing compatibility.")
continue
}
// Write enchantment value if needed
val testPath = "default.${enchantment.key.key}"
if(!config.getBoolean(testPath, false)){
doSave = true
config[testPath] = true
defaultConfig["enchant_limits.${enchantment.key.key}"] = enchantment.defaultMaxLevel()
val rarity = enchantment.defaultRarity()
defaultConfig["enchant_values.${enchantment.key.key}.item"] = rarity.itemValue
defaultConfig["enchant_values.${enchantment.key.key}.book"] = rarity.bookValue
}
}
if(doSave){
config.save(compatibilityFile)
ConfigHolder.DEFAULT_CONFIG.saveToDisk(true)
CustomAnvil.instance.logger.info("Saved default for new eco enchant enchantments.")
} }
CustomAnvil.instance.logger.info("Eco Enchant should now work as expected !")
} }
} }

View file

@ -3,14 +3,19 @@ package xyz.alexcrea.cuanvil.dependency
import io.delilaheve.CustomAnvil import io.delilaheve.CustomAnvil
import me.athlaeos.enchantssquared.enchantments.CustomEnchant import me.athlaeos.enchantssquared.enchantments.CustomEnchant
import me.athlaeos.enchantssquared.managers.CustomEnchantManager import me.athlaeos.enchantssquared.managers.CustomEnchantManager
import org.bukkit.Material
import org.bukkit.NamespacedKey import org.bukkit.NamespacedKey
import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.event.inventory.PrepareAnvilEvent
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.plugin.Plugin import org.bukkit.plugin.Plugin
import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.api.ConflictBuilder
import xyz.alexcrea.cuanvil.api.EnchantmentApi
import xyz.alexcrea.cuanvil.api.MaterialGroupApi
import xyz.alexcrea.cuanvil.enchant.CAEnchantment import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
import xyz.alexcrea.cuanvil.enchant.bulk.EnchantSquaredBulkOperation
import xyz.alexcrea.cuanvil.enchant.wrapped.CAEnchantSquaredEnchantment import xyz.alexcrea.cuanvil.enchant.wrapped.CAEnchantSquaredEnchantment
import xyz.alexcrea.cuanvil.group.IncludeGroup
import java.util.* import java.util.*
class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin) { class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin) {
@ -31,14 +36,18 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin)
} }
fun registerEnchantments(){ fun registerEnchantments(){
CustomAnvil.instance.logger.info("Preparing Enchantment Squared compatibility...")
// Register enchantments
for (enchant in CustomEnchantManager.getInstance().allEnchants.values) { for (enchant in CustomEnchantManager.getInstance().allEnchants.values) {
CAEnchantmentRegistry.getInstance().register( EnchantmentApi.registerEnchantment(CAEnchantSquaredEnchantment(enchant))
CAEnchantSquaredEnchantment(
enchant
)
)
} }
// Register bulk operation
val bulkOpperations = EnchantSquaredBulkOperation()
EnchantmentApi.addBulkGet(bulkOpperations)
EnchantmentApi.addBulkClean(bulkOpperations)
} }
fun getEnchantmentsSquared(item: ItemStack, enchantments: MutableMap<CAEnchantment, Int>) { fun getEnchantmentsSquared(item: ItemStack, enchantments: MutableMap<CAEnchantment, Int>) {
@ -50,10 +59,6 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin)
} }
fun clearEnchantments(item: ItemStack) {
CustomEnchantManager.getInstance().removeAllEnchants(item)
}
fun getKeyFromEnchant(enchant: CustomEnchant): NamespacedKey{ fun getKeyFromEnchant(enchant: CustomEnchant): NamespacedKey{
return NamespacedKey.fromString(enchant.type.lowercase(Locale.getDefault()), this.enchantmentSquaredPlugin)!! return NamespacedKey.fromString(enchant.type.lowercase(Locale.getDefault()), this.enchantmentSquaredPlugin)!!
} }
@ -61,14 +66,8 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin)
return CAEnchantment.getByKey(getKeyFromEnchant(enchant))!! return CAEnchantment.getByKey(getKeyFromEnchant(enchant))!!
} }
private val IS_READY_PATH = "enchantment_square_ready"
fun registerPluginConfiguration(){ fun registerPluginConfiguration(){
val defaultConfig = ConfigHolder.DEFAULT_CONFIG.config CustomAnvil.instance.logger.info("Preparing Enchantment Squared config...")
val isReady = defaultConfig.getBoolean(IS_READY_PATH, false)
if(isReady) return
CustomAnvil.instance.logger.info("Preparing configuration for Enchantment Squared...")
// Prepare enchantments // Prepare enchantments
val esEnchantments = ArrayList<CAEnchantSquaredEnchantment>() val esEnchantments = ArrayList<CAEnchantSquaredEnchantment>()
@ -76,91 +75,62 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin)
esEnchantments.add(getWrappedEnchant(enchant) as CAEnchantSquaredEnchantment) esEnchantments.add(getWrappedEnchant(enchant) as CAEnchantSquaredEnchantment)
} }
// Write default level limit and xp cost
for (enchantment in esEnchantments) {
defaultConfig["enchant_limits.${enchantment.key.key}"] = enchantment.defaultMaxLevel()
val rarity = enchantment.defaultRarity()
defaultConfig["enchant_values.${enchantment.key.key}.item"] = rarity.itemValue
defaultConfig["enchant_values.${enchantment.key.key}.book"] = rarity.bookValue
}
// Write groups and conflicts // Write groups and conflicts
writeMissingGroups() writeMissingGroups()
writeMaterialRestriction(esEnchantments) writeMaterialRestriction(esEnchantments)
writeEnchantmentConflicts(esEnchantments) writeEnchantmentConflicts(esEnchantments)
// Set ready
defaultConfig[IS_READY_PATH] = true
// Save
ConfigHolder.DEFAULT_CONFIG.saveToDisk(true)
ConfigHolder.ITEM_GROUP_HOLDER.saveToDisk(true)
ConfigHolder.CONFLICT_HOLDER.saveToDisk(true)
// Reload
ConfigHolder.ITEM_GROUP_HOLDER.reload()
CustomAnvil.instance.logger.info("Enchantment Squared should now work as expected !") CustomAnvil.instance.logger.info("Enchantment Squared should now work as expected !")
} }
private fun writeMissingGroups(){ private fun writeMissingGroups(){
// Write group that do not exist on custom anvil. // Write group that do not exist on custom anvil.
// (Tools group regroup most of the tool items. I did not create a seperated group for theses) // (Tools group regroup most of the tool items. I did not create a seperated group for theses)
val groupConfig = ConfigHolder.ITEM_GROUP_HOLDER.config val pickaxes = IncludeGroup("pickaxes")
if(!groupConfig.isConfigurationSection("pickaxes")){ pickaxes.addAll(Material.WOODEN_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.DIAMOND_PICKAXE, Material.GOLDEN_PICKAXE, Material.NETHERITE_PICKAXE)
groupConfig["pickaxes.type"] = "include" MaterialGroupApi.addMaterialGroup(pickaxes)
groupConfig["pickaxes.items"] = listOf("wooden_pickaxe", "stone_pickaxe", "iron_pickaxe", "diamond_pickaxe", "golden_pickaxe", "netherite_pickaxe")
}
if(!groupConfig.isConfigurationSection("shovels")){ val shovels = IncludeGroup("shovels")
groupConfig["shovels.type"] = "include" shovels.addAll(Material.WOODEN_SHOVEL, Material.STONE_SHOVEL, Material.IRON_SHOVEL, Material.DIAMOND_SHOVEL, Material.GOLDEN_SHOVEL, Material.NETHERITE_SHOVEL)
groupConfig["shovels.items"] = listOf("wooden_shovel", "stone_shovel", "iron_shovel", "diamond_shovel", "golden_shovel", "netherite_shovel") MaterialGroupApi.addMaterialGroup(shovels)
}
if(!groupConfig.isConfigurationSection("hoes")){ val hoes = IncludeGroup("hoes")
groupConfig["hoes.type"] = "include" hoes.addAll(Material.WOODEN_HOE, Material.STONE_HOE, Material.IRON_HOE, Material.DIAMOND_HOE, Material.GOLDEN_HOE, Material.NETHERITE_HOE)
groupConfig["hoes.items"] = listOf("wooden_hoe", "stone_hoe", "iron_hoe", "diamond_hoe", "golden_hoe", "netherite_hoe") MaterialGroupApi.addMaterialGroup(hoes)
}
if(!groupConfig.isConfigurationSection("shield")){ val shield = IncludeGroup("shield")
groupConfig["shield.type"] = "include" shield.addToPolicy(Material.SHIELD)
groupConfig["shield.items"] = listOf("shield") MaterialGroupApi.addMaterialGroup(shield)
}
if(!groupConfig.isConfigurationSection("elytra")){ val elytra = IncludeGroup("elytra")
groupConfig["elytra.type"] = "include" elytra.addToPolicy(Material.ELYTRA)
groupConfig["elytra.items"] = listOf("elytra") MaterialGroupApi.addMaterialGroup(elytra)
}
if(!groupConfig.isConfigurationSection("trinkets")){ val trinkets = IncludeGroup("trinkets")
groupConfig["trinkets.type"] = "include" trinkets.addToPolicy(Material.ROTTEN_FLESH)
groupConfig["trinkets.items"] = listOf("rotten_flesh") MaterialGroupApi.addMaterialGroup(trinkets)
}
} }
private fun writeMaterialRestriction(esEnchantments: List<CAEnchantSquaredEnchantment>){ private fun writeMaterialRestriction(esEnchantments: List<CAEnchantSquaredEnchantment>){
val conflictConfig = ConfigHolder.CONFLICT_HOLDER.config
for (enchantment in esEnchantments) { for (enchantment in esEnchantments) {
val restrictionName = "restriction_${enchantment.key.key}" val conflict = ConflictBuilder("restriction_${enchantment.key.key}", CustomAnvil.instance)
if(!conflictConfig.isConfigurationSection(restrictionName)){ conflict.addEnchantment(enchantment)
conflictConfig["$restrictionName.enchantments"] = listOf(enchantment.name)
// Get allowed groups // enchanted book is allowed in any case.
val listOfAllowed = ArrayList<String>() conflict.addExcludedGroup("enchanted_book")
listOfAllowed.add("enchanted_book") // enchanted book is allowed in any case.
for (esGroup in enchantment.enchant.compatibleItems) { // Get allowed groups
val caGroup = esGroupToCAGroup(esGroup) for (esGroup in enchantment.enchant.compatibleItems) {
if(caGroup == null){ val caGroup = esGroupToCAGroup(esGroup)
CustomAnvil.instance.logger.info("Could not find equivalent custom anvil group for $esGroup") if(caGroup == null){
continue CustomAnvil.instance.logger.info("Could not find equivalent custom anvil group for $esGroup")
} continue
listOfAllowed.add(caGroup)
} }
conflictConfig["$restrictionName.notAffectedGroups"] = listOfAllowed conflict.addExcludedGroup(caGroup)
} }
conflict.registerIfAbsent()
} }
} }
@ -181,18 +151,12 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin)
} }
private fun writeConflict(enchantment1: CAEnchantment, enchantment2: CAEnchantment){ private fun writeConflict(enchantment1: CAEnchantment, enchantment2: CAEnchantment){
val conflictConfig = ConfigHolder.CONFLICT_HOLDER.config val conflict = ConflictBuilder("${enchantment1.name}_with_${enchantment2.name}_conflict", CustomAnvil.instance)
val conflictPath = "${enchantment1.name}_with_${enchantment2.name}_conflict"
if(!conflictConfig.isConfigurationSection(conflictPath)){ conflict.addEnchantment(enchantment1).addEnchantment(enchantment2)
conflictConfig["$conflictPath.enchantments"] = listOf(enchantment1.name, enchantment2.name)
val empty: List<String> = Collections.emptyList()
conflictConfig["$conflictPath.notAffectedGroups"] = empty
conflictConfig["$conflictPath.maxEnchantmentBeforeConflict"] = 1
}
conflict.setMaxBeforeConflict(1)
conflict.registerIfAbsent()
} }
/** /**

View file

@ -25,13 +25,37 @@ abstract class AbstractMaterialGroup(private val name: String) {
/** /**
* Push a material to this group to follow this group policy * Push a material to this group to follow this group policy
* @return this instance.
*/ */
abstract fun addToPolicy(mat: Material) abstract fun addToPolicy(mat: Material): AbstractMaterialGroup
/**
* Push a list of material to this group to follow this group policy
* @return this instance.
*/
fun addAll(vararg materials: Material): AbstractMaterialGroup {
for (material in materials) {
addToPolicy(material)
}
return this
}
/** /**
* Push a group to this group to follow this group policy * Push a group to this group to follow this group policy
* @return this instance.
*/ */
abstract fun addToPolicy(other: AbstractMaterialGroup) abstract fun addToPolicy(other: AbstractMaterialGroup): AbstractMaterialGroup
/**
* Push a list of group to this group to follow this group policy
* @return this instance.
*/
fun addAll(vararg otherList: AbstractMaterialGroup): AbstractMaterialGroup {
for (group in otherList) {
addToPolicy(group)
}
return this
}
/** /**
* Get the group contained material as a set * Get the group contained material as a set

View file

@ -5,7 +5,7 @@ import org.bukkit.Material
import xyz.alexcrea.cuanvil.enchant.CAEnchantment import xyz.alexcrea.cuanvil.enchant.CAEnchantment
class EnchantConflictGroup( class EnchantConflictGroup(
private val name: String, val name: String,
private val cantConflict: AbstractMaterialGroup, private val cantConflict: AbstractMaterialGroup,
var minBeforeBlock: Int var minBeforeBlock: Int
) { ) {

View file

@ -9,7 +9,6 @@ import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment
import xyz.alexcrea.cuanvil.enchant.CAEnchantment import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
import java.util.* import java.util.*
import kotlin.collections.ArrayList
class EnchantConflictManager { class EnchantConflictManager {
@ -28,7 +27,7 @@ class EnchantConflictManager {
private const val FUTURE_USE_PATH = "useInFuture" private const val FUTURE_USE_PATH = "useInFuture"
// Default name for a joining group // Default name for a joining group
private const val DEFAULT_GROUP_NAME = "joinedGroup" const val DEFAULT_GROUP_NAME = "joinedGroup"
// 1.20.5 compatibility TODO better update system // 1.20.5 compatibility TODO better update system
private val SWEEPING_EDGE_ENCHANT = private val SWEEPING_EDGE_ENCHANT =
@ -53,12 +52,21 @@ class EnchantConflictManager {
val section = config.getConfigurationSection(key)!! val section = config.getConfigurationSection(key)!!
val conflict = createConflict(section, itemManager, key) val conflict = createConflict(section, itemManager, key)
addConflictToEnchantments(conflict) addConflict(conflict)
conflictList.add(conflict)
} }
} }
fun addConflict(conflict: EnchantConflictGroup){
addConflictToEnchantments(conflict)
conflictList.add(conflict)
}
fun removeConflict(conflict: EnchantConflictGroup){
removeConflictFromEnchantments(conflict)
conflictList.remove(conflict)
}
// Add the conflict to enchantments // Add the conflict to enchantments
private fun addConflictToEnchantments(conflict: EnchantConflictGroup) { private fun addConflictToEnchantments(conflict: EnchantConflictGroup) {
conflict.getEnchants().forEach { enchant -> conflict.getEnchants().forEach { enchant ->
@ -66,6 +74,13 @@ class EnchantConflictManager {
} }
} }
// Remove the conflict from enchantments
private fun removeConflictFromEnchantments(conflict: EnchantConflictGroup) {
conflict.getEnchants().forEach { enchant ->
enchant.removeConflict(conflict)
}
}
// create and read a conflict from a yaml section // create and read a conflict from a yaml section
private fun createConflict( private fun createConflict(
section: ConfigurationSection, section: ConfigurationSection,
@ -140,7 +155,7 @@ class EnchantConflictManager {
): AbstractMaterialGroup { ): AbstractMaterialGroup {
val group = itemManager.get(groupName) val group = itemManager.get(groupName)
if (group == null) { if (group == null) {
CustomAnvil.instance.logger.warning("Group $groupName do not exist but is ask by conflict $conflictName") CustomAnvil.instance.logger.warning("Material group $groupName do not exist but is ask by conflict $conflictName")
return IncludeGroup("error_placeholder") return IncludeGroup("error_placeholder")
} }
@ -175,7 +190,7 @@ class EnchantConflictManager {
if(doConflict){ if(doConflict){
return ConflictType.ENCHANTMENT_CONFLICT return ConflictType.ENCHANTMENT_CONFLICT
} }
;
} }
} }
@ -188,14 +203,14 @@ class EnchantConflictManager {
} }
return result; return result
} }
private fun createPartialResult(item: ItemStack, enchantments: Map<CAEnchantment, Int>): ItemStack { private fun createPartialResult(item: ItemStack, enchantments: Map<CAEnchantment, Int>): ItemStack {
val newItem = item.clone() val newItem = item.clone()
CAEnchantment.clearEnchants(newItem) CAEnchantment.clearEnchants(newItem)
enchantments.forEach{//TODO maybe bulk add if possible enchantments.forEach{
enchantment -> enchantment.key.addEnchantmentUnsafe(newItem, enchantment.value) enchantment -> enchantment.key.addEnchantmentUnsafe(newItem, enchantment.value)
} }

View file

@ -20,14 +20,18 @@ class ExcludeGroup(name: String) : AbstractMaterialGroup(name) {
return false return false
} }
override fun addToPolicy(mat: Material) { override fun addToPolicy(mat: Material): ExcludeGroup {
includedMaterial.remove(mat) includedMaterial.remove(mat)
groupItems.remove(mat) groupItems.remove(mat)
return this
} }
override fun addToPolicy(other: AbstractMaterialGroup) { override fun addToPolicy(other: AbstractMaterialGroup): ExcludeGroup {
includedGroup.add(other) includedGroup.add(other)
groupItems.removeAll(other.getMaterials()) groupItems.removeAll(other.getMaterials())
return this
} }
override fun setGroups(groups: MutableSet<AbstractMaterialGroup>) { override fun setGroups(groups: MutableSet<AbstractMaterialGroup>) {

View file

@ -20,14 +20,18 @@ class IncludeGroup(name: String) : AbstractMaterialGroup(name) {
return false return false
} }
override fun addToPolicy(mat: Material) { override fun addToPolicy(mat: Material): IncludeGroup {
includedMaterial.add(mat) includedMaterial.add(mat)
groupItems.add(mat) groupItems.add(mat)
return this
} }
override fun addToPolicy(other: AbstractMaterialGroup) { override fun addToPolicy(other: AbstractMaterialGroup): IncludeGroup {
includedGroup.add(other) includedGroup.add(other)
groupItems.addAll(other.getMaterials()) groupItems.addAll(other.getMaterials())
return this
} }
override fun setGroups(groups: MutableSet<AbstractMaterialGroup>) { override fun setGroups(groups: MutableSet<AbstractMaterialGroup>) {

View file

@ -7,7 +7,7 @@ import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant
class AnvilCustomRecipe( class AnvilCustomRecipe(
private val name: String, val name: String,
var exactCount: Boolean, var exactCount: Boolean,
//var exactLeft: Boolean, //var exactLeft: Boolean,
//var exactRight: Boolean, //var exactRight: Boolean,
@ -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",