25 incompatible with disenchantment (#26)

Ensure compatibility with disenchantment and make it use custom anvil xp
settings.
This commit is contained in:
alexcrea 2024-08-21 16:20:41 +02:00 committed by GitHub
commit 42814237f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 359 additions and 164 deletions

View file

@ -47,18 +47,22 @@ under 1.2.0 replace ca prefix by ue and use ue.unsafe. some permission/features
anvilconfigreload or carl: Reload every config of this plugin anvilconfigreload or carl: Reload every config of this plugin
customanvilconfig or configanvil: open a menu for administrator to edit plugin's config in game customanvilconfig or configanvil: open a menu for administrator to edit plugin's config in game
``` ```
### Custom Enchantment Plugins ### Supported Plugins
Custom Anvil can be compatible with some custom enchant plugins. \ Custom Anvil can be compatible with some custom enchant and anvil mechanics plugins.
Currently, there is not a lot of compatible plugin
Here is a list of supported plugins with support status: Here is a list of supported custom enchantment plugins with support status:
- [Enchantment²](https://www.spigotmc.org/resources/enchants-squared-the-enchantsplus-rewrite-custom-enchantments-that-act-like-vanilla-ones.86747/): - [Enchantment²](https://www.spigotmc.org/resources/enchants-squared-the-enchantsplus-rewrite-custom-enchantments-that-act-like-vanilla-ones.86747/):
Officially supported by Custom Anvil but still experimental. Automatic configuration. Officially supported by Custom Anvil but still experimental. Automatic configuration.
- [EcoEnchant](https://www.spigotmc.org/resources/50-sale-%E2%8C%9B-ecoenchants-%E2%AD%95-250-enchantments-%E2%9C%85-create-custom-enchants-%E2%9C%A8-essentials-cmi-support.79573/):
Officially supported by Custom Anvil but still experimental. Need to use /anvilconfigreload or a server restart to add newly added enchantment.
Use EcoEnchant restriction system by default.
If you like Custom Anvil to support a specific custom enchantment plugin. - [EcoEnchant](https://www.spigotmc.org/resources/ecoenchants-%E2%AD%95-250-enchantments-%E2%9C%85-create-custom-enchants-%E2%9C%A8-essentials-cmi-support.79573/):
Officially supported by Custom Anvil but still experimental. Need to use /anvilconfigreload or a server restart to add newly added enchantment.
Use EcoEnchant restriction system by default.
Here is a list of supported anvil mechanic plugins with support status:
- [Disenchantment](https://www.spigotmc.org/resources/disenchantment-1-21-1-1-20-6-new-book-splitting-mechanics.110741/)
Officially supported by Custom Anvil but still experimental. mostly use Custom Anvil xp settings.
If you like Custom Anvil to support a specific plugin (custom enchant or anvil mechanic).
You can ask, but please note implementing compatibility will be considered You can ask, but please note implementing compatibility will be considered
as low priority as I work for the plugin on my free time for free. as low priority as I work for the plugin on my free time for free.

View file

@ -14,7 +14,7 @@ plugins {
} }
group = "xyz.alexcrea" group = "xyz.alexcrea"
version = "1.5.5" version = "1.6.0"
repositories { repositories {
// EcoEnchants // EcoEnchants
@ -36,6 +36,9 @@ dependencies {
compileOnly("com.willfp:EcoEnchants:12.5.1") compileOnly("com.willfp:EcoEnchants:12.5.1")
compileOnly("com.willfp:eco:6.70.1") compileOnly("com.willfp:eco:6.70.1")
// Disenchantment
compileOnly("cz.kominekjan:Disenchantment:v5.3.1")
// Include nms // Include nms
implementation(project(":nms:nms-common")) implementation(project(":nms:nms-common"))
implementation(project(":nms:v1_17R1", configuration = "reobf")) implementation(project(":nms:v1_17R1", configuration = "reobf"))

View file

@ -1,5 +1,14 @@
import java.net.URI
rootProject.name = "CustomAnvil" rootProject.name = "CustomAnvil"
// for Disenchantment dependency
sourceControl {
gitRepository(URI.create("https://github.com/H7KZ/Disenchantment.git")) {
producesModule("cz.kominekjan:Disenchantment")
}
}
// NMS subproject // NMS subproject
include("nms:nms-common") include("nms:nms-common")
findProject(":nms:nms-common")?.name = "nms-common" findProject(":nms:nms-common")?.name = "nms-common"

View file

@ -3,7 +3,6 @@ package xyz.alexcrea.cuanvil.enchant.wrapped;
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.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
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;

View file

@ -9,7 +9,8 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import xyz.alexcrea.cuanvil.gui.config.MainConfigGui; import xyz.alexcrea.cuanvil.gui.config.MainConfigGui;
import java.util.*; import java.util.Arrays;
import java.util.Collections;
public class GuiSharedConstant { public class GuiSharedConstant {

View file

@ -2,7 +2,6 @@ package io.delilaheve
import io.delilaheve.util.ConfigOptions import io.delilaheve.util.ConfigOptions
import io.delilaheve.util.EnchantmentUtil.combineWith import io.delilaheve.util.EnchantmentUtil.combineWith
import io.delilaheve.util.EnchantmentUtil.enchantmentName
import io.delilaheve.util.ItemUtil.canMergeWith import io.delilaheve.util.ItemUtil.canMergeWith
import io.delilaheve.util.ItemUtil.findEnchantments import io.delilaheve.util.ItemUtil.findEnchantments
import io.delilaheve.util.ItemUtil.isEnchantedBook import io.delilaheve.util.ItemUtil.isEnchantedBook
@ -25,11 +24,13 @@ import org.bukkit.event.inventory.PrepareAnvilEvent
import org.bukkit.inventory.AnvilInventory import org.bukkit.inventory.AnvilInventory
import org.bukkit.inventory.InventoryView.Property.REPAIR_COST import org.bukkit.inventory.InventoryView.Property.REPAIR_COST
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.Repairable
import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.dependency.packet.PacketManager import xyz.alexcrea.cuanvil.dependency.packet.PacketManager
import xyz.alexcrea.cuanvil.group.ConflictType
import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe
import xyz.alexcrea.cuanvil.util.AnvilXpUtil.calculatePenalty
import xyz.alexcrea.cuanvil.util.AnvilXpUtil.getRightValues
import xyz.alexcrea.cuanvil.util.AnvilXpUtil.setAnvilInvXp
import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair
import java.util.regex.Matcher import java.util.regex.Matcher
import java.util.regex.Pattern import java.util.regex.Pattern
@ -43,9 +44,9 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
companion object { companion object {
// Anvil's output slot // Anvil's output slot
private const val ANVIL_INPUT_LEFT = 0 const val ANVIL_INPUT_LEFT = 0
private const val ANVIL_INPUT_RIGHT = 1 const val ANVIL_INPUT_RIGHT = 1
private const val ANVIL_OUTPUT_SLOT = 2 const val ANVIL_OUTPUT_SLOT = 2
// static slot container // static slot container
private val NO_SLOT = SlotContainer(SlotType.NO_SLOT, 0) private val NO_SLOT = SlotContainer(SlotType.NO_SLOT, 0)
@ -57,6 +58,9 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
*/ */
@EventHandler(priority = HIGHEST) @EventHandler(priority = HIGHEST)
fun anvilCombineCheck(event: PrepareAnvilEvent) { fun anvilCombineCheck(event: PrepareAnvilEvent) {
// Test if the event should bypass custom anvil.
if(DependencyManager.tryEventPreAnvilBypass(event)) return
val inventory = event.inventory val inventory = event.inventory
val first = inventory.getItem(ANVIL_INPUT_LEFT) ?: return val first = inventory.getItem(ANVIL_INPUT_LEFT) ?: return
val second = inventory.getItem(ANVIL_INPUT_RIGHT) val second = inventory.getItem(ANVIL_INPUT_RIGHT)
@ -75,7 +79,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
resultItem.amount *= amount resultItem.amount *= amount
event.result = resultItem event.result = resultItem
handleAnvilXp(inventory, event, recipe.xpCostPerCraft * amount, true) setAnvilInvXp(inventory, event.view, recipe.xpCostPerCraft * amount, true)
return return
} }
@ -96,7 +100,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
anvilCost += calculatePenalty(first, null, resultItem) anvilCost += calculatePenalty(first, null, resultItem)
handleAnvilXp(inventory, event, anvilCost) setAnvilInvXp(inventory, event.view, anvilCost)
return return
} }
@ -130,7 +134,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
// Finally, we set result // Finally, we set result
event.result = resultItem event.result = resultItem
handleAnvilXp(inventory, event, anvilCost) setAnvilInvXp(inventory, event.view, anvilCost)
return return
} }
@ -155,7 +159,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
} }
event.result = resultItem event.result = resultItem
handleAnvilXp(inventory, event, anvilCost) setAnvilInvXp(inventory, event.view, anvilCost)
} else { } else {
CustomAnvil.log("no anvil fuse type found") CustomAnvil.log("no anvil fuse type found")
event.result = null event.result = null
@ -282,9 +286,13 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
val player = event.whoClicked as? Player ?: return val player = event.whoClicked as? Player ?: return
if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return
val inventory = event.inventory as? AnvilInventory ?: return val inventory = event.inventory as? AnvilInventory ?: return
if (event.rawSlot != ANVIL_OUTPUT_SLOT) { if (event.rawSlot != ANVIL_OUTPUT_SLOT) {
return return
} }
// Test if the event should bypass custom anvil.
if(DependencyManager.tryClickAnvilResultBypass(event, inventory)) return
val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return
val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return
val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT) val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT)
@ -504,96 +512,6 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
} }
} }
/**
* Function to calculate work penalty of anvil work
* Also change result work penalty if right item is not null
*/
private fun calculatePenalty(left: ItemStack, right: ItemStack?, result: ItemStack): Int {
return calculatePenalty(left, right, result, false)
}
/**
* Function to calculate work penalty of anvil work
* Also change result work penalty if right item is not null
*/
private fun calculatePenalty(left: ItemStack, right: ItemStack?, result: ItemStack, unitRepair: Boolean): Int {
// Extracted From https://minecraft.fandom.com/wiki/Anvil_mechanics#Enchantment_equation
// Calculate work penalty
val leftPenalty = (left.itemMeta as? Repairable)?.repairCost ?: 0
val rightPenalty =
if (right == null) {
0
} else {
(right.itemMeta as? Repairable)?.repairCost ?: 0
}
// Increase penalty on fusing or unit repair
if(right != null || unitRepair){
result.itemMeta?.let {
(it as? Repairable)?.repairCost = leftPenalty * 2 + 1
result.itemMeta = it
}
}
CustomAnvil.log(
"Calculated penalty: " +
"leftPenalty: $leftPenalty, " +
"rightPenalty: $rightPenalty, " +
"result penalty: ${(result.itemMeta as? Repairable)?.repairCost ?: "none"}"
)
return leftPenalty + rightPenalty
}
/**
* Function to calculate right enchantment values
* it include enchantment placed on final item and conflicting enchantment
*/
private fun getRightValues(right: ItemStack, result: ItemStack): Int {
// Calculate right value and illegal enchant penalty
var illegalPenalty = 0
var rightValue = 0
val rightIsFormBook = right.isEnchantedBook()
val resultEnchs = result.findEnchantments()
val resultEnchsKeys = HashMap(resultEnchs)
for (enchantment in right.findEnchantments()) {
// count enchant as illegal enchant if it conflicts with another enchant or not in result
if ((enchantment.key !in resultEnchsKeys)) {
resultEnchsKeys[enchantment.key] = enchantment.value
val conflictType = ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(
resultEnchsKeys,
result,
enchantment.key
)
resultEnchsKeys.remove(enchantment.key)
if (ConflictType.ENCHANTMENT_CONFLICT == conflictType) {
illegalPenalty += ConfigOptions.sacrificeIllegalCost
CustomAnvil.verboseLog("Big conflict. Adding illegal price penalty")
}
continue
}
// We know "enchantment.key in resultEnchs" true
val resultLevel = resultEnchs[enchantment.key]!!
val enchantmentMultiplier = ConfigOptions.enchantmentValue(enchantment.key, rightIsFormBook)
val value = resultLevel * enchantmentMultiplier
CustomAnvil.log("Value for ${enchantment.key.enchantmentName} level ${enchantment.value} is $value ($resultLevel * $enchantmentMultiplier)")
rightValue += value
}
CustomAnvil.log(
"Calculated right values: " +
"rightValue: $rightValue, " +
"illegalPenalty: $illegalPenalty"
)
return rightValue + illegalPenalty
}
private fun getCustomRecipe ( private fun getCustomRecipe (
leftItem: ItemStack, leftItem: ItemStack,
rightItem: ItemStack?) : AnvilCustomRecipe? { rightItem: ItemStack?) : AnvilCustomRecipe? {
@ -638,58 +556,6 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
} }
/**
* Display xp needed for the work on the anvil inventory
*/
private fun handleAnvilXp(
inventory: AnvilInventory,
event: PrepareAnvilEvent,
anvilCost: Int,
ignoreRules: Boolean = false
) {
// Test repair cost limit
val finalAnvilCost = if (
!ignoreRules &&
!ConfigOptions.doRemoveCostLimit &&
ConfigOptions.doCapCost) {
min(anvilCost, ConfigOptions.maxAnvilCost)
} else {
anvilCost
}
/* Because Minecraft likes to have the final say in the repair cost displayed
* we need to wait for the event to end before overriding it, this ensures that
* we have the final say in the process. */
CustomAnvil.instance
.server
.scheduler
.runTask(CustomAnvil.instance, Runnable {
inventory.maximumRepairCost =
if (ConfigOptions.doRemoveCostLimit || ignoreRules)
{ Int.MAX_VALUE }
else
{ ConfigOptions.maxAnvilCost + 1 }
val player = event.view.player
inventory.repairCost = finalAnvilCost
event.view.setProperty(REPAIR_COST, finalAnvilCost)
player.openInventory.setProperty(REPAIR_COST, finalAnvilCost)
if(player is Player){
if(player.gameMode != GameMode.CREATIVE ){
val bypassToExpensive = (ConfigOptions.doReplaceTooExpensive) &&
(finalAnvilCost >= 40) &&
finalAnvilCost < inventory.maximumRepairCost
packetManager.setInstantBuild(player, bypassToExpensive)
}
player.updateInventory()
}
})
}
@EventHandler @EventHandler
fun onAnvilClose(event: InventoryCloseEvent){ fun onAnvilClose(event: InventoryCloseEvent){
val player = event.player val player = event.player

View file

@ -1,6 +1,9 @@
package xyz.alexcrea.cuanvil.dependency package xyz.alexcrea.cuanvil.dependency
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.PrepareAnvilEvent
import org.bukkit.inventory.AnvilInventory
import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.dependency.packet.PacketManager import xyz.alexcrea.cuanvil.dependency.packet.PacketManager
import xyz.alexcrea.cuanvil.dependency.packet.PacketManagerSelector import xyz.alexcrea.cuanvil.dependency.packet.PacketManagerSelector
@ -10,6 +13,7 @@ object DependencyManager {
lateinit var packetManager: PacketManager lateinit var packetManager: PacketManager
var enchantmentSquaredCompatibility: EnchantmentSquaredDependency? = null var enchantmentSquaredCompatibility: EnchantmentSquaredDependency? = null
var ecoEnchantCompatibility: EcoEnchantDependency? = null var ecoEnchantCompatibility: EcoEnchantDependency? = null
var disenchantmentCompatibility: DisenchantmentDependency? = null
fun loadDependency(){ fun loadDependency(){
val pluginManager = Bukkit.getPluginManager() val pluginManager = Bukkit.getPluginManager()
@ -30,6 +34,12 @@ object DependencyManager {
ecoEnchantCompatibility!!.disableAnvilListener() ecoEnchantCompatibility!!.disableAnvilListener()
} }
// Disenchantment dependency
if(pluginManager.isPluginEnabled("Disenchantment")){
disenchantmentCompatibility = DisenchantmentDependency()
disenchantmentCompatibility!!.redirectListeners()
}
} }
fun handleCompatibilityConfig() { fun handleCompatibilityConfig() {
@ -52,4 +62,20 @@ object DependencyManager {
} }
fun tryEventPreAnvilBypass(event: PrepareAnvilEvent): Boolean {
var bypass = false
if(disenchantmentCompatibility?.testPrepareAnvil(event) == true) bypass = true
return bypass
}
fun tryClickAnvilResultBypass(event: InventoryClickEvent, inventory: AnvilInventory): Boolean {
var bypass = false
if(disenchantmentCompatibility?.testAnvilResult(event, inventory) == true) bypass = true
return bypass
}
} }

View file

@ -0,0 +1,123 @@
package xyz.alexcrea.cuanvil.dependency
import cz.kominekjan.disenchantment.events.ItemClickEvent
import cz.kominekjan.disenchantment.events.ItemEvent
import cz.kominekjan.disenchantment.events.SplitBookClickEvent
import cz.kominekjan.disenchantment.events.SplitBookEvent
import io.delilaheve.AnvilEventListener
import io.delilaheve.CustomAnvil
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.PrepareAnvilEvent
import org.bukkit.inventory.AnvilInventory
import org.bukkit.inventory.ItemStack
import org.bukkit.plugin.RegisteredListener
import xyz.alexcrea.cuanvil.util.AnvilXpUtil
class DisenchantmentDependency {
init {
CustomAnvil.instance.logger.info("Disenchantment Detected !")
}
private lateinit var splitEvent: SplitBookEvent
private lateinit var itemEvent: ItemEvent
private lateinit var splitBookClickEvent: SplitBookClickEvent
private lateinit var itemClickEvent: ItemClickEvent
fun redirectListeners() {
val toUnregister = ArrayList<RegisteredListener>()
// get required PrepareAnvilEvent listener
for (registeredListener in PrepareAnvilEvent.getHandlerList().registeredListeners) {
val listener = registeredListener.listener
if(listener is SplitBookEvent){
this.splitEvent = listener
toUnregister.add(registeredListener)
}
if(listener is ItemEvent){
itemEvent = listener
toUnregister.add(registeredListener)
}
}
for (listener in toUnregister) {
PrepareAnvilEvent.getHandlerList().unregister(listener)
}
toUnregister.clear()
// get required InventoryClickEvent listener
for (registeredListener in InventoryClickEvent.getHandlerList().registeredListeners) {
val listener = registeredListener.listener
if(listener is SplitBookClickEvent){
splitBookClickEvent = listener
toUnregister.add(registeredListener)
}
if(listener is ItemClickEvent){
itemClickEvent = listener
toUnregister.add(registeredListener)
}
}
for (listener in toUnregister) {
InventoryClickEvent.getHandlerList().unregister(listener)
}
}
fun testPrepareAnvil(event: PrepareAnvilEvent): Boolean {
val previousResult = event.result
event.result = null
// Test if event change the result
itemEvent.onDisenchantmentEvent(event)
if(event.result != null) {
CustomAnvil.log("Detected pre anvil item extract bypass.")
AnvilXpUtil.setAnvilInvXp(event.inventory, event.view, event.inventory.repairCost)
return true
}
splitEvent.onDisenchantmentEvent(event)
if(event.result != null) {
CustomAnvil.log("Detected pre anvil split enchant bypass.")
AnvilXpUtil.setAnvilInvXp(event.inventory, event.view, event.inventory.repairCost)
return true
}
event.result = previousResult
return false
}
fun testAnvilResult(event: InventoryClickEvent, inventory: AnvilInventory): Boolean {
val previousResultSlot = inventory.getItem(AnvilEventListener.ANVIL_OUTPUT_SLOT)?.clone()
// Test event if change the result
itemClickEvent.onDisenchantmentClickEvent(event)
if(!testAnvilInventoryChange(inventory, previousResultSlot) || event.isCancelled) {
CustomAnvil.log("Detected anvil click item extract bypass.")
return true
}
splitBookClickEvent.onDisenchantmentClickEvent(event)
if(!testAnvilInventoryChange(inventory, previousResultSlot) || event.isCancelled) {
CustomAnvil.log("Detected anvil click split enchant bypass.")
return true
}
return false
}
private fun testAnvilInventoryChange(inventory: AnvilInventory, previous: ItemStack?): Boolean {
val currentResult = inventory.getItem(AnvilEventListener.ANVIL_OUTPUT_SLOT)
return currentResult == previous
}
}

View file

@ -0,0 +1,163 @@
package xyz.alexcrea.cuanvil.util
import io.delilaheve.CustomAnvil
import io.delilaheve.util.ConfigOptions
import io.delilaheve.util.EnchantmentUtil.enchantmentName
import io.delilaheve.util.ItemUtil.findEnchantments
import io.delilaheve.util.ItemUtil.isEnchantedBook
import org.bukkit.GameMode
import org.bukkit.entity.Player
import org.bukkit.inventory.AnvilInventory
import org.bukkit.inventory.InventoryView
import org.bukkit.inventory.InventoryView.Property.REPAIR_COST
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.Repairable
import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.group.ConflictType
import kotlin.math.min
object AnvilXpUtil {
/**
* Display xp needed for the work on the anvil inventory
*/
fun setAnvilInvXp(
inventory: AnvilInventory,
view: InventoryView,
anvilCost: Int,
ignoreRules: Boolean = false
) {
// Test repair cost limit
val finalAnvilCost = if (
!ignoreRules &&
!ConfigOptions.doRemoveCostLimit &&
ConfigOptions.doCapCost) {
min(anvilCost, ConfigOptions.maxAnvilCost)
} else {
anvilCost
}
/* Because Minecraft likes to have the final say in the repair cost displayed
* we need to wait for the event to end before overriding it, this ensures that
* we have the final say in the process. */
CustomAnvil.instance
.server
.scheduler
.runTask(CustomAnvil.instance, Runnable {
inventory.maximumRepairCost =
if (ConfigOptions.doRemoveCostLimit || ignoreRules)
{ Int.MAX_VALUE }
else
{ ConfigOptions.maxAnvilCost + 1 }
val player = view.player
inventory.repairCost = finalAnvilCost
view.setProperty(REPAIR_COST, finalAnvilCost)
player.openInventory.setProperty(REPAIR_COST, finalAnvilCost)
if(player is Player){
if(player.gameMode != GameMode.CREATIVE ){
val bypassToExpensive = (ConfigOptions.doReplaceTooExpensive) &&
(finalAnvilCost >= 40) &&
finalAnvilCost < inventory.maximumRepairCost
DependencyManager.packetManager.setInstantBuild(player, bypassToExpensive)
}
player.updateInventory()
}
})
}
/**
* Function to calculate work penalty of anvil work
* Also change result work penalty if right item is not null
*/
fun calculatePenalty(left: ItemStack, right: ItemStack?, result: ItemStack): Int {
return calculatePenalty(left, right, result, false)
}
/**
* Function to calculate work penalty of anvil work
* Also change result work penalty if right item is not null
*/
fun calculatePenalty(left: ItemStack, right: ItemStack?, result: ItemStack, unitRepair: Boolean): Int {
// Extracted From https://minecraft.fandom.com/wiki/Anvil_mechanics#Enchantment_equation
// Calculate work penalty
val leftPenalty = (left.itemMeta as? Repairable)?.repairCost ?: 0
val rightPenalty =
if (right == null) {
0
} else {
(right.itemMeta as? Repairable)?.repairCost ?: 0
}
// Increase penalty on fusing or unit repair
if(right != null || unitRepair){
result.itemMeta?.let {
(it as? Repairable)?.repairCost = leftPenalty * 2 + 1
result.itemMeta = it
}
}
CustomAnvil.log(
"Calculated penalty: " +
"leftPenalty: $leftPenalty, " +
"rightPenalty: $rightPenalty, " +
"result penalty: ${(result.itemMeta as? Repairable)?.repairCost ?: "none"}"
)
return leftPenalty + rightPenalty
}
/**
* Function to calculate right enchantment values
* it include enchantment placed on final item and conflicting enchantment
*/
fun getRightValues(right: ItemStack, result: ItemStack): Int {
// Calculate right value and illegal enchant penalty
var illegalPenalty = 0
var rightValue = 0
val rightIsFormBook = right.isEnchantedBook()
val resultEnchs = result.findEnchantments()
val resultEnchsKeys = HashMap(resultEnchs)
for (enchantment in right.findEnchantments()) {
// count enchant as illegal enchant if it conflicts with another enchant or not in result
if ((enchantment.key !in resultEnchsKeys)) {
resultEnchsKeys[enchantment.key] = enchantment.value
val conflictType = ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(
resultEnchsKeys,
result,
enchantment.key
)
resultEnchsKeys.remove(enchantment.key)
if (ConflictType.ENCHANTMENT_CONFLICT == conflictType) {
illegalPenalty += ConfigOptions.sacrificeIllegalCost
CustomAnvil.verboseLog("Big conflict. Adding illegal price penalty")
}
continue
}
// We know "enchantment.key in resultEnchs" true
val resultLevel = resultEnchs[enchantment.key]!!
val enchantmentMultiplier = ConfigOptions.enchantmentValue(enchantment.key, rightIsFormBook)
val value = resultLevel * enchantmentMultiplier
CustomAnvil.log("Value for ${enchantment.key.enchantmentName} level ${enchantment.value} is $value ($resultLevel * $enchantmentMultiplier)")
rightValue += value
}
CustomAnvil.log(
"Calculated right values: " +
"rightValue: $rightValue, " +
"illegalPenalty: $illegalPenalty"
)
return rightValue + illegalPenalty
}
}

View file

@ -1,7 +1,7 @@
main: io.delilaheve.CustomAnvil main: io.delilaheve.CustomAnvil
name: CustomAnvil name: CustomAnvil
prefix: "Custom Anvil" prefix: "Custom Anvil"
version: 1.5.5 version: 1.6.0
description: Allow to customise anvil mechanics description: Allow to customise anvil mechanics
api-version: 1.16 api-version: 1.16
load: POSTWORLD load: POSTWORLD
@ -53,6 +53,7 @@ permissions:
softdepend: softdepend:
- UnsafeEnchantsPlus - UnsafeEnchantsPlus
- ProtocolLib - ProtocolLib
- Disenchantment
- EnchantsSquared - EnchantsSquared
- EcoEnchants - EcoEnchants
- eco - eco