Per color code permission (#114)

Add ability to have color code restricted by a specific permission for
each color code
This commit is contained in:
alexcrea 2026-05-22 23:48:33 +02:00 committed by GitHub
commit 90cc758e88
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 119 additions and 20 deletions

View file

@ -77,6 +77,18 @@ allow_color_code: false
allow_hexadecimal_color: false
allow_minimessage: false
# This enables restricting color code for player having specific permission
# It requires allow_color_code enabled for... obvious reasons
#
# For example: if player want to use "&aHello" it will be required that the player has
# the permission "ca.color.code.a" as he used the color code "a"
# In general permission to give to the player is "ca.color.code.[code]"
# where [code] is the color code you wish to allow the player
#
# It is kinda of useless when minimessage is supported as players would be able to bypass
# that using the equivalent minimessage tag
per_color_code_permission: false
# Toggle if color should only be applicable if the player a certain permission.
#
# permission are "ca.color.code" for use of color code and "ca.color.hex" for use of hexadecimal color.

View file

@ -79,6 +79,18 @@ allow_color_code: false
allow_hexadecimal_color: false
allow_minimessage: false
# This enables restricting color code for player having specific permission
# It requires allow_color_code enabled for... obvious reasons
#
# For example: if player want to use "&aHello" it will be required that the player has
# the permission "ca.color.code.a" as he used the color code "a"
# In general permission to give to the player is "ca.color.code.[code]"
# where [code] is the color code you wish to allow the player
#
# It is kinda of useless when minimessage is supported as players would be able to bypass
# that using the equivalent minimessage tag
per_color_code_permission: false
# Toggle if color should only be applicable if the player a certain permission.
#
# permission are "ca.color.code" for use of color code and "ca.color.hex" for use of hexadecimal color.

View file

@ -77,6 +77,18 @@ allow_color_code: false
allow_hexadecimal_color: false
allow_minimessage: false
# This enables restricting color code for player having specific permission
# It requires allow_color_code enabled for... obvious reasons
#
# For example: if player want to use "&aHello" it will be required that the player has
# the permission "ca.color.code.a" as he used the color code "a"
# In general permission to give to the player is "ca.color.code.[code]"
# where [code] is the color code you wish to allow the player
#
# It is kinda of useless when minimessage is supported as players would be able to bypass
# that using the equivalent minimessage tag
per_color_code_permission: false
# Toggle if color should only be applicable if the player a certain permission.
#
# permission are "ca.color.code" for use of color code and "ca.color.hex" for use of hexadecimal color.

View file

@ -77,6 +77,18 @@ allow_color_code: false
allow_hexadecimal_color: false
allow_minimessage: false
# This enables restricting color code for player having specific permission
# It requires allow_color_code enabled for... obvious reasons
#
# For example: if player want to use "&aHello" it will be required that the player has
# the permission "ca.color.code.a" as he used the color code "a"
# In general permission to give to the player is "ca.color.code.[code]"
# where [code] is the color code you wish to allow the player
#
# It is kinda of useless when minimessage is supported as players would be able to bypass
# that using the equivalent minimessage tag
per_color_code_permission: false
# Toggle if color should only be applicable if the player a certain permission.
#
# permission are "ca.color.code" for use of color code and "ca.color.hex" for use of hexadecimal color.

View file

@ -2,7 +2,6 @@ package io.delilaheve.util
import io.delilaheve.CustomAnvil
import io.delilaheve.util.EnchantmentUtil.enchantmentName
import org.bukkit.Material
import org.bukkit.NamespacedKey
import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.config.WorkPenaltyType
@ -45,6 +44,8 @@ object ConfigOptions {
const val PERMISSION_NEEDED_FOR_COLOR = "permission_needed_for_color"
const val USE_OF_COLOR_COST = "use_of_color_cost"
const val PER_COLOR_CODE_PERMISSION = "per_color_code_permission"
// Work penalty config
const val WORK_PENALTY_ROOT = "work_penalty"
const val WORK_PENALTY_INCREASE = "shared_increase"
@ -100,6 +101,8 @@ object ConfigOptions {
const val DEFAULT_PERMISSION_NEEDED_FOR_COLOR = true
const val DEFAULT_USE_OF_COLOR_COST = 0
const val DEFAULT_PER_COLOR_CODE_PERMISSION = false
// Debug flag
private const val DEFAULT_DEBUG_LOG = false
private const val DEFAULT_VERBOSE_DEBUG_LOG = false
@ -297,6 +300,16 @@ object ConfigOptions {
.getBoolean(PERMISSION_NEEDED_FOR_COLOR, DEFAULT_PERMISSION_NEEDED_FOR_COLOR)
}
/**
* Should each color code require a permission
*/
val usePerColorCodePermission: Boolean
get() {
return ConfigHolder.DEFAULT_CONFIG
.config
.getBoolean(PER_COLOR_CODE_PERMISSION, DEFAULT_PER_COLOR_CODE_PERMISSION)
}
/**
* How many xp should use of color should cost
*/

View file

@ -1,5 +1,6 @@
package xyz.alexcrea.cuanvil.util
import io.delilaheve.util.ConfigOptions
import net.kyori.adventure.text.Component
import org.bukkit.permissions.Permissible
import java.util.regex.Matcher
@ -13,7 +14,8 @@ object AnvilColorUtil {
class ColorPermissions(
val canUseColorCode: Boolean,
val canUseHexColor: Boolean,
val canUseMinimessage: Boolean
val canUseMinimessage: Boolean,
val permissible: Permissible, // source of the permission. tried to avoid needing it but meh
) {
fun allowed(): Boolean {
return canUseColorCode || canUseHexColor || canUseMinimessage
@ -36,7 +38,8 @@ object AnvilColorUtil {
return ColorPermissions(
canUseColorCode = false,
canUseHexColor = false,
canUseMinimessage = false
canUseMinimessage = false,
player,
)
val canUseColorCode =
@ -54,7 +57,7 @@ object AnvilColorUtil {
useType.hexColorPerm
))
return ColorPermissions(canUseColorCode, canUseHexColor, canUseMinimessage)
return ColorPermissions(canUseColorCode, canUseHexColor, canUseMinimessage, player)
}
/**
@ -70,9 +73,11 @@ object AnvilColorUtil {
allowMinimessage: Boolean,
useType: ColorUseType
): Component? {
val permission = calculatePermissions(player, usePermission,
val permission = calculatePermissions(
player, usePermission,
allowColorCode, allowHexadecimalColor, allowMinimessage,
useType)
useType
)
return handleColor(textToColorText, permission)
}
@ -82,9 +87,10 @@ object AnvilColorUtil {
*/
fun handleColor(
textToColorText: String,
permission: ColorPermissions
): Component? {
if(!permission.allowed()) return null
permission: ColorPermissions,
): Component? {
if (!permission.allowed()) return null
val textToColor = StringBuilder(textToColorText)
var useColor = false
@ -93,7 +99,12 @@ object AnvilColorUtil {
var nbReplacement = replaceAll(textToColor, "&", "§", 2)
nbReplacement -= 2 * replaceAll(textToColor, "§§", "&", 2)
if (nbReplacement > 0) useColor = true
if (nbReplacement > 0) {
useColor = true
if (ConfigOptions.usePerColorCodePermission)
filterPermissibleColorCode(textToColor, permission.permissible)
}
}
if (permission.canUseHexColor) {
@ -104,23 +115,38 @@ object AnvilColorUtil {
val previousStr = textToColor.toString()
var result: Component = MiniMessageUtil.legacy_mm.deserialize(previousStr)
if(permission.canUseMinimessage) {
if (permission.canUseMinimessage) {
// we dance with formats here
val toMinimessage = MiniMessageUtil.mm.serialize(result)
val hackySolution = toMinimessage.replace("\\<", "<")
val fromMinimessage = MiniMessageUtil.mm.deserialize(hackySolution)
val asPlain = MiniMessageUtil.plain_text_mm.serialize(fromMinimessage)
if(previousStr != asPlain){
if (previousStr != asPlain) {
useColor = true
result = fromMinimessage
}
}
return if(useColor) result
return if (useColor) result
else null
}
private fun filterPermissibleColorCode(textToColor: StringBuilder, player: Permissible) {
var index = 0
while (true) {
index = textToColor.indexOf('§', index)
if (index == -1 || index == textToColor.length - 1) return
val next = textToColor[index + 1]
// check permission for this color
if(!player.hasPermission("ca.color.code.$next"))
textToColor.replace(index, index + 1, "&")
index++
}
}
/**
* Best effort to revert a component to the smallest allowed string
* that would result in it getting closest as possible to handleColor
@ -131,12 +157,12 @@ object AnvilColorUtil {
component: Component?,
permission: ColorPermissions
): String? {
if(!permission.allowed() || component == null) return null
if (!permission.allowed() || component == null) return null
val transformed = MiniMessageUtil.mm.serialize(component)
val plainTransform = MiniMessageUtil.plain_text_mm.serialize(component)
if(transformed == plainTransform) return null
if(permission.onlyMinimessage()){
if (transformed == plainTransform) return null
if (permission.onlyMinimessage()) {
return transformed
}
@ -164,10 +190,10 @@ object AnvilColorUtil {
val hackySolution = hackySolutionStb.toString()
val result: String =
if(permission.canUseMinimessage) hackySolution
if (permission.canUseMinimessage) hackySolution
else MiniMessageUtil.mm.stripTags(hackySolution)
return if(result == plainTransform) null
return if (result == plainTransform) null
else result
}
@ -209,7 +235,7 @@ object AnvilColorUtil {
while (matcher.find(startIndex)) {
startIndex = matcher.start()
if (startIndex >= builder.length - endOffset) break //HOW AND WHERE WOULD THIS HAPPEN ?????
if(checkTag && isInTag(builder, startIndex)) {
if (checkTag && isInTag(builder, startIndex)) {
startIndex += 1 // Avoid infinite loop
continue
}
@ -237,7 +263,7 @@ object AnvilColorUtil {
var rightIndex = left.lastIndexOf(">")
// last < do not exist or is before last >
if(leftIndex == -1 || rightIndex > leftIndex) return false
if (leftIndex == -1 || rightIndex > leftIndex) return false
val right = builder.slice(index..<builder.length)
val newleftIndex = right.indexOf("<")

View file

@ -79,6 +79,18 @@ allow_color_code: false
allow_hexadecimal_color: false
allow_minimessage: false
# This enables restricting color code for player having specific permission
# It requires allow_color_code enabled for... obvious reasons
#
# For example: if player want to use "&aHello" it will be required that the player has
# the permission "ca.color.code.a" as he used the color code "a"
# In general permission to give to the player is "ca.color.code.[code]"
# where [code] is the color code you wish to allow the player
#
# It is kinda of useless when minimessage is supported as players would be able to bypass
# that using the equivalent minimessage tag
per_color_code_permission: false
# Toggle if color should only be applicable if the player a certain permission.
#
# permission are "ca.color.code" for use of color code and "ca.color.hex" for use of hexadecimal color.