Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add configurable maximum durability feature via config key "Item-Durability" #16

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/main/java/com/cjcrafter/armormechanics/ArmorMechanics.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package com.cjcrafter.armormechanics

import com.cjcrafter.armormechanics.commands.Command
import com.cjcrafter.armormechanics.durability.registerDurabilityPlaceholders
import com.cjcrafter.armormechanics.listeners.*
import listeners.ArmorEquipListener
import me.cjcrafter.auto.UpdateChecker
import me.cjcrafter.auto.UpdateInfo
import me.deecaad.core.MechanicsCore
import me.deecaad.core.events.QueueSerializerEvent
import me.deecaad.core.file.BukkitConfig
import me.deecaad.core.file.SerializeData
import me.deecaad.core.file.SerializerException
import me.deecaad.core.file.TaskChain
import me.deecaad.core.lib.adventure.text.serializer.legacy.LegacyComponentSerializer
import me.deecaad.core.utils.Debugger
import me.deecaad.core.utils.FileUtil
import me.deecaad.core.utils.LogLevel
import me.deecaad.core.utils.ReflectionUtil
import me.deecaad.core.utils.StringUtil
import org.bstats.bukkit.Metrics
import org.bstats.charts.SimplePie
import org.bukkit.Bukkit
Expand Down Expand Up @@ -51,6 +55,7 @@ class ArmorMechanics : JavaPlugin() {
server.pluginManager.disablePlugin(this)
return
}
registerDurabilityPlaceholders()
}

override fun onEnable() {
Expand All @@ -62,6 +67,7 @@ class ArmorMechanics : JavaPlugin() {
pm.registerEvents(ArmorUpdateListener(), this)
pm.registerEvents(BlockPlaceListener(), this)
pm.registerEvents(DamageMechanicListener(), this)
pm.registerEvents(DurabilityListener(), this)
pm.registerEvents(ImmunePotionCanceller(), this)
pm.registerEvents(PreventRemoveListener(), this)

Expand Down Expand Up @@ -100,6 +106,9 @@ class ArmorMechanics : JavaPlugin() {
})
.thenRunSync(Runnable {
reloadConfig()
// Reload durability prefix and format
CJCrafter marked this conversation as resolved.
Show resolved Hide resolved
DURABILITY_PREFIX = LegacyComponentSerializer.legacySection().serialize(MechanicsCore.getPlugin().message.deserialize(StringUtil.colorAdventure(config.getString("Durability_Prefix"))!!))
DURABILITY_FORMAT = StringUtil.colorAdventure(config.getString("Durability_Format"))!!

// Clear old data
effects.clear()
Expand Down Expand Up @@ -202,5 +211,7 @@ class ArmorMechanics : JavaPlugin() {

companion object {
lateinit var INSTANCE: ArmorMechanics
lateinit var DURABILITY_PREFIX: String
lateinit var DURABILITY_FORMAT: String
}
}
30 changes: 28 additions & 2 deletions src/main/java/com/cjcrafter/armormechanics/ArmorSerializer.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.cjcrafter.armormechanics

import me.deecaad.core.compatibility.CompatibilityAPI
import com.cjcrafter.armormechanics.durability.DurabilityManager.setDurability
import com.cjcrafter.armormechanics.durability.DurabilityManager.setMaxDurability
import me.deecaad.core.file.SerializeData
import me.deecaad.core.file.SerializerException
import me.deecaad.core.file.serializers.ItemSerializer
import me.deecaad.core.utils.AdventureUtil
import me.deecaad.core.lib.adventure.text.serializer.legacy.LegacyComponentSerializer
import me.deecaad.core.placeholder.PlaceholderData
import me.deecaad.core.placeholder.PlaceholderMessage
import me.deecaad.weaponmechanics.utils.CustomTag
import org.bukkit.inventory.ItemStack
import javax.annotation.Nonnull
Expand All @@ -20,6 +23,29 @@ class ArmorSerializer : ItemSerializer() {
"Material was not a valid armor type",
SerializerException.forValue(item.type)
)


if (data.has("Item_Durability")) {
val durability = data.of("Item_Durability").getInt(0)
if (durability > 0) {
setDurability(item, durability)
setMaxDurability(item, durability)
val meta = item.itemMeta
val lore = ArrayList<String>()
if (meta!!.hasLore()) {
lore.addAll(meta.lore!!)
}
val placeholderMessage = PlaceholderMessage(ArmorMechanics.DURABILITY_FORMAT)
val component = placeholderMessage.replaceAndDeserialize(PlaceholderData.of(null, item, null, null))
val legacy = LegacyComponentSerializer.legacySection().serialize(component)
lore.add(ArmorMechanics.DURABILITY_PREFIX + legacy)
meta.lore = lore
item.itemMeta = meta
}
}



val title = data.key
val effect = data.of("Bonus_Effects").serialize(BonusEffect::class.java)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.cjcrafter.armormechanics.durability

import com.cjcrafter.armormechanics.ArmorMechanics
import me.deecaad.core.compatibility.CompatibilityAPI
import me.deecaad.core.lib.adventure.text.serializer.legacy.LegacyComponentSerializer
import me.deecaad.core.placeholder.PlaceholderData
import me.deecaad.core.placeholder.PlaceholderMessage
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.Damageable
import org.bukkit.inventory.meta.ItemMeta

object DurabilityManager {
fun changeDurability(item: ItemStack, change: Int) {
if (getDurability(item) == -1) {
return
}
var durability = getDurability(item)
val maxDurability = getMaxDurability(item)
durability = Math.min(durability + change, maxDurability)
setDurability(item, durability)
val damageable = item.itemMeta
if (damageable !is Damageable) {
return
}

if (durability > 0) {
damageable.damage = item.type.maxDurability - (durability * item.type.maxDurability) / maxDurability
if ((damageable as ItemMeta).hasLore()) {
val lore: ArrayList<String> = ArrayList((damageable as ItemMeta).lore!!)
val loreClone = lore.toMutableList()
val index = loreClone.indexOfFirst { it.startsWith(ArmorMechanics.DURABILITY_PREFIX) }
val placeholderMessage = PlaceholderMessage(ArmorMechanics.DURABILITY_FORMAT)
val component = placeholderMessage.replaceAndDeserialize(PlaceholderData.of(null, item, null, null))
val legacy = LegacyComponentSerializer.legacySection().serialize(component)
loreClone[index] = ArmorMechanics.DURABILITY_PREFIX + legacy
(damageable as ItemMeta).lore = loreClone
} else {
(damageable as ItemMeta).lore = listOf(
ArmorMechanics.DURABILITY_PREFIX + LegacyComponentSerializer.legacySection().serialize(
PlaceholderMessage(
ArmorMechanics.DURABILITY_FORMAT
).replaceAndDeserialize(PlaceholderData.of(null, item, null, null))
)
)
}
} else {
damageable.damage = item.type.maxDurability.toInt()
item.amount = 0
}
item.itemMeta = damageable
}

fun getMaxDurability(item: ItemStack): Int {
return if (CompatibilityAPI.getNBTCompatibility().hasInt(item, "ArmorMechanics", "armor-durability-max")) {
CompatibilityAPI.getNBTCompatibility().getInt(item, "ArmorMechanics", "armor-durability-max")
} else -1
}

fun getDurability(item: ItemStack): Int {
return if (CompatibilityAPI.getNBTCompatibility().hasInt(item, "ArmorMechanics", "armor-durability")) {
CompatibilityAPI.getNBTCompatibility().getInt(item, "ArmorMechanics", "armor-durability")
} else -1
}

fun setMaxDurability(item: ItemStack, value: Int) {
CompatibilityAPI.getNBTCompatibility().setInt(item, "ArmorMechanics", "armor-durability-max", value)
}

fun setDurability(item: ItemStack, value: Int) {
CompatibilityAPI.getNBTCompatibility().setInt(item, "ArmorMechanics", "armor-durability", value)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.cjcrafter.armormechanics.durability

import me.deecaad.core.placeholder.NumericPlaceholderHandler
import me.deecaad.core.placeholder.PlaceholderData
import me.deecaad.core.placeholder.PlaceholderHandler

fun registerDurabilityPlaceholders() {
PlaceholderHandler.REGISTRY.add(object : DurabilityPlaceholderHandler() {})
PlaceholderHandler.REGISTRY.add(object : MaxDurabilityPlaceholderHandler() {})
}
abstract class DurabilityPlaceholderHandler : NumericPlaceholderHandler("durability_current") {
LiberaTeMetuMortis marked this conversation as resolved.
Show resolved Hide resolved
override fun requestValue(p0: PlaceholderData): Number? {
return DurabilityManager.getDurability(p0.item()!!)
}
}

abstract class MaxDurabilityPlaceholderHandler : NumericPlaceholderHandler("durability_max") {
override fun requestValue(p0: PlaceholderData): Number? {
return DurabilityManager.getMaxDurability(p0.item()!!)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.cjcrafter.armormechanics.listeners

import com.cjcrafter.armormechanics.durability.DurabilityManager.changeDurability
import com.cjcrafter.armormechanics.durability.DurabilityManager.getDurability
import me.deecaad.core.compatibility.CompatibilityAPI
import org.bukkit.Material
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.inventory.PrepareAnvilEvent
import org.bukkit.event.inventory.PrepareItemCraftEvent
import org.bukkit.event.player.PlayerItemDamageEvent
import org.bukkit.event.player.PlayerItemMendEvent
import org.bukkit.inventory.ItemStack

class DurabilityListener : Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
fun onItemDamaged(event: PlayerItemDamageEvent) {
changeDurability(event.item, -event.damage)
}

@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
fun onItemMend(event: PlayerItemMendEvent) {
changeDurability(event.item, event.repairAmount)
}

@EventHandler
fun onRepairAnvil(event: PrepareAnvilEvent) {
var totalDurability = 0
val contents = event.inventory.contents.filter{ it != null && it.type != Material.AIR }
if (contents.size != 2) {
event.result = null
return
}
val resultItem: ItemStack = event.result ?: return
val titles = ArrayList<String>()
contents.forEach { item ->
if (item != null && item.type.maxDurability > 0) {
val title =
CompatibilityAPI.getNBTCompatibility().getString(item, "ArmorMechanics", "armor-title")
titles.add(title)
totalDurability += getDurability(item)
}
}
if (titles.distinct().size != 1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see 3 or 4 data structures being created and I can't tell what this is supposed to be doing. I also side some side effects for non armor mechanics items...

e.g.

        if (contents.size != 2) {
            event.result = null
            return
        }

Why set the result to null? Why not just return? Seems like this might interfere with vanilla behavior or other plugins when we don't even know if there was an ArmorMechanics item involved.

e.g.

if (titles.distinct().size != 1)

This line and the loop above it uses 2 data structures to accomplish what a simple kotlin optional could handle.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood the side effect part, will fix that.

This listener basically does:
For example we have an ArmorMechanics item "X"
When player tries to repair their X using another X in anvil plugin should return item with correct durability.

The reason I check distinct title size is for being sure they are not trying to fix X using Y (another ArmorMechanics item).

To get rid of data types I can probably just use one loop that is like:
for item in event.inventory.items
Continue if item is Air or Null
Add title of the item to titles Set (will check set size after loop is done)
Total durability += Durability of the item
Do you think this is what should be done?

event.result = null
return
}
changeDurability(resultItem, totalDurability-getDurability(resultItem))
event.result = resultItem
}

@EventHandler
fun onRepairCraft(event: PrepareItemCraftEvent) {
if (!event.isRepair) return
var totalDurability = 0
val contents = event.inventory.contents.drop(1).filter{ it != null && it.type != Material.AIR }
val resultItem: ItemStack = contents[0].clone()
val titles = ArrayList<String>()
contents.forEach { item ->
if (item != null && item.type.maxDurability > 0) {
val title =
CompatibilityAPI.getNBTCompatibility().getString(item, "ArmorMechanics", "armor-title")
titles.add(title)
totalDurability += getDurability(item)
}
}
if (titles.distinct().size != 1) {
event.inventory.result = null
return
}
changeDurability(resultItem, totalDurability - getDurability(resultItem))
event.inventory.result = resultItem
}
}
7 changes: 6 additions & 1 deletion src/main/resources/ArmorMechanics/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ Delete_Old_Armor: false
# Whenever you update your armor, I *HIGHLY SUGGEST* you run a /restart on your
# server instead of just a /am reload. This will force all players to relog and
# their armor will be updated.
Update_Armor: true
Update_Armor: true

# These settings are for setting maximum durability for armor.
# You can use Item_Durability attribute on armors to use this feature.
Durability_Prefix: '<gray>Durability: '
Durability_Format: "<green><durability_current><white>/<green><durability_max>"