diff --git a/README.MD b/README.MD
index 6fad0cd..72149b0 100644
--- a/README.MD
+++ b/README.MD
@@ -17,50 +17,50 @@ systems and divide them up into readable, manageable, customizable segments.
### Anvil Enchanting
Anvil enchanting is primarily accessed via the
-[`AnvilOperation`](src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilOperation.java).
+[`VanillaAnvil`](src/main/java/com/github/jikoo/planarenchanting/anvil/VanillaAnvil.java).
This is a class containing several simple ways to modify anvil behaviors.
-For basic vanilla-style combination, all you need is an ordinary `AnvilOperation`.
+For basic vanilla-style combination, all you need is an ordinary `VanillaAnvil`.
```java
class MyAnvilHandler implements Listener {
@EventHandler
private void onPrepareAnvil(PrepareAnvilEvent event) {
- AnvilView view = event.getView();
- AnvilOperation operation = new AnvilOperation();
- AnvilResult result = operation.apply(view);
+ VanillaAnvil anvil = new VanillaAnvil();
+ AnvilResult result = anvil.getResult(event.getView());
event.setResult(result.item());
inventory.setRepairCostAmount(result.materialCost());
// Note: depending on how anvil actually functions, may need to update cost on a 0-tick delay.
- // May also need to set relevant window property for client.
inventory.setRepairCost(result.levelCost());
}
}
```
-For specific use cases (i.e. removing or changing enchantment level cap) you can provide the
-`AnvilOperation` with different functions which will be used by the default `AnvilFunction`
-implementations.
+For specific tweaks (i.e. removing or changing enchantment level cap) you can provide the
+`VanillaAnvil` with a different `AnvilBehavior` implementation.
Allowing conflicting enchantments to be added:
+
```java
-AnvilOperation operation = new AnvilOperation();
-operation.setEnchantsConflict((enchant1, enchant2) -> false);
+VanillaAnvil anvil = new VanillaAnvil(new AnvilBehavior() {
+ @Override
+ public boolean getEnchantsConflict(Enchantment enchant1, Enchantment enchant2) {
+ return false;
+ }
+});
```
If you have even more specific needs but still want to leverage certain vanilla-style functionality,
-you can write your own `AnvilOperation` and override `AnvilOperation#apply` to set your own
-operation order.
+you can write your own anvil functionality.
-A custom `AnvilOperation` that only performs rename operations:
+An implementation that only allows the input to be renamed:
```java
-class RenameOperation extends AnvilOperation {
- @Override
- public void apply(@NotNull AnvilView view) {
- AnvilOperationState state = new AnvilOperationState(this, view);
+class RenameOnlyAnvil {
+ public void getResult(@NotNull AnvilView view) {
+ AnvilState state = new AnvilState(VanillaAnvil.BEHAVIOR, view);
// Require first item to be set, second item to be unset.
if (ItemUtil.isEmpty(state.getBase().getItem())
@@ -69,9 +69,9 @@ class RenameOperation extends AnvilOperation {
}
// Apply base cost.
- state.apply(AnvilFunction.PRIOR_WORK_LEVEL_COST);
+ state.apply(AnvilFunctions.PRIOR_WORK_LEVEL_COST);
// Apply rename.
- state.apply(AnvilFunction.RENAME);
+ state.apply(AnvilFunctions.RENAME);
return state.forge();
}
diff --git a/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilBehavior.java b/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilBehavior.java
new file mode 100644
index 0000000..5edc9f1
--- /dev/null
+++ b/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilBehavior.java
@@ -0,0 +1,54 @@
+package com.github.jikoo.planarenchanting.anvil;
+
+import com.github.jikoo.planarenchanting.util.MetaCachedStack;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.NotNull;
+
+public interface AnvilBehavior {
+
+ /**
+ * Get whether an {@link Enchantment} is applicable for a wrapped {@link ItemStack}.
+ *
+ * @param enchantment the {@code Enchantment} to check for applicability
+ * @param base the item that may be enchanted
+ * @return whether the {@code Enchantment} can be applied
+ */
+ boolean enchantApplies(@NotNull Enchantment enchantment, @NotNull MetaCachedStack base);
+
+ /**
+ * Get whether two {@link Enchantment Enchantments} conflict.
+ *
+ * @return whether the {@code Enchantments} conflict
+ */
+ boolean enchantsConflict(@NotNull Enchantment enchant1, @NotNull Enchantment enchant2);
+
+ /**
+ * Get the maximum level for an {@link Enchantment}.
+ *
+ * @return the maximum level for an {@code Enchantment}
+ */
+ int getEnchantMaxLevel(@NotNull Enchantment enchantment);
+
+ /**
+ * Get whether an item should combine its {@link Enchantment Enchantments} with another item.
+ *
+ * @param base the base item
+ * @param addition the item added
+ * @return whether items should combine {@code Enchantments}
+ */
+ boolean itemsCombineEnchants(@NotNull MetaCachedStack base, @NotNull MetaCachedStack addition);
+
+ /**
+ * Get whether an item is repaired by another item. This is not the same as a repair via
+ * combination of like items! Like items always attempt to combine durability. If you require
+ * different behavior, override {@link VanillaAnvil#getResult(org.bukkit.inventory.view.AnvilView)}
+ * and do not call {@link AnvilFunctions#REPAIR_WITH_COMBINATION}.
+ *
+ * @param repaired the item repaired
+ * @param repairMat the item used to repair
+ * @return the method determining whether an item is repaired by another item
+ */
+ public boolean itemRepairedBy(@NotNull MetaCachedStack repaired, @NotNull MetaCachedStack repairMat);
+
+}
diff --git a/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilFunction.java b/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilFunction.java
index 93cf5b3..7a2c89a 100644
--- a/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilFunction.java
+++ b/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilFunction.java
@@ -1,16 +1,6 @@
package com.github.jikoo.planarenchanting.anvil;
-import com.github.jikoo.planarenchanting.enchant.EnchantData;
-import com.github.jikoo.planarenchanting.util.ItemUtil;
-import com.github.jikoo.planarenchanting.util.MetaCachedStack;
-import java.util.Objects;
-import org.bukkit.Material;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.inventory.meta.Damageable;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.inventory.meta.Repairable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/**
* An interface representing a portion of the functionality of an anvil. By using several in
@@ -18,275 +8,28 @@
*/
public interface AnvilFunction {
- /** Constant for adding the level cost from prior work. */
- AnvilFunction PRIOR_WORK_LEVEL_COST = new AnvilFunction() {
- @Override
- public boolean canApply(@NotNull AnvilOperation operation, @NotNull AnvilOperationState state) {
- return true;
- }
-
- @Override
- public @NotNull AnvilFunctionResult getResult(
- @NotNull AnvilOperation operation,
- @NotNull AnvilOperationState state) {
- return new AnvilFunctionResult() {
- @Override
- public int getLevelCostIncrease() {
- return ItemUtil.getRepairCost(state.getBase().getMeta())
- + ItemUtil.getRepairCost(state.getAddition().getMeta());
- }
- };
- }
- };
-
- /** Constant for adding the level cost for a renaming operation. */
- AnvilFunction RENAME = new AnvilFunction() {
- @Override
- public boolean canApply(@NotNull AnvilOperation operation, @NotNull AnvilOperationState state) {
- var itemMeta = state.getBase().getMeta();
-
- // If names are not the same, can be applied.
- return itemMeta != null
- && !Objects.equals(itemMeta.getDisplayName(), state.getAnvil().getRenameText());
- }
-
- @Override
- public @NotNull AnvilFunctionResult getResult(
- @NotNull AnvilOperation operation,
- @NotNull AnvilOperationState state) {
- return new AnvilFunctionResult() {
- @Override
- public int getLevelCostIncrease() {
- // Renames always apply a level cost of 1.
- return 1;
- }
-
- @Override
- public void modifyResult(@Nullable ItemMeta itemMeta) {
- if (itemMeta == null) {
- return;
- }
-
- itemMeta.setDisplayName(state.getAnvil().getRenameText());
- if (itemMeta instanceof Repairable repairable) {
- int repairCost = Math.max(
- ItemUtil.getRepairCost(state.getBase().getMeta()),
- ItemUtil.getRepairCost(state.getAddition().getMeta()));
- repairable.setRepairCost(repairCost);
- }
- }
- };
- }
- };
-
- /** Constant for updating prior work to new value. */
- AnvilFunction UPDATE_PRIOR_WORK_COST = new AnvilFunction() {
- @Override
- public boolean canApply(@NotNull AnvilOperation operation, @NotNull AnvilOperationState state) {
- return state.getBase().getMeta() instanceof Repairable;
- }
-
- @Override
- public @NotNull AnvilFunctionResult getResult(
- @NotNull AnvilOperation operation,
- @NotNull AnvilOperationState state) {
-
- return new AnvilFunctionResult() {
- @Override
- public int getLevelCostIncrease() {
- return 0;
- }
-
- @Override
- public void modifyResult(@Nullable ItemMeta itemMeta) {
- if (itemMeta instanceof Repairable repairable) {
- int priorRepairCost = Math.max(
- ItemUtil.getRepairCost(state.getBase().getMeta()),
- ItemUtil.getRepairCost(state.getAddition().getMeta()));
- repairable.setRepairCost(priorRepairCost * 2 + 1);
- }
- }
- };
- }
- };
-
- /** Constant for using materials to restore durability to the base item. */
- AnvilFunction REPAIR_WITH_MATERIAL = new AnvilFunction() {
- @Override
- public boolean canApply(@NotNull AnvilOperation operation, @NotNull AnvilOperationState state) {
- MetaCachedStack base = state.getBase();
- return operation.itemRepairedBy(base.getItem(), state.getAddition().getItem())
- && base.getItem().getType().getMaxDurability() > 0
- && base.getMeta() instanceof Damageable damageable
- && damageable.getDamage() > 0;
- }
-
- @Override
- public @NotNull AnvilFunctionResult getResult(
- @NotNull AnvilOperation operation,
- @NotNull AnvilOperationState state) {
- if (!(state.getBase().getMeta() instanceof Damageable damageable)) {
- // If result is not damageable, it cannot be repaired.
- return AnvilFunctionResult.EMPTY;
- }
-
- int missingDurability = damageable.getDamage();
-
- if (missingDurability < 1) {
- // If result is not damaged, no repair.
- return AnvilFunctionResult.EMPTY;
- }
-
- int repairs = 0;
- // Each repair removes up to 1/4 max durability in damage.
- int damageRepairedPerMaterial = state.getBase().getItem().getType().getMaxDurability() / 4;
-
- while (missingDurability > 0 && repairs < state.getAddition().getItem().getAmount()) {
- missingDurability -= damageRepairedPerMaterial;
- ++repairs;
- }
-
- // Finalize for later use.
- int totalRepairs = repairs;
- int resultDamage = Math.max(0, missingDurability);
-
- return new AnvilFunctionResult() {
- @Override
- public int getLevelCostIncrease() {
- return totalRepairs;
- }
-
- @Override
- public int getMaterialCostIncrease() {
- return totalRepairs;
- }
-
- @Override
- public void modifyResult(@Nullable ItemMeta itemMeta) {
- if (itemMeta instanceof Damageable damageable) {
- damageable.setDamage(resultDamage);
- }
- }
- };
- }
- };
-
- /** Constant for using identical materials to restore durability. */
- AnvilFunction REPAIR_WITH_COMBINATION = new AnvilFunction() {
- @Override
- public boolean canApply(@NotNull AnvilOperation operation, @NotNull AnvilOperationState state) {
- Material baseType = state.getBase().getItem().getType();
- return baseType == state.getAddition().getItem().getType()
- && baseType.getMaxDurability() > 0
- && state.getBase().getMeta() instanceof Damageable damageable
- && damageable.getDamage() > 0;
- }
-
- @Override
- public @NotNull AnvilFunctionResult getResult(
- @NotNull AnvilOperation operation,
- @NotNull AnvilOperationState state) {
- if (!(state.getBase().getMeta() instanceof Damageable baseDamageable
- && state.getAddition().getMeta() instanceof Damageable additionDamageable)) {
- return AnvilFunctionResult.EMPTY;
- }
-
- int missingDurability = baseDamageable.getDamage();
-
- if (missingDurability < 1) {
- return AnvilFunctionResult.EMPTY;
- }
-
- int maxDurability = state.getBase().getItem().getType().getMaxDurability();
- // Restore durability remaining in added item.
- int restoredDurability = maxDurability - additionDamageable.getDamage();
- // Add a bonus 12% total tool durability to the repair.
- restoredDurability += maxDurability * .12;
-
- // Finalize for later use.
- int resultDamage = Math.max(0, missingDurability - restoredDurability);
-
- return new AnvilFunctionResult() {
- @Override
- public int getLevelCostIncrease() {
- return 2;
- }
-
- @Override
- public void modifyResult(@Nullable ItemMeta itemMeta) {
- if (itemMeta instanceof Damageable damageable) {
- damageable.setDamage(resultDamage);
- }
- }
- };
- }
- };
-
- /** Constant for combining enchantments from source and target like Java Edition. */
- AnvilFunction COMBINE_ENCHANTMENTS_JAVA_EDITION = new CombineEnchantments() {
- @Override
- protected int getTotalCost(int baseCost, int oldLevel, int newLevel) {
- return baseCost * newLevel;
- }
-
- @Override
- protected int getNonApplicableCost() {
- return 1;
- }
- };
-
- /** Constant for combining enchantments from source and target like Bedrock Edition. */
- AnvilFunction COMBINE_ENCHANTMENTS_BEDROCK_EDITION = new CombineEnchantments() {
- @Override
- protected int getAnvilCost(Enchantment enchantment, boolean isFromBook) {
- EnchantData enchantData = EnchantData.of(enchantment);
- if (!enchantData.getSecondaryItems().isTagged(Material.TRIDENT)) {
- return super.getAnvilCost(enchantment, isFromBook);
- }
-
- int base = enchantData.getAnvilCost();
-
- // Bedrock Edition rarity is 1 tier lower for trident enchantments.
- return Math.max(1, isFromBook ? base / 4 : base / 2);
- }
-
- @Override
- protected int getTotalCost(int baseCost, int oldLevel, int newLevel) {
- if (oldLevel >= newLevel) {
- return 0;
- }
-
- return baseCost * (newLevel - oldLevel);
- }
-
- @Override
- protected int getNonApplicableCost() {
- return 0;
- }
- };
-
/**
* Check if the function is capable of generating a usable result. Note that this may be a quick
* cursory check - the function may yield an empty result even if it initially reported itself
* applicable. The only guarantee this method makes is that retrieving and using a result will not
* cause an error if its return value is respected.
*
- * @param operation the {@link AnvilOperation} being performed
- * @param state the {@link AnvilOperationState} the state of the {@code AnvilOperation} in use
+ * @param behavior the definition of behaviors for the anvil
+ * @param state the {@link AnvilState} the state of the {@code AnvilOperation} in use
* @return whether the {@link AnvilFunction} can generate an {@link AnvilFunctionResult}
*/
- boolean canApply(@NotNull AnvilOperation operation, @NotNull AnvilOperationState state);
+ boolean canApply(@NotNull AnvilBehavior behavior, @NotNull AnvilState state);
/**
* Get an {@link AnvilFunctionResult} used to apply the changes from the function based on the
* provided anvil operation state and settings.
*
- * @param operation the {@link AnvilOperation} being performed
- * @param state the {@link AnvilOperationState} the state of the anvil in use
+ * @param behavior the definition of behaviors for the anvil
+ * @param state the {@link AnvilState} the state of the anvil in use
* @return the resulting applicable changes
*/
@NotNull AnvilFunctionResult getResult(
- @NotNull AnvilOperation operation,
- @NotNull AnvilOperationState state);
+ @NotNull AnvilBehavior behavior,
+ @NotNull AnvilState state);
}
diff --git a/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilFunctions.java b/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilFunctions.java
new file mode 100644
index 0000000..0ccf9a2
--- /dev/null
+++ b/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilFunctions.java
@@ -0,0 +1,265 @@
+package com.github.jikoo.planarenchanting.anvil;
+
+import com.github.jikoo.planarenchanting.enchant.EnchantData;
+import com.github.jikoo.planarenchanting.util.ItemUtil;
+import com.github.jikoo.planarenchanting.util.MetaCachedStack;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.meta.Damageable;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.meta.Repairable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import java.util.Objects;
+
+public enum AnvilFunctions {
+ ; // Empty enum to hold constants.
+
+ /** Constant for adding the level cost from prior work. */
+ public static AnvilFunction PRIOR_WORK_LEVEL_COST = new AnvilFunction() {
+ @Override
+ public boolean canApply(@NotNull AnvilBehavior behavior, @NotNull AnvilState state) {
+ return true;
+ }
+
+ @Override
+ public @NotNull AnvilFunctionResult getResult(
+ @NotNull AnvilBehavior behavior,
+ @NotNull AnvilState state) {
+ return new AnvilFunctionResult() {
+ @Override
+ public int getLevelCostIncrease() {
+ return ItemUtil.getRepairCost(state.getBase().getMeta())
+ + ItemUtil.getRepairCost(state.getAddition().getMeta());
+ }
+ };
+ }
+ };
+
+ /** Constant for adding the level cost for a renaming operation. */
+ public static AnvilFunction RENAME = new AnvilFunction() {
+ @Override
+ public boolean canApply(@NotNull AnvilBehavior behavior, @NotNull AnvilState state) {
+ var itemMeta = state.getBase().getMeta();
+
+ // If names are not the same, can be applied.
+ return itemMeta != null
+ && !Objects.equals(itemMeta.getDisplayName(), state.getAnvil().getRenameText());
+ }
+
+ @Override
+ public @NotNull AnvilFunctionResult getResult(
+ @NotNull AnvilBehavior behavior,
+ @NotNull AnvilState state) {
+ return new AnvilFunctionResult() {
+ @Override
+ public int getLevelCostIncrease() {
+ // Renames always apply a level cost of 1.
+ return 1;
+ }
+
+ @Override
+ public void modifyResult(@Nullable ItemMeta itemMeta) {
+ if (itemMeta == null) {
+ return;
+ }
+
+ itemMeta.setDisplayName(state.getAnvil().getRenameText());
+ if (itemMeta instanceof Repairable repairable) {
+ int repairCost = Math.max(
+ ItemUtil.getRepairCost(state.getBase().getMeta()),
+ ItemUtil.getRepairCost(state.getAddition().getMeta()));
+ repairable.setRepairCost(repairCost);
+ }
+ }
+ };
+ }
+ };
+
+ /** Constant for updating prior work to new value. */
+ public static AnvilFunction UPDATE_PRIOR_WORK_COST = new AnvilFunction() {
+ @Override
+ public boolean canApply(@NotNull AnvilBehavior behavior, @NotNull AnvilState state) {
+ return state.getBase().getMeta() instanceof Repairable;
+ }
+
+ @Override
+ public @NotNull AnvilFunctionResult getResult(
+ @NotNull AnvilBehavior behavior,
+ @NotNull AnvilState state) {
+
+ return new AnvilFunctionResult() {
+ @Override
+ public int getLevelCostIncrease() {
+ return 0;
+ }
+
+ @Override
+ public void modifyResult(@Nullable ItemMeta itemMeta) {
+ if (itemMeta instanceof Repairable repairable) {
+ int priorRepairCost = Math.max(
+ ItemUtil.getRepairCost(state.getBase().getMeta()),
+ ItemUtil.getRepairCost(state.getAddition().getMeta()));
+ repairable.setRepairCost(priorRepairCost * 2 + 1);
+ }
+ }
+ };
+ }
+ };
+
+ /** Constant for using materials to restore durability to the base item. */
+ public static AnvilFunction REPAIR_WITH_MATERIAL = new AnvilFunction() {
+ @Override
+ public boolean canApply(@NotNull AnvilBehavior behavior, @NotNull AnvilState state) {
+ MetaCachedStack base = state.getBase();
+ return behavior.itemRepairedBy(base, state.getAddition())
+ && base.getItem().getType().getMaxDurability() > 0
+ && base.getMeta() instanceof Damageable damageable
+ && damageable.getDamage() > 0;
+ }
+
+ @Override
+ public @NotNull AnvilFunctionResult getResult(
+ @NotNull AnvilBehavior behavior,
+ @NotNull AnvilState state) {
+ if (!(state.getBase().getMeta() instanceof Damageable damageable)) {
+ // If result is not damageable, it cannot be repaired.
+ return AnvilFunctionResult.EMPTY;
+ }
+
+ int missingDurability = damageable.getDamage();
+
+ if (missingDurability < 1) {
+ // If result is not damaged, no repair.
+ return AnvilFunctionResult.EMPTY;
+ }
+
+ int repairs = 0;
+ // Each repair removes up to 1/4 max durability in damage.
+ int damageRepairedPerMaterial = state.getBase().getItem().getType().getMaxDurability() / 4;
+
+ while (missingDurability > 0 && repairs < state.getAddition().getItem().getAmount()) {
+ missingDurability -= damageRepairedPerMaterial;
+ ++repairs;
+ }
+
+ // Finalize for later use.
+ int totalRepairs = repairs;
+ int resultDamage = Math.max(0, missingDurability);
+
+ return new AnvilFunctionResult() {
+ @Override
+ public int getLevelCostIncrease() {
+ return totalRepairs;
+ }
+
+ @Override
+ public int getMaterialCostIncrease() {
+ return totalRepairs;
+ }
+
+ @Override
+ public void modifyResult(@Nullable ItemMeta itemMeta) {
+ if (itemMeta instanceof Damageable damageable) {
+ damageable.setDamage(resultDamage);
+ }
+ }
+ };
+ }
+ };
+
+ /** Constant for using identical materials to restore durability. */
+ public static AnvilFunction REPAIR_WITH_COMBINATION = new AnvilFunction() {
+ @Override
+ public boolean canApply(@NotNull AnvilBehavior behavior, @NotNull AnvilState state) {
+ Material baseType = state.getBase().getItem().getType();
+ return baseType == state.getAddition().getItem().getType()
+ && baseType.getMaxDurability() > 0
+ && state.getBase().getMeta() instanceof Damageable damageable
+ && damageable.getDamage() > 0;
+ }
+
+ @Override
+ public @NotNull AnvilFunctionResult getResult(
+ @NotNull AnvilBehavior behavior,
+ @NotNull AnvilState state) {
+ if (!(state.getBase().getMeta() instanceof Damageable baseDamageable
+ && state.getAddition().getMeta() instanceof Damageable additionDamageable)) {
+ return AnvilFunctionResult.EMPTY;
+ }
+
+ int missingDurability = baseDamageable.getDamage();
+
+ if (missingDurability < 1) {
+ return AnvilFunctionResult.EMPTY;
+ }
+
+ int maxDurability = state.getBase().getItem().getType().getMaxDurability();
+ // Restore durability remaining in added item.
+ int restoredDurability = maxDurability - additionDamageable.getDamage();
+ // Add a bonus 12% total tool durability to the repair.
+ restoredDurability += maxDurability * .12;
+
+ // Finalize for later use.
+ int resultDamage = Math.max(0, missingDurability - restoredDurability);
+
+ return new AnvilFunctionResult() {
+ @Override
+ public int getLevelCostIncrease() {
+ return 2;
+ }
+
+ @Override
+ public void modifyResult(@Nullable ItemMeta itemMeta) {
+ if (itemMeta instanceof Damageable damageable) {
+ damageable.setDamage(resultDamage);
+ }
+ }
+ };
+ }
+ };
+
+ /** Constant for combining enchantments from source and target like Java Edition. */
+ public static AnvilFunction COMBINE_ENCHANTMENTS_JAVA_EDITION = new CombineEnchantments() {
+ @Override
+ protected int getTotalCost(int baseCost, int oldLevel, int newLevel) {
+ return baseCost * newLevel;
+ }
+
+ @Override
+ protected int getNonApplicableCost() {
+ return 1;
+ }
+ };
+
+ /** Constant for combining enchantments from source and target like Bedrock Edition. */
+ public static AnvilFunction COMBINE_ENCHANTMENTS_BEDROCK_EDITION = new CombineEnchantments() {
+ @Override
+ protected int getAnvilCost(Enchantment enchantment, boolean isFromBook) {
+ EnchantData enchantData = EnchantData.of(enchantment);
+ if (!enchantData.getSecondaryItems().isTagged(Material.TRIDENT)) {
+ return super.getAnvilCost(enchantment, isFromBook);
+ }
+
+ int base = enchantData.getAnvilCost();
+
+ // Bedrock Edition rarity is 1 tier lower for trident enchantments.
+ return Math.max(1, isFromBook ? base / 4 : base / 2);
+ }
+
+ @Override
+ protected int getTotalCost(int baseCost, int oldLevel, int newLevel) {
+ if (oldLevel >= newLevel) {
+ return 0;
+ }
+
+ return baseCost * (newLevel - oldLevel);
+ }
+
+ @Override
+ protected int getNonApplicableCost() {
+ return 0;
+ }
+ };
+
+}
diff --git a/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilOperation.java b/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilOperation.java
deleted file mode 100644
index 294dd94..0000000
--- a/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilOperation.java
+++ /dev/null
@@ -1,196 +0,0 @@
-package com.github.jikoo.planarenchanting.anvil;
-
-import com.github.jikoo.planarenchanting.util.ItemUtil;
-import java.util.function.BiPredicate;
-import java.util.function.ToIntFunction;
-import org.bukkit.Material;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.view.AnvilView;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A container for data required to calculate an anvil combination.
- */
-public class AnvilOperation {
-
- private @NotNull BiPredicate<@NotNull Enchantment, @NotNull ItemStack> enchantApplies;
- private @NotNull BiPredicate<@NotNull Enchantment, @NotNull Enchantment> enchantsConflict;
- private @NotNull ToIntFunction<@NotNull Enchantment> enchantMaxLevel;
- private @NotNull BiPredicate<@NotNull ItemStack, @NotNull ItemStack> itemRepairedBy;
- private @NotNull BiPredicate<@NotNull ItemStack, @NotNull ItemStack> itemsCombineEnchants;
-
- /**
- * Construct a new {@code AnvilOperation}.
- */
- public AnvilOperation() {
- this.enchantApplies = Enchantment::canEnchantItem;
- this.enchantsConflict = Enchantment::conflictsWith;
- this.enchantMaxLevel = Enchantment::getMaxLevel;
- this.itemRepairedBy = RepairMaterial::repairs;
- this.itemsCombineEnchants = (base, addition) ->
- base.getType() == addition.getType()
- || addition.getType() == Material.ENCHANTED_BOOK;
- }
-
- /**
- * Get whether an {@link Enchantment} is applicable for an {@link ItemStack}.
- *
- * @param enchantment the {@code Enchantment} to check for applicability
- * @param itemStack the item that may be enchanted
- * @return whether the {@code Enchantment} can be applied
- */
- public boolean enchantApplies(@NotNull Enchantment enchantment, @NotNull ItemStack itemStack) {
- return this.enchantApplies.test(enchantment, itemStack);
- }
-
- /**
- * Set the method for determining if an {@link Enchantment} is applicable for an
- * {@link ItemStack}.
- *
- * @param enchantApplies the method for determining if an {@code Enchantment} is applicable
- */
- public void setEnchantApplies(
- @NotNull BiPredicate<@NotNull Enchantment, @NotNull ItemStack> enchantApplies) {
- this.enchantApplies = enchantApplies;
- }
-
- /**
- * Get the method for determining if {@link Enchantment Enchantments} conflict.
- *
- * @return whether the {@code Enchantments} conflict
- */
- public boolean enchantsConflict(@NotNull Enchantment enchant1, @NotNull Enchantment enchant2) {
- return this.enchantsConflict.test(enchant1, enchant2);
- }
-
- /**
- * Set the method for determining if {@link Enchantment Enchantments} conflict.
- *
- * @param enchantsConflict the method for determining if {@code Enchantments} conflict
- */
- public void setEnchantsConflict(
- @NotNull BiPredicate<@NotNull Enchantment, @NotNull Enchantment> enchantsConflict) {
- this.enchantsConflict = enchantsConflict;
- }
-
- /**
- * Get the method supplying maximum level for an {@link Enchantment}.
- *
- * @return the method supplying maximum level for an {@code Enchantment}
- */
- public int getEnchantMaxLevel(@NotNull Enchantment enchantment) {
- return this.enchantMaxLevel.applyAsInt(enchantment);
- }
-
- /**
- * Set the method supplying maximum level for an {@link Enchantment}.
- *
- * @param enchantMaxLevel the method supplying maximum level for an {@code Enchantment}
- */
- public void setEnchantMaxLevel(@NotNull ToIntFunction<@NotNull Enchantment> enchantMaxLevel) {
- this.enchantMaxLevel = enchantMaxLevel;
- }
-
- /**
- * Get whether an item should combine its {@link Enchantment Enchantments} with another item.
- *
- * @param base the base item
- * @param addition the item added
- * @return whether items should combine {@code Enchantments}
- */
- public boolean itemsCombineEnchants(@NotNull ItemStack base, @NotNull ItemStack addition) {
- return this.itemsCombineEnchants.test(base, addition);
- }
-
- /**
- * Set the method determining whether an item should combine its {@link Enchantment Enchantments}
- * with another item.
- *
- * @param itemsCombineEnchants the method determining whether an item should combine its
- * {@code Enchantments}
- */
- public void setItemsCombineEnchants(
- @NotNull BiPredicate<@NotNull ItemStack, @NotNull ItemStack> itemsCombineEnchants) {
- this.itemsCombineEnchants = itemsCombineEnchants;
- }
-
- /**
- * Get whether an item is repaired by another item.
- *
- * @see #setItemRepairedBy
- * @param repaired the item repaired
- * @param repairMat the item used to repair
- * @return the method determining whether an item is repaired by another item
- */
- public boolean itemRepairedBy(@NotNull ItemStack repaired, @NotNull ItemStack repairMat) {
- return this.itemRepairedBy.test(repaired, repairMat);
- }
-
- /**
- * Set the method determining whether an item is repaired by another item. This is not the same as
- * a repair via combination of like items! Like items always attempt to combine durability. If
- * you require different behavior, override {@link #apply(AnvilView)} and do not call
- * {@link AnvilFunction#REPAIR_WITH_COMBINATION}.
- *
- *
N.B. Only {@link org.bukkit.inventory.meta.Damageable Damageable} items can be repaired.
- * A material repair restores 25% of the durability of an item per material consumed.
- *
- * @param itemRepairedBy the method determining whether an item is repaired by another item
- */
- public void setItemRepairedBy(
- @NotNull BiPredicate<@NotNull ItemStack, @NotNull ItemStack> itemRepairedBy) {
- this.itemRepairedBy = itemRepairedBy;
- }
-
- /**
- * Get an {@link AnvilResult} for this anvil operation.
- *
- * @return the {@code AnvilResult}
- */
- public @NotNull AnvilResult apply(@NotNull AnvilView view) {
- AnvilOperationState state = new AnvilOperationState(this, view);
-
- if (ItemUtil.isEmpty(state.getBase().getItem())) {
- return AnvilResult.EMPTY;
- }
-
- // Apply base cost.
- state.apply(AnvilFunction.PRIOR_WORK_LEVEL_COST);
-
- if (ItemUtil.isEmpty(state.getAddition().getItem())) {
- if (state.apply(AnvilFunction.RENAME)) {
- // If the only thing occurring is a renaming operation, it is always allowed.
- state.setLevelCost(Math.min(state.getLevelCost(), state.getAnvil().getMaximumRepairCost() - 1));
- }
-
- // No addition means no additional operations to perform.
- return state.forge();
- }
-
-
- if (state.getBase().getItem().getAmount() != 1) {
- // Multi-renames are allowed, multi-modifications are not.
- // Vanilla allows multi-modifications "for creative" but the way it does it is problematic.
- return AnvilResult.EMPTY;
- }
-
- state.apply(AnvilFunction.RENAME);
- // Apply prior work cost after rename.
- // Rename also applies a prior work cost but does not increase it.
- state.apply(AnvilFunction.UPDATE_PRIOR_WORK_COST);
-
- if (!state.apply(AnvilFunction.REPAIR_WITH_MATERIAL)) {
- // Only do combination repair if this is not a material repair.
- state.apply(AnvilFunction.REPAIR_WITH_COMBINATION);
- }
-
- // Differing from vanilla - since we use a custom determination for whether enchantments should
- // transfer (which defaults to indirectly mimicking vanilla), enchantments may need to be
- // applied from a material repair.
- state.apply(AnvilFunction.COMBINE_ENCHANTMENTS_JAVA_EDITION);
-
- return state.forge();
- }
-
-}
diff --git a/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilOperationState.java b/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilState.java
similarity index 90%
rename from src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilOperationState.java
rename to src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilState.java
index 5d1da22..862c70e 100644
--- a/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilOperationState.java
+++ b/src/main/java/com/github/jikoo/planarenchanting/anvil/AnvilState.java
@@ -11,9 +11,9 @@
/**
* A mutable data holder similar to an {@link AnvilResult}.
*/
-public class AnvilOperationState {
+public class AnvilState {
- private final @NotNull AnvilOperation operation;
+ private final @NotNull AnvilBehavior behavior;
private final @NotNull AnvilView view;
private final @NotNull MetaCachedStack base;
private final @NotNull MetaCachedStack addition;
@@ -24,11 +24,11 @@ public class AnvilOperationState {
/**
* Create an {@code AnvilOperationState} instance for the given operation and inventory.
*
- * @param operation the {@link AnvilOperation} mutating the state
+ * @param behavior the {@link AnvilBehavior} mutating the state
* @param view the {@link AnvilView} the state is derived from
*/
- public AnvilOperationState(@NotNull AnvilOperation operation, @NotNull AnvilView view) {
- this.operation = operation;
+ public AnvilState(@NotNull AnvilBehavior behavior, @NotNull AnvilView view) {
+ this.behavior = behavior;
this.view = view;
this.base = new MetaCachedStack(this.view.getItem(0));
this.addition = new MetaCachedStack(this.view.getItem(1));
@@ -103,16 +103,16 @@ public void setMaterialCost(int materialCost) {
* Note that a function reporting itself applicable does not guarantee that the result or costs
* will actually differ.
*
- * @see AnvilFunction#canApply(AnvilOperation, AnvilOperationState)
+ * @see AnvilFunction#canApply(AnvilBehavior, AnvilState)
* @param function the {@code AnvilFunction} to apply
* @return whether the {@link AnvilFunction} could apply
*/
public boolean apply(@NotNull AnvilFunction function) {
- if (!function.canApply(this.operation, this)) {
+ if (!function.canApply(this.behavior, this)) {
return false;
}
- AnvilFunctionResult anvilResult = function.getResult(this.operation, this);
+ AnvilFunctionResult anvilResult = function.getResult(this.behavior, this);
anvilResult.modifyResult(this.result.getMeta());
this.levelCost += anvilResult.getLevelCostIncrease();
diff --git a/src/main/java/com/github/jikoo/planarenchanting/anvil/CombineEnchantments.java b/src/main/java/com/github/jikoo/planarenchanting/anvil/CombineEnchantments.java
index 3d74443..7c8b98a 100644
--- a/src/main/java/com/github/jikoo/planarenchanting/anvil/CombineEnchantments.java
+++ b/src/main/java/com/github/jikoo/planarenchanting/anvil/CombineEnchantments.java
@@ -14,14 +14,14 @@
abstract class CombineEnchantments implements AnvilFunction {
@Override
- public boolean canApply(@NotNull AnvilOperation operation, @NotNull AnvilOperationState state) {
- return operation.itemsCombineEnchants(state.getBase().getItem(), state.getAddition().getItem());
+ public boolean canApply(@NotNull AnvilBehavior behavior, @NotNull AnvilState state) {
+ return behavior.itemsCombineEnchants(state.getBase(), state.getAddition());
}
@Override
public final @NotNull AnvilFunctionResult getResult(
- @NotNull AnvilOperation operation,
- @NotNull AnvilOperationState state) {
+ @NotNull AnvilBehavior behavior,
+ @NotNull AnvilState state) {
Map baseEnchants = EnchantmentUtil.getEnchants(
state.getBase().getMeta());
Map additionEnchants = EnchantmentUtil.getEnchants(
@@ -39,15 +39,15 @@ public boolean canApply(@NotNull AnvilOperation operation, @NotNull AnvilOperati
Enchantment newEnchantment = enchantEntry.getKey();
int oldLevel = baseEnchants.getOrDefault(newEnchantment, 0);
int baseCost = getAnvilCost(newEnchantment, isFromBook);
- if (operation.enchantApplies(newEnchantment, state.getBase().getItem())
+ if (behavior.enchantApplies(newEnchantment, state.getBase())
&& baseEnchants.keySet().stream()
.noneMatch(existingEnchant ->
!existingEnchant.getKey().equals(newEnchantment.getKey())
- && operation.enchantsConflict(existingEnchant, newEnchantment))) {
+ && behavior.enchantsConflict(existingEnchant, newEnchantment))) {
int addedLevel = enchantEntry.getValue();
int newLevel = oldLevel == addedLevel ? addedLevel + 1 : Math.max(oldLevel, addedLevel);
- newLevel = Math.min(newLevel, operation.getEnchantMaxLevel(newEnchantment));
+ newLevel = Math.min(newLevel, behavior.getEnchantMaxLevel(newEnchantment));
newEnchants.put(newEnchantment, newLevel);
levelCost += getTotalCost(baseCost, oldLevel, newLevel);
diff --git a/src/main/java/com/github/jikoo/planarenchanting/anvil/VanillaAnvil.java b/src/main/java/com/github/jikoo/planarenchanting/anvil/VanillaAnvil.java
new file mode 100644
index 0000000..c3da525
--- /dev/null
+++ b/src/main/java/com/github/jikoo/planarenchanting/anvil/VanillaAnvil.java
@@ -0,0 +1,100 @@
+package com.github.jikoo.planarenchanting.anvil;
+
+import com.github.jikoo.planarenchanting.util.ItemUtil;
+import com.github.jikoo.planarenchanting.util.MetaCachedStack;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.view.AnvilView;
+import org.jetbrains.annotations.NotNull;
+
+public class VanillaAnvil {
+
+ public static final AnvilBehavior BEHAVIOR = new AnvilBehavior() {
+ @Override
+ public boolean enchantApplies(@NotNull Enchantment enchantment, @NotNull MetaCachedStack base) {
+ return enchantment.canEnchantItem(base.getItem());
+ }
+
+ @Override
+ public boolean enchantsConflict(@NotNull Enchantment enchant1, @NotNull Enchantment enchant2) {
+ return enchant1.conflictsWith(enchant2);
+ }
+
+ @Override
+ public int getEnchantMaxLevel(@NotNull Enchantment enchantment) {
+ return enchantment.getMaxLevel();
+ }
+
+ @Override
+ public boolean itemsCombineEnchants(@NotNull MetaCachedStack base, @NotNull MetaCachedStack addition) {
+ Material additionType = addition.getItem().getType();
+ return base.getItem().getType() == additionType || additionType == Material.ENCHANTED_BOOK;
+ }
+
+ @Override
+ public boolean itemRepairedBy(@NotNull MetaCachedStack repaired, @NotNull MetaCachedStack repairMat) {
+ return RepairMaterial.repairs(repaired.getItem(), repairMat.getItem());
+ }
+ };
+
+ private final @NotNull AnvilBehavior behavior;
+
+ public VanillaAnvil() {
+ this(BEHAVIOR);
+ }
+
+ public VanillaAnvil(@NotNull AnvilBehavior behavior) {
+ this.behavior = behavior;
+ }
+
+ /**
+ * Get an {@link AnvilResult} for this anvil operation.
+ *
+ * @return the {@code AnvilResult}
+ */
+ public @NotNull AnvilResult getResult(@NotNull AnvilView view) {
+ AnvilState state = new AnvilState(behavior, view);
+
+ if (ItemUtil.isEmpty(state.getBase().getItem())) {
+ return AnvilResult.EMPTY;
+ }
+
+ // Apply base cost.
+ state.apply(AnvilFunctions.PRIOR_WORK_LEVEL_COST);
+
+ if (ItemUtil.isEmpty(state.getAddition().getItem())) {
+ if (state.apply(AnvilFunctions.RENAME)) {
+ // If the only thing occurring is a renaming operation, it is always allowed.
+ state.setLevelCost(Math.min(state.getLevelCost(), state.getAnvil().getMaximumRepairCost() - 1));
+ }
+
+ // No addition means no additional operations to perform.
+ return state.forge();
+ }
+
+
+ if (state.getBase().getItem().getAmount() != 1) {
+ // Multi-renames are allowed, multi-modifications are not.
+ // Vanilla allows multi-modifications "for creative" but the way it does it is problematic.
+ return AnvilResult.EMPTY;
+ }
+
+ state.apply(AnvilFunctions.RENAME);
+ // Apply prior work cost after rename.
+ // Rename also applies a prior work cost but does not increase it.
+ state.apply(AnvilFunctions.UPDATE_PRIOR_WORK_COST);
+
+ if (!state.apply(AnvilFunctions.REPAIR_WITH_MATERIAL)) {
+ // Only do combination repair if this is not a material repair.
+ state.apply(AnvilFunctions.REPAIR_WITH_COMBINATION);
+ }
+
+ // Differing from vanilla - since we use a custom determination for whether enchantments should
+ // transfer (which defaults to indirectly mimicking vanilla), enchantments may need to be
+ // applied from a material repair.
+ state.apply(AnvilFunctions.COMBINE_ENCHANTMENTS_JAVA_EDITION);
+
+ return state.forge();
+ }
+
+}
diff --git a/src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilFunctionTest.java b/src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilFunctionTest.java
index 4891100..40bcf4c 100644
--- a/src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilFunctionTest.java
+++ b/src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilFunctionTest.java
@@ -12,9 +12,11 @@
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import com.github.jikoo.planarenchanting.anvil.mock.ReadableResultState;
@@ -79,15 +81,15 @@ void beforeAll() {
@Nested
class PriorWorkLevelCost {
- private final AnvilFunction function = AnvilFunction.PRIOR_WORK_LEVEL_COST;
+ private final AnvilFunction function = AnvilFunctions.PRIOR_WORK_LEVEL_COST;
@Test
void testPriorWorkLevelCostApplies() {
var anvil = getMockView(new ItemStack(BASE_MAT), new ItemStack(BASE_MAT));
- var operation = new AnvilOperation();
- var state = new AnvilOperationState(operation, anvil);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new AnvilState(behavior, anvil);
- assertThat("Prior work level cost always applies", function.canApply(operation, state));
+ assertThat("Prior work level cost always applies", function.canApply(behavior, state));
}
@ParameterizedTest
@@ -97,12 +99,12 @@ void testPriorWorkLevelCostValues(int baseWork, int addedWork) {
var anvil = getMockView(
prepareItem(baseItem, 0, baseWork),
prepareItem(new ItemStack(BASE_MAT), 0, addedWork));
- var operation = new AnvilOperation();
- var state = new ReadableResultState(operation, anvil);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new ReadableResultState(behavior, anvil);
- assertThat("Prior work level cost always applies", function.canApply(operation, state));
+ assertThat("Prior work level cost always applies", function.canApply(behavior, state));
- var result = function.getResult(operation, state);
+ var result = function.getResult(behavior, state);
assertThat(
"Cost must be total prior work",
result.getLevelCostIncrease(),
@@ -135,18 +137,18 @@ void testPriorWorkLevelCostValues(int baseWork, int addedWork) {
@TestInstance(Lifecycle.PER_CLASS) // Should be inherited but isn't for whatever reason
class Rename {
- private final AnvilFunction function = AnvilFunction.RENAME;
+ private final AnvilFunction function = AnvilFunctions.RENAME;
@DisplayName("Rename requires ItemMeta")
@Test
void testRenameRequiresMeta() {
var base = getNullMetaItem();
var inventory = getMockView(base, null);
- var operation = new AnvilOperation();
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new AnvilState(behavior, inventory);
assertThat("Base meta is null", state.getBase().getMeta(), is(nullValue()));
- assertThat("Rename requires meta", function.canApply(operation, state), is(false));
+ assertThat("Rename requires meta", function.canApply(behavior, state), is(false));
}
@DisplayName("Rename requires different name")
@@ -157,14 +159,14 @@ void testRenameRequiresDifferentName(
boolean canApply) {
var base = new ItemStack(BASE_MAT);
var inventory = getMockView(base, null);
- var operation = new AnvilOperation();
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new AnvilState(behavior, inventory);
assertThat("Base meta is not null", state.getBase().getMeta(), is(notNullValue()));
setup.accept(state.getBase().getMeta(), inventory);
- assertThat("Rename requires different name", function.canApply(operation, state), is(canApply));
+ assertThat("Rename requires different name", function.canApply(behavior, state), is(canApply));
}
@DisplayName("Rename applies name and cost")
@@ -179,10 +181,10 @@ void testRenameApplication(BiConsumer setup) {
base.setItemMeta(baseMeta);
inventory.setItem(0, base);
- var operation = new AnvilOperation();
- var state = new ReadableResultState(operation, inventory);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new ReadableResultState(behavior, inventory);
- AnvilFunctionResult result = function.getResult(operation, state);
+ AnvilFunctionResult result = function.getResult(behavior, state);
assertThat("Level cost increase is 1", result.getLevelCostIncrease(), is(1));
result.modifyResult(state.getResult().getMeta());
@@ -236,18 +238,18 @@ private Stream renameSituations() {
@Nested
class UpdatePriorWorkCost {
- private final AnvilFunction function = AnvilFunction.UPDATE_PRIOR_WORK_COST;
+ private final AnvilFunction function = AnvilFunctions.UPDATE_PRIOR_WORK_COST;
@Test
void testBaseNotRepairable() {
var base = getNullMetaItem();
var inventory = getMockView(base, null);
- var operation = new AnvilOperation();
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new AnvilState(behavior, inventory);
assertThat(
"Base must be repairable",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(false));
}
@@ -256,12 +258,12 @@ void testBaseRepairable() {
var base = new ItemStack(BASE_MAT);
var addition = getNullMetaItem();
var inventory = getMockView(base, addition);
- var operation = new AnvilOperation();
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new AnvilState(behavior, inventory);
assertThat(
"Repairable base is acceptable",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(true));
}
@@ -272,12 +274,12 @@ void testPriorWorkUpdate(int baseWork, int addedWork) {
var anvil = getMockView(
prepareItem(baseItem, 0, baseWork),
prepareItem(new ItemStack(BASE_MAT), 0, addedWork));
- var operation = new AnvilOperation();
- var state = new ReadableResultState(operation, anvil);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new ReadableResultState(behavior, anvil);
- assertThat("Prior work level cost always applies", function.canApply(operation, state));
+ assertThat("Prior work level cost always applies", function.canApply(behavior, state));
- var result = function.getResult(operation, state);
+ var result = function.getResult(behavior, state);
assertThat("Cost must be unchanged", result.getLevelCostIncrease(), is(0));
assertThat("Material cost is unchanged", result.getMaterialCostIncrease(), is(0));
@@ -302,10 +304,10 @@ void testPriorWorkUpdate(int baseWork, int addedWork) {
void testMetaNotRepairable() {
var base = getNullMetaItem();
var inventory = getMockView(base, null);
- var operation = new AnvilOperation();
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new AnvilState(behavior, inventory);
- var result = function.getResult(operation, state);
+ var result = function.getResult(behavior, state);
assertDoesNotThrow(() -> result.modifyResult(base.getItemMeta()));
}
@@ -314,31 +316,31 @@ void testMetaNotRepairable() {
@Nested
class RepairWithMaterial {
- private final AnvilFunction function = AnvilFunction.REPAIR_WITH_MATERIAL;
+ private final AnvilFunction function = AnvilFunctions.REPAIR_WITH_MATERIAL;
@Test
void testCanApplyNotRepairedBy() {
var inventory = getMockView(null, null);
- var operation = new AnvilOperation();
- operation.setItemRepairedBy((item1, item2) -> false);
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = spy(VanillaAnvil.BEHAVIOR);
+ doReturn(false).when(behavior).itemRepairedBy(notNull(), notNull());
+ var state = new AnvilState(behavior, inventory);
assertThat(
"Must be repairable by item",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(false));
}
@Test
void testCanApplyNotDurable() {
var inventory = getMockView(null, null);
- var operation = new AnvilOperation();
- operation.setItemRepairedBy((item1, item2) -> true);
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = spy(VanillaAnvil.BEHAVIOR);
+ doReturn(true).when(behavior).itemRepairedBy(notNull(), notNull());
+ var state = new AnvilState(behavior, inventory);
assertThat(
"Must have durability",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(false));
}
@@ -347,34 +349,34 @@ void testCanApplyNotDamageable() {
var base = getNullMetaItem();
base.setType(BASE_MAT);
var inventory = getMockView(base, null);
- var operation = new AnvilOperation();
- operation.setItemRepairedBy((item1, item2) -> true);
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = spy(VanillaAnvil.BEHAVIOR);
+ doReturn(true).when(behavior).itemRepairedBy(notNull(), notNull());
+ var state = new AnvilState(behavior, inventory);
assertThat(
"Must have Damageable meta",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(false));
assertThat(
"Non-Damageable must return empty result",
- function.getResult(operation, state),
+ function.getResult(behavior, state),
is(AnvilFunctionResult.EMPTY));
}
@Test
void testCanApplyNotDamaged() {
var inventory = getMockView(new ItemStack(BASE_MAT), null);
- var operation = new AnvilOperation();
- operation.setItemRepairedBy((item1, item2) -> true);
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = spy(VanillaAnvil.BEHAVIOR);
+ doReturn(true).when(behavior).itemRepairedBy(notNull(), notNull());
+ var state = new AnvilState(behavior, inventory);
assertThat(
"Must be damaged",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(false));
assertThat(
"Undamaged must return empty result",
- function.getResult(operation, state),
+ function.getResult(behavior, state),
is(AnvilFunctionResult.EMPTY));
}
@@ -383,16 +385,16 @@ void testCanApplyNotDamaged() {
void testRepair(int repairMats) {
var baseItem = getMaxDamageItem();
var inventory = getMockView(baseItem, new ItemStack(REPAIR_MAT, repairMats));
- var operation = new AnvilOperation();
- operation.setItemRepairedBy((item1, item2) -> true);
- var state = new ReadableResultState(operation, inventory);
+ var behavior = spy(VanillaAnvil.BEHAVIOR);
+ doReturn(true).when(behavior).itemRepairedBy(notNull(), notNull());
+ var state = new ReadableResultState(behavior, inventory);
assertThat(
"Must be applicable",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(true));
- AnvilFunctionResult result = function.getResult(operation, state);
+ AnvilFunctionResult result = function.getResult(behavior, state);
result.modifyResult(state.getResult().getMeta());
@@ -428,29 +430,29 @@ void testRepair(int repairMats) {
@Nested
class RepairWithCombination {
- private final AnvilFunction function = AnvilFunction.REPAIR_WITH_COMBINATION;
+ private final AnvilFunction function = AnvilFunctions.REPAIR_WITH_COMBINATION;
@Test
void testCanApplyNotRepairedBy() {
var inventory = getMockView(new ItemStack(BASE_MAT), new ItemStack(REPAIR_MAT));
- var operation = new AnvilOperation();
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new AnvilState(behavior, inventory);
assertThat(
"Must be same item",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(false));
}
@Test
void testCanApplyNotDurable() {
var inventory = getMockView(null, null);
- var operation = new AnvilOperation();
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new AnvilState(behavior, inventory);
assertThat(
"Must have durability",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(false));
}
@@ -460,39 +462,38 @@ void testCanApplyNotDamageable() {
nullMetaItem.setType(BASE_MAT);
ItemStack normalItem = new ItemStack(BASE_MAT);
var inventory = getMockView(nullMetaItem, normalItem);
- var operation = new AnvilOperation();
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new AnvilState(behavior, inventory);
assertThat(
"Must have Damageable meta",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(false));
assertThat(
"Non-Damageable base must return empty result",
- function.getResult(operation, state),
+ function.getResult(behavior, state),
is(AnvilFunctionResult.EMPTY));
inventory = getMockView(normalItem, nullMetaItem);
- operation = new AnvilOperation();
- state = new AnvilOperationState(operation, inventory);
+ state = new AnvilState(behavior, inventory);
assertThat(
"Non-Damageable addition must return empty result",
- function.getResult(operation, state),
+ function.getResult(behavior, state),
is(AnvilFunctionResult.EMPTY));
}
@Test
void testCanApplyNotDamaged() {
var inventory = getMockView(new ItemStack(BASE_MAT), new ItemStack(BASE_MAT));
- var operation = new AnvilOperation();
- var state = new AnvilOperationState(operation, inventory);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new AnvilState(behavior, inventory);
assertThat(
"Must be damaged",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(false));
assertThat(
"Undamaged must return empty result",
- function.getResult(operation, state),
+ function.getResult(behavior, state),
is(AnvilFunctionResult.EMPTY));
}
@@ -500,15 +501,15 @@ void testCanApplyNotDamaged() {
void testRepair() {
var baseItem = getMaxDamageItem();
var inventory = getMockView(baseItem, baseItem.clone());
- var operation = new AnvilOperation();
- var state = new ReadableResultState(operation, inventory);
+ var behavior = VanillaAnvil.BEHAVIOR;
+ var state = new ReadableResultState(behavior, inventory);
assertThat(
"Must be applicable",
- function.canApply(operation, state),
+ function.canApply(behavior, state),
is(true));
- AnvilFunctionResult result = function.getResult(operation, state);
+ AnvilFunctionResult result = function.getResult(behavior, state);
result.modifyResult(state.getResult().getMeta());
diff --git a/src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilOperationStateTest.java b/src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilStateTest.java
similarity index 88%
rename from src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilOperationStateTest.java
rename to src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilStateTest.java
index 429ecba..98e1b0a 100644
--- a/src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilOperationStateTest.java
+++ b/src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilStateTest.java
@@ -37,9 +37,9 @@
@DisplayName("Verify AnvilOperationState functionality")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
-class AnvilOperationStateTest {
+class AnvilStateTest {
- private AnvilOperation operation;
+ private AnvilBehavior operation;
private AnvilView view;
@BeforeAll
@@ -62,7 +62,7 @@ void beforeAll() {
@BeforeEach
void beforeEach() {
- operation = new AnvilOperation();
+ operation = VanillaAnvil.BEHAVIOR;
var anvil = InventoryMocks.newAnvilMock();
view = mock(AnvilView.class);
@@ -76,7 +76,7 @@ void beforeEach() {
@Test
void testGetAnvil() {
- var state = new AnvilOperationState(operation, view);
+ var state = new AnvilState(operation, view);
assertThat("Anvil must be provided instance", state.getAnvil(), is(view));
}
@@ -84,7 +84,7 @@ void testGetAnvil() {
void testBase() {
var base = new ItemStack(Material.DIRT);
view.setItem(0, base);
- var state = new AnvilOperationState(operation, view);
+ var state = new AnvilState(operation, view);
assertThat("Base item must match", state.getBase().getItem(), is(base));
}
@@ -92,13 +92,13 @@ void testBase() {
void testAddition() {
var addition = new ItemStack(Material.DIRT);
view.setItem(1, addition);
- var state = new AnvilOperationState(operation, view);
+ var state = new AnvilState(operation, view);
assertThat("Addition item must match", state.getAddition().getItem(), is(addition));
}
@Test
void testGetSetLevelCost() {
- var state = new AnvilOperationState(operation, view);
+ var state = new AnvilState(operation, view);
assertThat("Level cost starts at 0", state.getLevelCost(), is(0));
int value = 10;
state.setLevelCost(value);
@@ -107,7 +107,7 @@ void testGetSetLevelCost() {
@Test
void testGetSetMaterialCost() {
- var state = new AnvilOperationState(operation, view);
+ var state = new AnvilState(operation, view);
assertThat("Material cost starts at 0", state.getMaterialCost(), is(0));
int value = 10;
state.setMaterialCost(value);
@@ -119,15 +119,15 @@ void testApplyNonApplicable() {
var function = new AnvilFunction() {
@Override
public boolean canApply(
- @NotNull AnvilOperation operation,
- @NotNull AnvilOperationState state) {
+ @NotNull AnvilBehavior behavior,
+ @NotNull AnvilState state) {
return false;
}
@Override
public @NotNull AnvilFunctionResult getResult(
- @NotNull AnvilOperation operation,
- @NotNull AnvilOperationState state) {
+ @NotNull AnvilBehavior behavior,
+ @NotNull AnvilState state) {
return new AnvilFunctionResult() {
@Override
public int getLevelCostIncrease() {
@@ -142,7 +142,7 @@ public int getMaterialCostIncrease() {
}
};
- var state = new AnvilOperationState(operation, view);
+ var state = new AnvilState(operation, view);
assertThat(
"Non-applicable function does not apply",
state.apply(function),
@@ -157,15 +157,15 @@ void testApply() {
var function = new AnvilFunction() {
@Override
public boolean canApply(
- @NotNull AnvilOperation operation,
- @NotNull AnvilOperationState state) {
+ @NotNull AnvilBehavior behavior,
+ @NotNull AnvilState state) {
return true;
}
@Override
public @NotNull AnvilFunctionResult getResult(
- @NotNull AnvilOperation operation,
- @NotNull AnvilOperationState state) {
+ @NotNull AnvilBehavior behavior,
+ @NotNull AnvilState state) {
return new AnvilFunctionResult() {
@Override
public int getLevelCostIncrease() {
@@ -180,7 +180,7 @@ public int getMaterialCostIncrease() {
}
};
- var state = new AnvilOperationState(operation, view);
+ var state = new AnvilState(operation, view);
assertThat("Applicable function applies", state.apply(function));
assertThat("Level cost is added", state.getLevelCost(), is(value));
@@ -200,7 +200,7 @@ void testForgeNullBaseMeta() {
}
});
- var state = new AnvilOperationState(operation, view);
+ var state = new AnvilState(operation, view);
assertThat("AnvilResult must be empty constant", state.forge(), is(AnvilResult.EMPTY));
}
@@ -224,7 +224,7 @@ void testForgeNullResultMeta() {
}
});
- var state = new AnvilOperationState(operation, view) {
+ var state = new AnvilState(operation, view) {
private final MetaCachedStack fakeBase = new MetaCachedStack(new ItemStack(Material.DIRT));
@Override
public @NotNull MetaCachedStack getBase() {
diff --git a/src/test/java/com/github/jikoo/planarenchanting/anvil/CombineEnchantmentsTest.java b/src/test/java/com/github/jikoo/planarenchanting/anvil/CombineEnchantmentsTest.java
index 548329b..a0385b6 100644
--- a/src/test/java/com/github/jikoo/planarenchanting/anvil/CombineEnchantmentsTest.java
+++ b/src/test/java/com/github/jikoo/planarenchanting/anvil/CombineEnchantmentsTest.java
@@ -11,9 +11,11 @@
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
@@ -105,33 +107,33 @@ protected CombineEnchantsTest(AnvilFunction function) {
@Test
void testAppliesIfNotCombine() {
var anvil = getMockView(new ItemStack(BASE_MAT), new ItemStack(BASE_MAT));
- var operation = new AnvilOperation();
- operation.setItemsCombineEnchants(((itemStack, itemStack2) -> false));
- var state = new AnvilOperationState(operation, anvil);
+ var behavior = spy(VanillaAnvil.BEHAVIOR);
+ doReturn(false).when(behavior).itemsCombineEnchants(notNull(), notNull());
+ var state = new AnvilState(behavior, anvil);
- assertThat("Combination must not apply", function.canApply(operation, state), is(false));
+ assertThat("Combination must not apply", function.canApply(behavior, state), is(false));
}
@Test
void testAppliesIfCombine() {
var anvil = getMockView(new ItemStack(BASE_MAT), new ItemStack(BASE_MAT));
- var operation = new AnvilOperation();
- operation.setItemsCombineEnchants(((itemStack, itemStack2) -> true));
- var state = new AnvilOperationState(operation, anvil);
+ var behavior = spy(VanillaAnvil.BEHAVIOR);
+ doReturn(true).when(behavior).itemsCombineEnchants(notNull(), notNull());
+ var state = new AnvilState(behavior, anvil);
- assertThat("Combination must apply", function.canApply(operation, state));
+ assertThat("Combination must apply", function.canApply(behavior, state));
}
@Test
void testNoEnchantsAdded() {
var anvil = getMockView(new ItemStack(BASE_MAT), new ItemStack(BASE_MAT));
- var operation = new AnvilOperation();
- operation.setItemsCombineEnchants(((itemStack, itemStack2) -> true));
- var state = new AnvilOperationState(operation, anvil);
+ var behavior = spy(VanillaAnvil.BEHAVIOR);
+ doReturn(true).when(behavior).itemsCombineEnchants(notNull(), notNull());
+ var state = new AnvilState(behavior, anvil);
assertThat(
"No enchants added yields empty result",
- function.getResult(operation, state),
+ function.getResult(behavior, state),
is(AnvilFunctionResult.EMPTY));
}
@@ -143,15 +145,15 @@ void testBasicAdd() {
applyEnchantments(addition, enchantments);
var anvil = getMockView(new ItemStack(BASE_MAT), addition);
- var operation = new AnvilOperation();
- operation.setItemsCombineEnchants(((itemStack, itemStack2) -> true));
- operation.setEnchantApplies((enchantment, item) -> true);
- operation.setEnchantMaxLevel(enchantment -> Short.MAX_VALUE);
- var state = new ReadableResultState(operation, anvil);
+ var behavior = spy(VanillaAnvil.BEHAVIOR);
+ doReturn(true).when(behavior).itemsCombineEnchants(notNull(), notNull());
+ doReturn(true).when(behavior).enchantApplies(notNull(), notNull());
+ doReturn((int) Short.MAX_VALUE).when(behavior).getEnchantMaxLevel(notNull());
+ var state = new ReadableResultState(behavior, anvil);
- assertThat("Combination must apply", function.canApply(operation, state));
+ assertThat("Combination must apply", function.canApply(behavior, state));
- AnvilFunctionResult result = function.getResult(operation, state);
+ AnvilFunctionResult result = function.getResult(behavior, state);
assertThat("Material cost is unchanged", result.getMaterialCostIncrease(), is(0));
result.modifyResult(state.getResult().getMeta());
@@ -183,22 +185,21 @@ void testBookHalfPrice() {
var anvil = getMockView(base, addition);
var bookAnvil = getMockView(base, bookAddition);
- var operation = new AnvilOperation();
- operation.setItemsCombineEnchants(((itemStack, itemStack2) -> true));
- operation.setEnchantApplies((enchantment, item) -> true);
- operation.setEnchantMaxLevel(enchantment -> Short.MAX_VALUE);
- operation.setEnchantsConflict((enchantment1, enchantment2) -> false);
+ var behavior = mock(AnvilBehavior.class);
+ doReturn(true).when(behavior).itemsCombineEnchants(notNull(), notNull());
+ doReturn(true).when(behavior).enchantApplies(notNull(), notNull());
+ doReturn((int) Short.MAX_VALUE).when(behavior).getEnchantMaxLevel(notNull());
- var state = new ReadableResultState(operation, anvil);
- var bookState = new ReadableResultState(operation, bookAnvil);
+ var state = new ReadableResultState(behavior, anvil);
+ var bookState = new ReadableResultState(behavior, bookAnvil);
- assertThat("Combination must apply", function.canApply(operation, state));
- assertThat("Book combination must apply", function.canApply(operation, bookState));
+ assertThat("Combination must apply", function.canApply(behavior, state));
+ assertThat("Book combination must apply", function.canApply(behavior, bookState));
- AnvilFunctionResult result = function.getResult(operation, state);
+ AnvilFunctionResult result = function.getResult(behavior, state);
assertThat("Material cost is unchanged", result.getMaterialCostIncrease(), is(0));
result.modifyResult(state.getResult().getMeta());
- AnvilFunctionResult bookResult = function.getResult(operation, bookState);
+ AnvilFunctionResult bookResult = function.getResult(behavior, bookState);
assertThat("Book material cost is unchanged", bookResult.getMaterialCostIncrease(), is(0));
bookResult.modifyResult(bookState.getResult().getMeta());
@@ -227,16 +228,15 @@ void testCombineAdd() {
applyEnchantments(addition, enchantments);
var anvil = getMockView(base, addition);
- var operation = new AnvilOperation();
- operation.setItemsCombineEnchants(((itemStack, itemStack2) -> true));
- operation.setEnchantApplies((enchantment, item) -> true);
- operation.setEnchantMaxLevel(enchantment -> Short.MAX_VALUE);
- operation.setEnchantsConflict((enchantment1, enchantment2) -> false);
- var state = new ReadableResultState(operation, anvil);
+ var behavior = mock(AnvilBehavior.class);
+ doReturn(true).when(behavior).itemsCombineEnchants(notNull(), notNull());
+ doReturn(true).when(behavior).enchantApplies(notNull(), notNull());
+ doReturn((int) Short.MAX_VALUE).when(behavior).getEnchantMaxLevel(notNull());
+ var state = new ReadableResultState(behavior, anvil);
- assertThat("Combination must apply", function.canApply(operation, state));
+ assertThat("Combination must apply", function.canApply(behavior, state));
- AnvilFunctionResult result = function.getResult(operation, state);
+ AnvilFunctionResult result = function.getResult(behavior, state);
assertThat("Material cost is unchanged", result.getMaterialCostIncrease(), is(0));
result.modifyResult(state.getResult().getMeta());
@@ -266,16 +266,16 @@ void testMergeInvalid() {
applyEnchantments(addition, invalidEnchants);
var anvil = getMockView(base, addition);
- var operation = new AnvilOperation();
- operation.setItemsCombineEnchants(((itemStack, itemStack2) -> true));
- operation.setEnchantApplies((enchantment, item) -> true);
- operation.setEnchantMaxLevel(enchantment -> Short.MAX_VALUE);
- operation.setEnchantsConflict((enchantment1, enchantment2) -> true);
- var state = new ReadableResultState(operation, anvil);
+ var behavior = mock(AnvilBehavior.class);
+ doReturn(true).when(behavior).itemsCombineEnchants(notNull(), notNull());
+ doReturn(true).when(behavior).enchantApplies(notNull(), notNull());
+ doReturn((int) Short.MAX_VALUE).when(behavior).getEnchantMaxLevel(notNull());
+ doReturn(true).when(behavior).enchantsConflict(notNull(), notNull());
+ var state = new ReadableResultState(behavior, anvil);
- assertThat("Combination must apply", function.canApply(operation, state));
+ assertThat("Combination must apply", function.canApply(behavior, state));
- AnvilFunctionResult result = function.getResult(operation, state);
+ AnvilFunctionResult result = function.getResult(behavior, state);
assertThat("Material cost is unchanged", result.getMaterialCostIncrease(), is(0));
result.modifyResult(state.getResult().getMeta());
@@ -300,16 +300,15 @@ void testCommonTridentEnchant() {
ItemStack base = new ItemStack(BASE_MAT);
var anvil = getMockView(base, addition);
- var operation = new AnvilOperation();
- operation.setItemsCombineEnchants(((itemStack, itemStack2) -> true));
- operation.setEnchantApplies((enchantment, item) -> true);
- operation.setEnchantMaxLevel(enchantment -> Short.MAX_VALUE);
- operation.setEnchantsConflict((enchantment1, enchantment2) -> false);
- var state = new ReadableResultState(operation, anvil);
+ var behavior = mock(AnvilBehavior.class);
+ doReturn(true).when(behavior).itemsCombineEnchants(notNull(), notNull());
+ doReturn(true).when(behavior).enchantApplies(notNull(), notNull());
+ doReturn((int) Short.MAX_VALUE).when(behavior).getEnchantMaxLevel(notNull());
+ var state = new ReadableResultState(behavior, anvil);
- assertThat("Combination must apply", function.canApply(operation, state));
+ assertThat("Combination must apply", function.canApply(behavior, state));
- AnvilFunctionResult result = function.getResult(operation, state);
+ AnvilFunctionResult result = function.getResult(behavior, state);
assertThat("Material cost is unchanged", result.getMaterialCostIncrease(), is(0));
result.modifyResult(state.getResult().getMeta());
@@ -329,16 +328,15 @@ void testTridentEnchant() {
ItemStack base = new ItemStack(BASE_MAT);
var anvil = getMockView(base, addition);
- var operation = new AnvilOperation();
- operation.setItemsCombineEnchants(((itemStack, itemStack2) -> true));
- operation.setEnchantApplies((enchantment, item) -> true);
- operation.setEnchantMaxLevel(enchantment -> Short.MAX_VALUE);
- operation.setEnchantsConflict((enchantment1, enchantment2) -> false);
- var state = new ReadableResultState(operation, anvil);
+ var behavior = mock(AnvilBehavior.class);
+ doReturn(true).when(behavior).itemsCombineEnchants(notNull(), notNull());
+ doReturn(true).when(behavior).enchantApplies(notNull(), notNull());
+ doReturn((int) Short.MAX_VALUE).when(behavior).getEnchantMaxLevel(notNull());
+ var state = new ReadableResultState(behavior, anvil);
- assertThat("Combination must apply", function.canApply(operation, state));
+ assertThat("Combination must apply", function.canApply(behavior, state));
- AnvilFunctionResult result = function.getResult(operation, state);
+ AnvilFunctionResult result = function.getResult(behavior, state);
assertThat("Material cost is unchanged", result.getMaterialCostIncrease(), is(0));
result.modifyResult(state.getResult().getMeta());
@@ -360,7 +358,7 @@ void testTridentEnchant() {
class CombineEnchantsJavaEdition extends CombineEnchantsTest {
protected CombineEnchantsJavaEdition() {
- super(AnvilFunction.COMBINE_ENCHANTMENTS_JAVA_EDITION);
+ super(AnvilFunctions.COMBINE_ENCHANTMENTS_JAVA_EDITION);
}
@Override
@@ -389,16 +387,15 @@ void testNegativeCost() {
applyEnchantments(addition, enchantments);
var anvil = getMockView(base, addition);
- var operation = new AnvilOperation();
- operation.setItemsCombineEnchants(((itemStack, itemStack2) -> true));
- operation.setEnchantApplies((enchantment, item) -> true);
- operation.setEnchantMaxLevel(enchantment -> Short.MAX_VALUE);
- operation.setEnchantsConflict((enchantment1, enchantment2) -> false);
- var state = new ReadableResultState(operation, anvil);
+ var behavior = mock(AnvilBehavior.class);
+ doReturn(true).when(behavior).itemsCombineEnchants(notNull(), notNull());
+ doReturn(true).when(behavior).enchantApplies(notNull(), notNull());
+ doReturn((int) Short.MAX_VALUE).when(behavior).getEnchantMaxLevel(notNull());
+ var state = new ReadableResultState(behavior, anvil);
- assertThat("Combination must apply", function.canApply(operation, state));
+ assertThat("Combination must apply", function.canApply(behavior, state));
- AnvilFunctionResult result = function.getResult(operation, state);
+ AnvilFunctionResult result = function.getResult(behavior, state);
assertThat("Material cost is unchanged", result.getMaterialCostIncrease(), is(0));
result.modifyResult(state.getResult().getMeta());
@@ -418,7 +415,7 @@ void testNegativeCost() {
class CombineEnchantsBedrockEdition extends CombineEnchantsTest {
protected CombineEnchantsBedrockEdition() {
- super(AnvilFunction.COMBINE_ENCHANTMENTS_BEDROCK_EDITION);
+ super(AnvilFunctions.COMBINE_ENCHANTMENTS_BEDROCK_EDITION);
}
@Override
@@ -447,16 +444,15 @@ void testOldLevelHigher() {
applyEnchantments(base, enchantments);
var anvil = getMockView(base, addition);
- var operation = new AnvilOperation();
- operation.setItemsCombineEnchants(((itemStack, itemStack2) -> true));
- operation.setEnchantApplies((enchantment, item) -> true);
- operation.setEnchantMaxLevel(enchantment -> Short.MAX_VALUE);
- operation.setEnchantsConflict((enchantment1, enchantment2) -> false);
- var state = new ReadableResultState(operation, anvil);
+ var behavior = mock(AnvilBehavior.class);
+ doReturn(true).when(behavior).itemsCombineEnchants(notNull(), notNull());
+ doReturn(true).when(behavior).enchantApplies(notNull(), notNull());
+ doReturn((int) Short.MAX_VALUE).when(behavior).getEnchantMaxLevel(notNull());
+ var state = new ReadableResultState(behavior, anvil);
- assertThat("Combination must apply", function.canApply(operation, state));
+ assertThat("Combination must apply", function.canApply(behavior, state));
- AnvilFunctionResult result = function.getResult(operation, state);
+ AnvilFunctionResult result = function.getResult(behavior, state);
assertThat("Material cost is unchanged", result.getMaterialCostIncrease(), is(0));
result.modifyResult(state.getResult().getMeta());
diff --git a/src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilOperationTest.java b/src/test/java/com/github/jikoo/planarenchanting/anvil/VanillaAnvilTest.java
similarity index 76%
rename from src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilOperationTest.java
rename to src/test/java/com/github/jikoo/planarenchanting/anvil/VanillaAnvilTest.java
index f0eea67..e492baa 100644
--- a/src/test/java/com/github/jikoo/planarenchanting/anvil/AnvilOperationTest.java
+++ b/src/test/java/com/github/jikoo/planarenchanting/anvil/VanillaAnvilTest.java
@@ -13,6 +13,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import com.github.jikoo.planarenchanting.util.MetaCachedStack;
import com.github.jikoo.planarenchanting.util.mock.ServerMocks;
import com.github.jikoo.planarenchanting.util.mock.enchantments.EnchantmentMocks;
import com.github.jikoo.planarenchanting.util.mock.inventory.InventoryMocks;
@@ -33,7 +34,6 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
@@ -44,9 +44,9 @@
* Note: These tests are only supposed to cover the functionality of the AnvilOperation class.
* Specific operations are not verified, that is handled in more specific and thorough tests.
*/
-@DisplayName("Verify AnvilOperation application")
+@DisplayName("Verify VanillaAnvil application")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
-class AnvilOperationTest {
+class VanillaAnvilTest {
private static final Material TOOL = Material.DIAMOND_SHOVEL;
private static final Material TOOL_REPAIR = Material.DIAMOND;
@@ -54,8 +54,6 @@ class AnvilOperationTest {
private static final Material INCOMPATIBLE = Material.STONE;
public static Enchantment toolEnchantment;
- private AnvilOperation operation;
-
@BeforeAll
void beforeAll() {
Server server = ServerMocks.mockServer();
@@ -78,38 +76,27 @@ void beforeAll() {
doReturn(Set.of(TOOL)).when(tag).getValues();
}
- @BeforeEach
- void beforeEach() {
- operation = new AnvilOperation();
- }
-
@Test
void testEnchantmentTarget() {
- var item = new ItemStack(TOOL);
- assertThat("Enchantment applies to tools", operation.enchantApplies(toolEnchantment, item));
- item.setType(INCOMPATIBLE);
+ var item = new MetaCachedStack(new ItemStack(TOOL));
+ assertThat(
+ "Enchantment applies to tools",
+ VanillaAnvil.BEHAVIOR.enchantApplies(toolEnchantment, item));
+ item.getItem().setType(INCOMPATIBLE);
assertThat(
"Enchantment does not apply to non-tools",
- operation.enchantApplies(toolEnchantment, item),
+ VanillaAnvil.BEHAVIOR.enchantApplies(toolEnchantment, item),
is(false));
- operation.setEnchantApplies((enchant, itemStack) -> true);
- assertThat(
- "Enchantment applies with alternate predicate",
- operation.enchantApplies(toolEnchantment, item));
}
@Test
void testEnchantmentConflict() {
- Enchantment conflict1 = Enchantment.SILK_TOUCH;
- Enchantment conflict2 = Enchantment.FORTUNE;
-
assertThat(
"Vanilla enchantments conflict",
- operation.enchantsConflict(conflict1, conflict2));
- operation.setEnchantsConflict(((enchantment, enchantment2) -> false));
+ VanillaAnvil.BEHAVIOR.enchantsConflict(Enchantment.SILK_TOUCH, Enchantment.FORTUNE));
assertThat(
- "Enchantments do not conflict with alternate predicate",
- operation.enchantsConflict(conflict1, conflict2),
+ "Nonconflicting enchantments do not conflict",
+ VanillaAnvil.BEHAVIOR.enchantsConflict(Enchantment.EFFICIENCY, Enchantment.FORTUNE),
is(false));
}
@@ -118,13 +105,8 @@ void testEnchantmentConflict() {
void testEnchantmentMaxLevel(Enchantment enchantment) {
assertThat(
"Enchantment max level must be vanilla",
- operation.getEnchantMaxLevel(enchantment),
+ VanillaAnvil.BEHAVIOR.getEnchantMaxLevel(enchantment),
is(enchantment.getMaxLevel()));
- operation.setEnchantMaxLevel(enchant -> Short.MAX_VALUE);
- assertThat(
- "Enchantment max level must set as expected",
- operation.getEnchantMaxLevel(enchantment),
- is((int) Short.MAX_VALUE));
}
private static @NotNull Stream getEnchantments() {
@@ -133,47 +115,43 @@ void testEnchantmentMaxLevel(Enchantment enchantment) {
@Test
void testSameMaterialEnchantCombination() {
- ItemStack base = new ItemStack(TOOL);
- ItemStack addition = new ItemStack(TOOL);
+ var base = new MetaCachedStack(new ItemStack(TOOL));
+ var addition = new MetaCachedStack(new ItemStack(TOOL));
assertThat(
"Same type combine enchantments",
- operation.itemsCombineEnchants(base, addition));
+ VanillaAnvil.BEHAVIOR.itemsCombineEnchants(base, addition));
}
@Test
void testEnchantedBookEnchantCombination() {
- ItemStack base = new ItemStack(TOOL);
- ItemStack addition = new ItemStack(BOOK);
+ var base = new MetaCachedStack(new ItemStack(TOOL));
+ var addition = new MetaCachedStack(new ItemStack(BOOK));
assertThat(
"Enchanted books combine enchantments",
- operation.itemsCombineEnchants(base, addition));
+ VanillaAnvil.BEHAVIOR.itemsCombineEnchants(base, addition));
}
@Test
void testDifferentMaterialEnchantCombination() {
- ItemStack base = new ItemStack(TOOL);
- ItemStack addition = new ItemStack(INCOMPATIBLE);
+ var base = new MetaCachedStack(new ItemStack(TOOL));
+ var addition = new MetaCachedStack(new ItemStack(INCOMPATIBLE));
assertThat(
"Incompatible materials do not combine enchantments",
- operation.itemsCombineEnchants(base, addition),
- not(true));
- operation.setItemsCombineEnchants((itemStack, itemStack2) -> true);
- assertThat(
- "Enchantments combine with alternate predicate",
- operation.itemsCombineEnchants(base, addition));
+ VanillaAnvil.BEHAVIOR.itemsCombineEnchants(base, addition),
+ is(false));
}
@Test
void testEmptyBaseIsEmpty() {
var anvil = getMockView(null, null);
- var result = operation.apply(anvil);
+ var result = new VanillaAnvil().getResult(anvil);
assertThat("Result must be empty", result, is(AnvilResult.EMPTY));
}
@Test
void testEmptyAdditionIsEmpty() {
var anvil = getMockView(new ItemStack(TOOL), null);
- var result = operation.apply(anvil);
+ var result = new VanillaAnvil().getResult(anvil);
assertThat("Result must be empty", result, is(AnvilResult.EMPTY));
}
@@ -181,7 +159,7 @@ void testEmptyAdditionIsEmpty() {
void testEmptyAdditionRenameNotEmpty() {
var anvil = getMockView(new ItemStack(TOOL), null);
when(anvil.getRenameText()).thenReturn("Sample Text");
- var result = operation.apply(anvil);
+ var result = new VanillaAnvil().getResult(anvil);
assertThat("Result must not be empty", result, not(AnvilResult.EMPTY));
}
@@ -191,7 +169,7 @@ void testMultipleBaseIsEmpty() {
base.setAmount(2);
var addition = new ItemStack(TOOL);
var anvil = getMockView(base, addition);
- var result = operation.apply(anvil);
+ var result = new VanillaAnvil().getResult(anvil);
assertThat("Result must be empty", result, is(AnvilResult.EMPTY));
}
@@ -209,10 +187,10 @@ void testRepairWithMaterial() {
var addition = new ItemStack(TOOL_REPAIR);
- assertThat("Base must be repairable by addition", operation.itemRepairedBy(base, addition));
+ assertThat("Base must be repairable by addition", VanillaAnvil.BEHAVIOR.itemRepairedBy(new MetaCachedStack(base), new MetaCachedStack(addition)));
var anvil = getMockView(base, addition);
- var result = operation.apply(anvil);
+ var result = new VanillaAnvil().getResult(anvil);
assertThat("Result must not be empty", result, is(not(AnvilResult.EMPTY)));
@@ -240,7 +218,7 @@ void testRepairWithCombination() {
var addition = base.clone();
var anvil = getMockView(base, addition);
- var result = operation.apply(anvil);
+ var result = new VanillaAnvil().getResult(anvil);
assertThat("Result must not be empty", result, is(not(AnvilResult.EMPTY)));
diff --git a/src/test/java/com/github/jikoo/planarenchanting/anvil/mock/ReadableResultState.java b/src/test/java/com/github/jikoo/planarenchanting/anvil/mock/ReadableResultState.java
index 29a57b7..bb0d5c0 100644
--- a/src/test/java/com/github/jikoo/planarenchanting/anvil/mock/ReadableResultState.java
+++ b/src/test/java/com/github/jikoo/planarenchanting/anvil/mock/ReadableResultState.java
@@ -1,17 +1,17 @@
package com.github.jikoo.planarenchanting.anvil.mock;
-import com.github.jikoo.planarenchanting.anvil.AnvilOperation;
-import com.github.jikoo.planarenchanting.anvil.AnvilOperationState;
+import com.github.jikoo.planarenchanting.anvil.AnvilBehavior;
+import com.github.jikoo.planarenchanting.anvil.AnvilState;
import com.github.jikoo.planarenchanting.util.MetaCachedStack;
import org.bukkit.inventory.view.AnvilView;
import org.jetbrains.annotations.NotNull;
-public class ReadableResultState extends AnvilOperationState {
+public class ReadableResultState extends AnvilState {
public ReadableResultState(
- @NotNull AnvilOperation operation,
+ @NotNull AnvilBehavior behavior,
@NotNull AnvilView view) {
- super(operation, view);
+ super(behavior, view);
}
public @NotNull MetaCachedStack getResult() {