lore edit color should work

This commit is contained in:
alexcrea 2025-03-17 14:07:44 +01:00
parent 5f3eed08e2
commit 074313fb7c
No known key found for this signature in database
GPG key ID: 43FD265DB0DBF91F
5 changed files with 259 additions and 45 deletions

View file

@ -30,6 +30,7 @@ import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil
import xyz.alexcrea.cuanvil.util.config.LoreEditType import xyz.alexcrea.cuanvil.util.config.LoreEditType
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import kotlin.collections.ArrayList
import kotlin.math.min import kotlin.math.min
class AnvilResultListener : Listener { class AnvilResultListener : Listener {
@ -348,13 +349,15 @@ class AnvilResultListener : Listener {
// fill book meta // fill book meta
val meta = leftItem.itemMeta val meta = leftItem.itemMeta
if (meta == null || !meta.hasLore()) return false if (meta == null || !meta.hasLore()) return false
val lore = meta.lore!! val lore = ArrayList<String>(meta.lore!!)
if (lore.isEmpty()) return false if (lore.isEmpty()) return false
// Uncolor the page
AnvilLoreEditUtil.uncolorLines(player, lore, LoreEditType.REMOVE_BOOK)
val bookPage = StringBuilder() val bookPage = StringBuilder()
lore.forEach { lore.forEach {
if (bookPage.isNotEmpty()) bookPage.append('\n') if (bookPage.isNotEmpty()) bookPage.append('\n')
//TODO check & do color
bookPage.append(it) bookPage.append(it)
} }
@ -426,10 +429,15 @@ class AnvilResultListener : Listener {
if (lore.isEmpty()) return false if (lore.isEmpty()) return false
val removeEnd = LoreEditConfigUtil.paperLoreOrderIsEnd val removeEnd = LoreEditConfigUtil.paperLoreOrderIsEnd
//TODO check & do color var line = if (removeEnd) lore[lore.size - 1]
val line = if (removeEnd) lore[lore.size - 1]
else lore[0] else lore[0]
// Overkill but uncolor the line
val tempList = ArrayList<String>(1)
tempList.add(line)
AnvilLoreEditUtil.uncolorLines(player, tempList, LoreEditType.REMOVE_PAPER)
line = tempList[0]
// Create result item // Create result item
val rightClone = rightItem.clone() val rightClone = rightItem.clone()
rightClone.amount = 1 rightClone.amount = 1

View file

@ -80,7 +80,7 @@ class PrepareAnvilListener : Listener {
} }
// return true if a custom recipe exist with these ingredient // return true if a custom recipe exist with these ingredients
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 {
@ -134,7 +134,10 @@ class PrepareAnvilListener : Listener {
if(ConfigOptions.renameColorPossible && inventoryName != null){ if(ConfigOptions.renameColorPossible && inventoryName != null){
val resultString = StringBuilder(inventoryName) val resultString = StringBuilder(inventoryName)
useColor = AnvilColorUtil.handleRenamingColor(resultString, player) useColor = AnvilColorUtil.handleColor(resultString, player,
ConfigOptions.permissionNeededForColor,
ConfigOptions.allowColorCode, ConfigOptions.allowHexadecimalColor,
AnvilColorUtil.ColorUseType.RENAME)
if(useColor) { if(useColor) {
inventoryName = resultString.toString() inventoryName = resultString.toString()

View file

@ -1,17 +1,35 @@
package xyz.alexcrea.cuanvil.util package xyz.alexcrea.cuanvil.util
import io.delilaheve.util.ConfigOptions import org.bukkit.permissions.Permissible
import org.bukkit.entity.HumanEntity
import java.util.regex.Matcher import java.util.regex.Matcher
import java.util.regex.Pattern import java.util.regex.Pattern
object AnvilColorUtil { object AnvilColorUtil {
private val HEX_PATTERN: Pattern = Pattern.compile("#[A-Fa-f0-9]{6}") // pattern to find hexadecimal string private val HEX_PATTERN: Pattern = Pattern.compile("#[A-Fa-f0-9]{6}") // pattern to find hexadecimal string
private val TRANSFORMED_HEX_PATTERN = Pattern.compile("§x(§[0-9a-fA-F]){6}") // pattern to find minecraft hex string
fun handleRenamingColor(textToColor: StringBuilder, player: HumanEntity): Boolean { /**
val usePermission = ConfigOptions.permissionNeededForColor * Color a stringbuilder object depending on allowed color type and player permissions on color use type
val canUseColorCode = ConfigOptions.allowColorCode && (!usePermission || player.hasPermission("ca.color.code")) * @return if the stringbuilder was changed and color applied
val canUseHexColor = ConfigOptions.allowHexadecimalColor && (!usePermission || player.hasPermission("ca.color.hex")) */
fun handleColor(
textToColor: StringBuilder,
player: Permissible,
usePermission: Boolean,
allowColorCode: Boolean,
allowHexadecimalColor: Boolean,
useType: ColorUseType
): Boolean {
if (!allowColorCode && !allowHexadecimalColor) return false
val canUseColorCode =
allowColorCode && (!usePermission || useType.colorCodePerm == null || player.hasPermission(
useType.colorCodePerm
))
val canUseHexColor =
allowHexadecimalColor && (!usePermission || useType.hexColorPerm == null || player.hasPermission(
useType.hexColorPerm
))
if ((!canUseColorCode) && (!canUseHexColor)) return false if ((!canUseColorCode) && (!canUseHexColor)) return false
@ -33,6 +51,49 @@ object AnvilColorUtil {
return useColor return useColor
} }
/**
* Revert a stringbuilder to a state where applying handleColor with the same options would give the same result
* @return if the stringbuilder was changed and color unapplied
*/
fun revertColor(
colorToText: StringBuilder,
player: Permissible,
usePermission: Boolean,
allowColorCode: Boolean,
allowHexadecimalColor: Boolean,
useType: ColorUseType
): Boolean {
if (!allowColorCode && !allowHexadecimalColor) return false
val canUseColorCode =
allowColorCode && (!usePermission || useType.colorCodePerm == null || player.hasPermission(
useType.colorCodePerm
))
val canUseHexColor =
allowHexadecimalColor && (!usePermission || useType.hexColorPerm == null || player.hasPermission(
useType.hexColorPerm
))
if ((!canUseColorCode) && (!canUseHexColor)) return false
var hasReversed = false
// Reverse hex pattern
if (canUseHexColor) {
val nbReplacement = replaceHexToColor(colorToText, 14)
if (nbReplacement > 0) hasReversed = true
}
if (canUseColorCode) {
replaceAll(colorToText, "&", "&&", 1)
val nbReplacement = replaceAll(colorToText, "§", "&", 2)
if (nbReplacement > 0) hasReversed = true
}
return hasReversed
}
/** /**
* Replace every instance of "from" to "to". * Replace every instance of "from" to "to".
* @param builder The builder to replace the string from. * @param builder The builder to replace the string from.
@ -70,7 +131,7 @@ object AnvilColorUtil {
while (matcher.find(startIndex)) { while (matcher.find(startIndex)) {
startIndex = matcher.start() startIndex = matcher.start()
if(startIndex >= builder.length - endOffset) break if (startIndex >= builder.length - endOffset) break //HOW AND WHERE WOULD THIS HAPPEN ?????
builder.replace(startIndex, startIndex + 1, "§x") builder.replace(startIndex, startIndex + 1, "§x")
startIndex += 2 startIndex += 2
@ -85,4 +146,41 @@ object AnvilColorUtil {
return numberOfChanges return numberOfChanges
} }
/**
* Replace every hex color from the minecraft format to a format like #000000
* @param builder The builder to replace the minecraft hex color from.
* @param endOffset Amount of character that should be ignored at the end.
* @return The number of replacement was that was done.
*/
private fun replaceColorToHex(builder: StringBuilder, endOffset: Int): Int {
val matcher: Matcher = TRANSFORMED_HEX_PATTERN.matcher(builder)
var numberOfChanges = 0
var startIndex = 0
while (matcher.find(startIndex)) {
startIndex = matcher.start()
if (startIndex >= builder.length - endOffset) break //HOW AND WHERE WOULD THIS HAPPEN ?????
builder.replace(startIndex, startIndex + 2, "#")
startIndex += 1
for (i in 0..5) {
builder.deleteCharAt(startIndex)
startIndex += 1
}
numberOfChanges += 1
}
return numberOfChanges
}
enum class ColorUseType(
val colorCodePerm: String?,
val hexColorPerm: String?
) {
RENAME("ca.color.code", "ca.color.hex"),
LORE_EDIT(null, null)
}
} }

View file

@ -35,16 +35,21 @@ object AnvilLoreEditUtil {
ArrayList<String>(meta.lore!!) ArrayList<String>(meta.lore!!)
} else ArrayList() } else ArrayList()
//TODO check color if color if enabled val page = book.pages[0]
val lines = book.pages[0].split("\n") val lines = ArrayList<String>(page.split("\n"))
val colorCost = colorLines(player, lines, LoreEditType.APPEND_BOOK)
lore.addAll(lines) lore.addAll(lines)
meta.lore = lore meta.lore = lore
result.itemMeta = meta result.itemMeta = meta
// Handle other xp if (result == first) return null
xpCost.addAndGet(lines.size * LoreEditType.APPEND_BOOK.perLineCost)
xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.APPEND_BOOK)) // Handle xp
xpCost.addAndGet(colorCost) // Cost of using color
xpCost.addAndGet(lines.size * LoreEditType.APPEND_BOOK.perLineCost) // per line cost
xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.APPEND_BOOK)) // Fixed cost and work penalty
return result return result
} }
@ -55,19 +60,24 @@ object AnvilLoreEditUtil {
// remove lore // remove lore
val result = first.clone() val result = first.clone()
val leftMeta = result.itemMeta ?: return null val leftMeta = result.itemMeta ?: return null
val currentLore = leftMeta.lore?: return null val currentLore = ArrayList<String>(leftMeta.lore ?: return null)
val uncolorCost = uncolorLines(player, currentLore, LoreEditType.REMOVE_BOOK)
leftMeta.lore = null leftMeta.lore = null
result.itemMeta = leftMeta result.itemMeta = leftMeta
// Handle other xp if (result == first) return null
// Handle xp
xpCost.addAndGet(uncolorCost)
xpCost.addAndGet(currentLore.size * LoreEditType.REMOVE_BOOK.perLineCost) xpCost.addAndGet(currentLore.size * LoreEditType.REMOVE_BOOK.perLineCost)
xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.REMOVE_BOOK)) xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.REMOVE_BOOK))
return result return result
} }
// Return true if append, false if remove, null if neither // Return true if appended, false if removed, null if neither
fun bookLoreEditIsAppend(first: ItemStack, second: ItemStack): Boolean? { fun bookLoreEditIsAppend(first: ItemStack, second: ItemStack): Boolean? {
// Test if the book & quil contain content // Test if the book & quil contain content
val meta = second.itemMeta as BookMeta? ?: return false val meta = second.itemMeta as BookMeta? ?: return false
@ -106,7 +116,7 @@ object AnvilLoreEditUtil {
else handleLoreRemoveByBook(player, first, xpCost) else handleLoreRemoveByBook(player, first, xpCost)
} }
// Return true if append, false if remove, null if neither // Return true if appended, false if removed, null if neither
fun paperLoreEditIsAppend(first: ItemStack, second: ItemStack): Boolean? { fun paperLoreEditIsAppend(first: ItemStack, second: ItemStack): Boolean? {
// Test if the paper contain a display name // Test if the paper contain a display name
val meta = second.itemMeta ?: return false val meta = second.itemMeta ?: return false
@ -134,24 +144,31 @@ object AnvilLoreEditUtil {
if (!hasLoreEditByPaperPermission(player)) return null if (!hasLoreEditByPaperPermission(player)) return null
val result = first.clone() val result = first.clone()
val meta = result.itemMeta val meta = result.itemMeta?: return null
val lore = if (meta?.hasLore() == true) { val lore = if (meta.hasLore()) {
ArrayList<String>(meta.lore!!) ArrayList<String>(meta.lore!!)
} else ArrayList() } else ArrayList()
val appendEnd = LoreEditConfigUtil.paperLoreOrderIsEnd val appendEnd = LoreEditConfigUtil.paperLoreOrderIsEnd
//TODO check color if color if enabled // A bit overdone to color 1 line but hey
val line = second.itemMeta!!.displayName val tempList = ArrayList<String>(1)
tempList.add(second.itemMeta!!.displayName)
val colorCost = colorLines(player, tempList, LoreEditType.APPEND_PAPER)
val line = tempList[0]
if (appendEnd) if (appendEnd)
lore.add(line) lore.add(line)
else else
lore.add(0, line) lore.add(0, line)
meta?.lore = lore meta.lore = lore
result.itemMeta = meta result.itemMeta = meta
// Handle other xp if (result == first) return null
// Handle xp
xpCost.addAndGet(colorCost)
xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.APPEND_PAPER)) xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.APPEND_PAPER))
return result return result
@ -167,13 +184,21 @@ object AnvilLoreEditUtil {
val removeEnd = LoreEditConfigUtil.paperLoreOrderIsEnd val removeEnd = LoreEditConfigUtil.paperLoreOrderIsEnd
val lore: ArrayList<String> = ArrayList(meta.lore!!) val lore: ArrayList<String> = ArrayList(meta.lore!!)
if (removeEnd) lore.removeAt(lore.size - 1) val line = if (removeEnd) lore.removeAt(lore.size - 1)
else lore.removeAt(0) else lore.removeAt(0)
meta.lore = if (lore.isEmpty()) null else lore meta.lore = if (lore.isEmpty()) null else lore
result.itemMeta = meta result.itemMeta = meta
// Get color cost to uncolor this line
val tempList = ArrayList<String>(1)
tempList.add(line)
val uncolorCost = uncolorLines(player, tempList, LoreEditType.REMOVE_PAPER)
if (result == first) return null
// Handle other xp // Handle other xp
xpCost.addAndGet(uncolorCost)
xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.REMOVE_PAPER)) xpCost.addAndGet(baseEditLoreXpCost(first, result, LoreEditType.REMOVE_PAPER))
return result return result
@ -202,4 +227,86 @@ object AnvilLoreEditUtil {
return xpCost return xpCost
} }
private fun colorLines(player: Permissible, lines: ArrayList<String>, useType: LoreEditType): Int {
val canUseHex: Boolean
val canUseColorCode: Boolean
val colorCost: Int
// If is book
if (useType == LoreEditType.REMOVE_BOOK || useType == LoreEditType.APPEND_BOOK) {
canUseHex = LoreEditConfigUtil.bookAllowHexColor
canUseColorCode = LoreEditConfigUtil.bookAllowColorCode
colorCost = LoreEditConfigUtil.bookUseColorCost
} // Else if is paper
else {
canUseHex = LoreEditConfigUtil.paperAllowHexColor
canUseColorCode = LoreEditConfigUtil.paperAllowColorCode
colorCost = LoreEditConfigUtil.paperUseColorCost
}
// Now handle color of each lines
var hasUsedColor = false
for ((index, line) in lines.withIndex()) {
val coloredLine = StringBuilder(line)
val lineUsedColor = AnvilColorUtil.handleColor(
coloredLine,
player,
false, canUseColorCode, canUseHex,
AnvilColorUtil.ColorUseType.LORE_EDIT
)
if (lineUsedColor) {
hasUsedColor = true
lines[index] = coloredLine.toString()
}
}
return if (hasUsedColor) {
colorCost
} else {
0
}
}
fun uncolorLines(player: Permissible, lines: ArrayList<String>, useType: LoreEditType): Int {
val canUseHex: Boolean
val canUseColorCode: Boolean
val colorCost: Int
// If is book
if (useType == LoreEditType.REMOVE_BOOK || useType == LoreEditType.APPEND_BOOK) {
canUseHex = LoreEditConfigUtil.bookAllowHexColor
canUseColorCode = LoreEditConfigUtil.bookAllowColorCode
colorCost = LoreEditConfigUtil.bookUseColorCost
} // Else if is paper
else {
canUseHex = LoreEditConfigUtil.paperAllowHexColor
canUseColorCode = LoreEditConfigUtil.paperAllowColorCode
colorCost = LoreEditConfigUtil.paperUseColorCost
}
// Now handle color of each lines
var hasUndidColor = false
for ((index, line) in lines.withIndex()) {
val uncoloredLine = StringBuilder(line)
val lineUndidColor = AnvilColorUtil.revertColor(
uncoloredLine,
player,
false, canUseColorCode, canUseHex,
AnvilColorUtil.ColorUseType.LORE_EDIT
)
if (lineUndidColor) {
hasUndidColor = true
lines[index] = uncoloredLine.toString()
}
}
return if (hasUndidColor) {
colorCost
} else {
0
}
}
} }

View file

@ -8,8 +8,6 @@ object LoreEditConfigUtil {
const val IS_ENABLED = "enabled" const val IS_ENABLED = "enabled"
const val FIXED_COST = "fixed_cost" const val FIXED_COST = "fixed_cost"
const val PER_LINE_COST = "per_line_cost" const val PER_LINE_COST = "per_line_cost"
const val USE_COST_PENALTY = "use_cost_penalty"
const val INCREASE_COST_PENALTY = "increase_cost_penalty"
const val DO_CONSUME = "do_consume" const val DO_CONSUME = "do_consume"
// Permission configs path // Permission configs path
@ -61,8 +59,8 @@ object LoreEditConfigUtil {
val FIXED_COST_RANGE = 0..1000 val FIXED_COST_RANGE = 0..1000
val PER_LINE_COST_RANGE = 0..1000 val PER_LINE_COST_RANGE = 0..1000
val COLOR_BOOK_COST_RANGE = 0..1000 private val COLOR_BOOK_COST_RANGE = 0..1000
val COLOR_PAPER_COST_RANGE = 0..1000 private val COLOR_PAPER_COST_RANGE = 0..1000
// ------------------- // -------------------
// Generic Get methods // Generic Get methods