mirror of
https://github.com/alexcrea/CustomAnvil.git
synced 2026-06-23 16:16:17 +02:00
v1.7.1 (#48)
Fix getting cost for color renaming causing null pointer exception when inventory name is null (Fix #47) Add safety when executing dependency handling code
This commit is contained in:
parent
5f557e3d49
commit
33474c379a
7 changed files with 130 additions and 34 deletions
|
|
@ -16,7 +16,7 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "xyz.alexcrea"
|
group = "xyz.alexcrea"
|
||||||
version = "1.7.0"
|
version = "1.7.1"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
// EcoEnchants
|
// EcoEnchants
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,8 @@ object ConfigOptions {
|
||||||
private const val KEY_ITEM = "item"
|
private const val KEY_ITEM = "item"
|
||||||
|
|
||||||
// Debug flag
|
// Debug flag
|
||||||
private const val DEBUG_LOGGING = "debug_log"
|
const val DEBUG_LOGGING = "debug_log"
|
||||||
private const val VERBOSE_DEBUG_LOGGING = "debug_log_verbose"
|
const val VERBOSE_DEBUG_LOGGING = "debug_log_verbose"
|
||||||
|
|
||||||
// ----------------------
|
// ----------------------
|
||||||
// Default config values
|
// Default config values
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package xyz.alexcrea.cuanvil.dependency
|
||||||
|
|
||||||
import io.delilaheve.CustomAnvil
|
import io.delilaheve.CustomAnvil
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.entity.HumanEntity
|
import org.bukkit.entity.HumanEntity
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
import org.bukkit.event.inventory.PrepareAnvilEvent
|
import org.bukkit.event.inventory.PrepareAnvilEvent
|
||||||
|
|
@ -15,6 +16,8 @@ import xyz.alexcrea.cuanvil.dependency.packet.PacketManagerSelector
|
||||||
import xyz.alexcrea.cuanvil.dependency.scheduler.BukkitScheduler
|
import xyz.alexcrea.cuanvil.dependency.scheduler.BukkitScheduler
|
||||||
import xyz.alexcrea.cuanvil.dependency.scheduler.FoliaScheduler
|
import xyz.alexcrea.cuanvil.dependency.scheduler.FoliaScheduler
|
||||||
import xyz.alexcrea.cuanvil.dependency.scheduler.TaskScheduler
|
import xyz.alexcrea.cuanvil.dependency.scheduler.TaskScheduler
|
||||||
|
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT
|
||||||
|
import java.util.logging.Level
|
||||||
|
|
||||||
object DependencyManager {
|
object DependencyManager {
|
||||||
|
|
||||||
|
|
@ -96,10 +99,25 @@ object DependencyManager {
|
||||||
|
|
||||||
// Then handle plugin reload
|
// Then handle plugin reload
|
||||||
ecoEnchantCompatibility?.handleConfigReload()
|
ecoEnchantCompatibility?.handleConfigReload()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if should bypass (either by a dependency or error)
|
||||||
fun tryEventPreAnvilBypass(event: PrepareAnvilEvent, player: HumanEntity): Boolean {
|
fun tryEventPreAnvilBypass(event: PrepareAnvilEvent, player: HumanEntity): Boolean {
|
||||||
|
try {
|
||||||
|
return unsafeTryEventPreAnvilBypass(event, player)
|
||||||
|
} catch (e: Exception){
|
||||||
|
CustomAnvil.instance.logger.log(Level.SEVERE, "Error while trying to handle custom anvil supported plugin: ", e)
|
||||||
|
|
||||||
|
// Just in case to avoid illegal items
|
||||||
|
event.inventory.setItem(ANVIL_OUTPUT_SLOT, null)
|
||||||
|
|
||||||
|
// Finally, warn the player, maybe a lot of time but better warn than do nothing
|
||||||
|
event.view.player.sendMessage(ChatColor.RED.toString() + "Error while handling the anvil.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun unsafeTryEventPreAnvilBypass(event: PrepareAnvilEvent, player: HumanEntity): Boolean {
|
||||||
var bypass = false
|
var bypass = false
|
||||||
|
|
||||||
// Test if disenchantment used prepare anvil
|
// Test if disenchantment used prepare anvil
|
||||||
|
|
@ -118,11 +136,44 @@ object DependencyManager {
|
||||||
return bypass
|
return bypass
|
||||||
}
|
}
|
||||||
|
|
||||||
fun treatAnvilResult(event: PrepareAnvilEvent, result: ItemStack) {
|
// Return true only if error occurred (and so should bypass rest)
|
||||||
|
fun tryTreatAnvilResult(event: PrepareAnvilEvent, result: ItemStack): Boolean {
|
||||||
|
try {
|
||||||
|
unsafeTryTreatAnvilResult(event, result)
|
||||||
|
return false
|
||||||
|
} catch (e: Exception){
|
||||||
|
CustomAnvil.instance.logger.log(Level.SEVERE, "Error while trying to handle custom anvil supported plugin: ", e)
|
||||||
|
|
||||||
|
// Just in case to avoid illegal items
|
||||||
|
event.inventory.setItem(ANVIL_OUTPUT_SLOT, null)
|
||||||
|
|
||||||
|
// Finally, warn the player, maybe a lot of time but better warn than do nothing
|
||||||
|
event.view.player.sendMessage(ChatColor.RED.toString() + "Error while handling the anvil.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun unsafeTryTreatAnvilResult(event: PrepareAnvilEvent, result: ItemStack) {
|
||||||
excellentEnchantsCompatibility?.treatAnvilResult(event, result)
|
excellentEnchantsCompatibility?.treatAnvilResult(event, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if should bypass (either by a dependency or error)
|
||||||
fun tryClickAnvilResultBypass(event: InventoryClickEvent, inventory: AnvilInventory): Boolean {
|
fun tryClickAnvilResultBypass(event: InventoryClickEvent, inventory: AnvilInventory): Boolean {
|
||||||
|
try {
|
||||||
|
return unsafeTryClickAnvilResultBypass(event, inventory)
|
||||||
|
} catch (e: Exception){
|
||||||
|
CustomAnvil.instance.logger.log(Level.SEVERE, "Error while trying to handle custom anvil supported plugin: ", e)
|
||||||
|
|
||||||
|
// Just in case to avoid illegal items
|
||||||
|
event.inventory.setItem(ANVIL_OUTPUT_SLOT, null)
|
||||||
|
|
||||||
|
// Finally, warn the player, maybe a lot of time but better warn than do nothing
|
||||||
|
event.whoClicked.sendMessage(ChatColor.RED.toString() + "Error while handling the anvil.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun unsafeTryClickAnvilResultBypass(event: InventoryClickEvent, inventory: AnvilInventory): Boolean {
|
||||||
var bypass = false
|
var bypass = false
|
||||||
|
|
||||||
// Test if disenchantment used event click
|
// Test if disenchantment used event click
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ class AnvilResultListener: Listener {
|
||||||
if (event.rawSlot != ANVIL_OUTPUT_SLOT) {
|
if (event.rawSlot != ANVIL_OUTPUT_SLOT) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if the event should bypass custom anvil.
|
// Test if the event should bypass custom anvil.
|
||||||
if(DependencyManager.tryClickAnvilResultBypass(event, inventory)) return
|
if(DependencyManager.tryClickAnvilResultBypass(event, inventory)) return
|
||||||
|
|
||||||
|
|
@ -52,7 +53,7 @@ class AnvilResultListener: Listener {
|
||||||
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)
|
||||||
|
|
||||||
if(!GameMode.CREATIVE.equals(player.gameMode) && inventory.repairCost >= inventory.maximumRepairCost) {
|
if(GameMode.CREATIVE != player.gameMode && inventory.repairCost >= inventory.maximumRepairCost) {
|
||||||
event.result = Event.Result.DENY
|
event.result = Event.Result.DENY
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +97,6 @@ class AnvilResultListener: Listener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun onCustomCraft(event: InventoryClickEvent,
|
private fun onCustomCraft(event: InventoryClickEvent,
|
||||||
recipe: AnvilCustomRecipe,
|
recipe: AnvilCustomRecipe,
|
||||||
player: Player,
|
player: Player,
|
||||||
|
|
@ -122,7 +122,7 @@ class AnvilResultListener: Listener {
|
||||||
|
|
||||||
// Handle not creative middle click...
|
// Handle not creative middle click...
|
||||||
if (event.click != ClickType.MIDDLE &&
|
if (event.click != ClickType.MIDDLE &&
|
||||||
!handleCustomCraftClick(event, recipe, inventory, player, leftItem, rightItem, amount, xpCost)) return;
|
!handleCustomCraftClick(event, recipe, inventory, player, leftItem, rightItem, amount, xpCost)) return
|
||||||
|
|
||||||
// Finally, we add the item to the player
|
// Finally, we add the item to the player
|
||||||
if (slotDestination.type == SlotType.CURSOR) {
|
if (slotDestination.type == SlotType.CURSOR) {
|
||||||
|
|
@ -222,7 +222,7 @@ class AnvilResultListener: Listener {
|
||||||
resultCopy: ItemStack, resultAmount: Int): Int {
|
resultCopy: ItemStack, resultAmount: Int): Int {
|
||||||
if (player.gameMode == GameMode.CREATIVE) return 0
|
if (player.gameMode == GameMode.CREATIVE) return 0
|
||||||
|
|
||||||
var repairCost = 0;
|
var repairCost = 0
|
||||||
// Get repairCost
|
// Get repairCost
|
||||||
leftItem.itemMeta?.let { leftMeta ->
|
leftItem.itemMeta?.let { leftMeta ->
|
||||||
val leftName = leftMeta.displayName
|
val leftName = leftMeta.displayName
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import xyz.alexcrea.cuanvil.util.AnvilColorUtil
|
||||||
import xyz.alexcrea.cuanvil.util.AnvilXpUtil
|
import xyz.alexcrea.cuanvil.util.AnvilXpUtil
|
||||||
import xyz.alexcrea.cuanvil.util.CustomRecipeUtil
|
import xyz.alexcrea.cuanvil.util.CustomRecipeUtil
|
||||||
import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair
|
import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair
|
||||||
|
import java.util.logging.Level
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener for anvil events
|
* Listener for anvil events
|
||||||
|
|
@ -45,7 +46,7 @@ class PrepareAnvilListener : Listener {
|
||||||
val player: HumanEntity = event.viewers.first()
|
val player: HumanEntity = event.viewers.first()
|
||||||
|
|
||||||
// Test if the event should bypass custom anvil.
|
// Test if the event should bypass custom anvil.
|
||||||
if(DependencyManager.tryEventPreAnvilBypass(event, player)) return
|
if (DependencyManager.tryEventPreAnvilBypass(event, player)) 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
|
||||||
|
|
@ -76,6 +77,7 @@ class PrepareAnvilListener : Listener {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return true if a custom recipe exist with these ingredient
|
||||||
private fun testCustomRecipe(event: PrepareAnvilEvent, inventory: AnvilInventory,
|
private fun testCustomRecipe(event: PrepareAnvilEvent, inventory: AnvilInventory,
|
||||||
player: HumanEntity,
|
player: HumanEntity,
|
||||||
first: ItemStack, second: ItemStack?): Boolean {
|
first: ItemStack, second: ItemStack?): Boolean {
|
||||||
|
|
@ -89,7 +91,7 @@ class PrepareAnvilListener : Listener {
|
||||||
resultItem.amount *= amount
|
resultItem.amount *= amount
|
||||||
|
|
||||||
event.result = resultItem
|
event.result = resultItem
|
||||||
DependencyManager.treatAnvilResult(event, resultItem)
|
if(DependencyManager.tryTreatAnvilResult(event, resultItem)) return true
|
||||||
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, recipe.xpCostPerCraft * amount, true)
|
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, recipe.xpCostPerCraft * amount, true)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
@ -108,7 +110,7 @@ class PrepareAnvilListener : Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
event.result = resultItem
|
event.result = resultItem
|
||||||
DependencyManager.treatAnvilResult(event, resultItem)
|
if(DependencyManager.tryTreatAnvilResult(event, resultItem)) return
|
||||||
|
|
||||||
anvilCost += AnvilXpUtil.calculatePenalty(first, null, resultItem)
|
anvilCost += AnvilXpUtil.calculatePenalty(first, null, resultItem)
|
||||||
|
|
||||||
|
|
@ -116,27 +118,30 @@ class PrepareAnvilListener : Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleRename(resultItem: ItemStack, inventory: AnvilInventory, player: HumanEntity): Int {
|
private fun handleRename(resultItem: ItemStack, inventory: AnvilInventory, player: HumanEntity): Int {
|
||||||
|
// Can be null
|
||||||
|
var inventoryName = ChatColor.stripColor(inventory.renameText)
|
||||||
|
|
||||||
|
var sumCost = 0
|
||||||
|
var useColor = false
|
||||||
|
if(ConfigOptions.renameColorPossible && inventoryName != null){
|
||||||
|
val resultString = StringBuilder(inventoryName)
|
||||||
|
|
||||||
|
useColor = AnvilColorUtil.handleRenamingColor(resultString, player)
|
||||||
|
|
||||||
|
if(useColor) {
|
||||||
|
inventoryName = resultString.toString()
|
||||||
|
|
||||||
|
sumCost+= ConfigOptions.useOfColorCost
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Rename item and add renaming cost
|
// Rename item and add renaming cost
|
||||||
resultItem.itemMeta?.let {
|
resultItem.itemMeta?.let {
|
||||||
val displayName = ChatColor.stripColor(it.displayName)
|
val displayName =
|
||||||
var inventoryName = ChatColor.stripColor(inventory.renameText)
|
if (useColor) it.displayName
|
||||||
|
else ChatColor.stripColor(it.displayName)
|
||||||
|
|
||||||
var sumCost = 0
|
if (!displayName.contentEquals(inventoryName)) {
|
||||||
|
|
||||||
var useColor = false
|
|
||||||
if(ConfigOptions.renameColorPossible){
|
|
||||||
val resultString = StringBuilder(inventoryName)
|
|
||||||
|
|
||||||
useColor = AnvilColorUtil.handleRenamingColor(resultString, player)
|
|
||||||
|
|
||||||
if(useColor) {
|
|
||||||
inventoryName = resultString.toString()
|
|
||||||
|
|
||||||
sumCost+= ConfigOptions.useOfColorCost
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!useColor && (!displayName.contentEquals(inventoryName))) || (useColor && !(it.displayName).contentEquals(inventoryName))) {
|
|
||||||
it.setDisplayName(inventoryName)
|
it.setDisplayName(inventoryName)
|
||||||
resultItem.itemMeta = it
|
resultItem.itemMeta = it
|
||||||
|
|
||||||
|
|
@ -178,11 +183,12 @@ class PrepareAnvilListener : Listener {
|
||||||
|
|
||||||
// Finally, we set result
|
// Finally, we set result
|
||||||
event.result = resultItem
|
event.result = resultItem
|
||||||
DependencyManager.treatAnvilResult(event, resultItem)
|
if(DependencyManager.tryTreatAnvilResult(event, resultItem)) return
|
||||||
|
|
||||||
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, anvilCost)
|
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, anvilCost)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return true if there is a valid unit repair with these ingredients
|
||||||
private fun testUnitRepair(event: PrepareAnvilEvent, inventory: AnvilInventory, player: HumanEntity,
|
private fun testUnitRepair(event: PrepareAnvilEvent, inventory: AnvilInventory, player: HumanEntity,
|
||||||
first: ItemStack, second: ItemStack): Boolean {
|
first: ItemStack, second: ItemStack): Boolean {
|
||||||
val unitRepairAmount = first.getRepair(second) ?: return false
|
val unitRepairAmount = first.getRepair(second) ?: return false
|
||||||
|
|
@ -204,7 +210,7 @@ class PrepareAnvilListener : Listener {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
event.result = resultItem
|
event.result = resultItem
|
||||||
DependencyManager.treatAnvilResult(event, resultItem)
|
if(DependencyManager.tryTreatAnvilResult(event, resultItem)) return true
|
||||||
|
|
||||||
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, anvilCost)
|
AnvilXpUtil.setAnvilInvXp(inventory, event.view, player, anvilCost)
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
package xyz.alexcrea.cuanvil.anvil;
|
package xyz.alexcrea.cuanvil.anvil;
|
||||||
|
|
||||||
|
import io.delilaheve.util.ConfigOptions;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.event.inventory.InventoryType;
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
import org.bukkit.inventory.AnvilInventory;
|
import org.bukkit.inventory.AnvilInventory;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.inventory.meta.Repairable;
|
import org.bukkit.inventory.meta.Repairable;
|
||||||
|
import org.eclipse.aether.util.ConfigUtils;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
|
@ -32,8 +36,9 @@ public class AnvilFuseTests extends SharedCustomAnvilTest {
|
||||||
AnvilFuseTests.anvil = (AnvilInventory) anvil;
|
AnvilFuseTests.anvil = (AnvilInventory) anvil;
|
||||||
player.openInventory(anvil);
|
player.openInventory(anvil);
|
||||||
|
|
||||||
ConfigHolder.DEFAULT_CONFIG.getConfig().set("debug_log", true);
|
ConfigHolder.DEFAULT_CONFIG.getConfig().set(ConfigOptions.DEBUG_LOGGING, true);
|
||||||
ConfigHolder.DEFAULT_CONFIG.getConfig().set("debug_log_verbose", true);
|
ConfigHolder.DEFAULT_CONFIG.getConfig().set(ConfigOptions.VERBOSE_DEBUG_LOGGING, true);
|
||||||
|
ConfigHolder.DEFAULT_CONFIG.getConfig().set(ConfigOptions.ALLOW_COLOR_CODE, true); // For rename test
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
|
|
@ -100,4 +105,23 @@ public class AnvilFuseTests extends SharedCustomAnvilTest {
|
||||||
AnvilFuseTestUtil.executeAnvilTest(anvil, player, data);
|
AnvilFuseTestUtil.executeAnvilTest(anvil, player, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: currently anvil can only have null name. maybe handle differently later
|
||||||
|
@Test
|
||||||
|
public void nullNameResetTest(){
|
||||||
|
ItemStack base = new ItemStack(Material.NETHERITE_SWORD);
|
||||||
|
ItemStack expected = base.clone();
|
||||||
|
|
||||||
|
ItemMeta meta = expected.getItemMeta();
|
||||||
|
meta.displayName(Component.text("test"));
|
||||||
|
base.setItemMeta(meta);
|
||||||
|
|
||||||
|
AnvilFuseTestData data = new AnvilFuseTestData(
|
||||||
|
base, null,
|
||||||
|
expected, expected, null
|
||||||
|
// TODO add expected price
|
||||||
|
);
|
||||||
|
|
||||||
|
AnvilFuseTestUtil.executeAnvilTest(anvil, player, data);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,4 +36,19 @@ public record AnvilFuseTestData(
|
||||||
this(leftItem, rightItem, expectedResult, null
|
this(leftItem, rightItem, expectedResult, null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AnvilFuseTestData(
|
||||||
|
@Nullable ItemStack leftItem,
|
||||||
|
@Nullable ItemStack rightItem,
|
||||||
|
@Nullable ItemStack expectedResult,
|
||||||
|
|
||||||
|
@Nullable ItemStack expectedAfterLeftPlaced,
|
||||||
|
@Nullable ItemStack expectedAfterRightPlaced
|
||||||
|
){
|
||||||
|
this(leftItem, rightItem,
|
||||||
|
expectedResult, expectedAfterLeftPlaced, expectedAfterRightPlaced,
|
||||||
|
null, null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue