mirror of
https://github.com/alexcrea/CustomAnvil.git
synced 2026-06-23 16:16:17 +02:00
25 incompatible with disenchantment (#26)
Ensure compatibility with disenchantment and make it use custom anvil xp settings.
This commit is contained in:
commit
42814237f3
10 changed files with 359 additions and 164 deletions
20
README.md
20
README.md
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"))
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
163
src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt
Normal file
163
src/main/kotlin/xyz/alexcrea/cuanvil/util/AnvilXpUtil.kt
Normal 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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue