Do not continue anvil process if Disenchantment done something.

This commit is contained in:
alexcrea 2024-08-21 03:13:58 +02:00
parent 3c8810ed72
commit 804c11a7f4
No known key found for this signature in database
GPG key ID: 43FD265DB0DBF91F
5 changed files with 231 additions and 59 deletions

View file

@ -27,10 +27,12 @@ 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.dependency.packet.PacketManager
import xyz.alexcrea.cuanvil.group.ConflictType
import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe
import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair
import xyz.alexcrea.cuanvil.util.XpSetterUtil.setAnvilInvXp
import java.util.regex.Matcher
import java.util.regex.Pattern
import kotlin.math.min
@ -43,9 +45,9 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
companion object {
// Anvil's output slot
private const val ANVIL_INPUT_LEFT = 0
private const val ANVIL_INPUT_RIGHT = 1
private const val ANVIL_OUTPUT_SLOT = 2
const val ANVIL_INPUT_LEFT = 0
const val ANVIL_INPUT_RIGHT = 1
const val ANVIL_OUTPUT_SLOT = 2
// static slot container
private val NO_SLOT = SlotContainer(SlotType.NO_SLOT, 0)
@ -57,6 +59,9 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
*/
@EventHandler(priority = HIGHEST)
fun anvilCombineCheck(event: PrepareAnvilEvent) {
// Test if the event should bypass custom anvil.
if(DependencyManager.tryEventPreAnvilBypass(event)) return
val inventory = event.inventory
val first = inventory.getItem(ANVIL_INPUT_LEFT) ?: return
val second = inventory.getItem(ANVIL_INPUT_RIGHT)
@ -75,7 +80,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
resultItem.amount *= amount
event.result = resultItem
handleAnvilXp(inventory, event, recipe.xpCostPerCraft * amount, true)
setAnvilInvXp(inventory, event.view, recipe.xpCostPerCraft * amount, true)
return
}
@ -96,7 +101,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
anvilCost += calculatePenalty(first, null, resultItem)
handleAnvilXp(inventory, event, anvilCost)
setAnvilInvXp(inventory, event.view, anvilCost)
return
}
@ -130,7 +135,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
// Finally, we set result
event.result = resultItem
handleAnvilXp(inventory, event, anvilCost)
setAnvilInvXp(inventory, event.view, anvilCost)
return
}
@ -155,7 +160,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
}
event.result = resultItem
handleAnvilXp(inventory, event, anvilCost)
setAnvilInvXp(inventory, event.view, anvilCost)
} else {
CustomAnvil.log("no anvil fuse type found")
event.result = null
@ -282,9 +287,13 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener {
val player = event.whoClicked as? Player ?: return
if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return
val inventory = event.inventory as? AnvilInventory ?: return
if (event.rawSlot != ANVIL_OUTPUT_SLOT) {
return
}
// Test if the event should bypass custom anvil.
if(DependencyManager.tryClickAnvilResultBypass(event, inventory)) return
val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return
val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return
val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT)
@ -638,58 +647,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
fun onAnvilClose(event: InventoryCloseEvent){
val player = event.player

View file

@ -1,6 +1,9 @@
package xyz.alexcrea.cuanvil.dependency
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.dependency.packet.PacketManager
import xyz.alexcrea.cuanvil.dependency.packet.PacketManagerSelector
@ -10,6 +13,7 @@ object DependencyManager {
lateinit var packetManager: PacketManager
var enchantmentSquaredCompatibility: EnchantmentSquaredDependency? = null
var ecoEnchantCompatibility: EcoEnchantDependency? = null
var disenchantmentCompatibility: DisenchantmentDependency? = null
fun loadDependency(){
val pluginManager = Bukkit.getPluginManager()
@ -30,6 +34,12 @@ object DependencyManager {
ecoEnchantCompatibility!!.disableAnvilListener()
}
// Disenchantment dependency
if(pluginManager.isPluginEnabled("Disenchantment")){
disenchantmentCompatibility = DisenchantmentDependency()
disenchantmentCompatibility!!.redirectListeners()
}
}
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,121 @@
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.XpSetterUtil
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.")
return true
}
splitEvent.onDisenchantmentEvent(event)
if(event.result != null) {
CustomAnvil.log("Detected pre anvil split enchant bypass.")
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,67 @@
package xyz.alexcrea.cuanvil.util
import io.delilaheve.CustomAnvil
import io.delilaheve.util.ConfigOptions
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 xyz.alexcrea.cuanvil.dependency.DependencyManager
import kotlin.math.min
object XpSetterUtil {
/**
* 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()
}
})
}
}

View file

@ -53,6 +53,7 @@ permissions:
softdepend:
- UnsafeEnchantsPlus
- ProtocolLib
- Disenchantment
- EnchantsSquared
- EcoEnchants
- eco