ChestShop-authors / ChestShop-3

ChestShop - the chest & sign shop plugin for Minecraft Servers running Bukkit/Spigot/Paper
https://dev.bukkit.org/projects/chestshop
GNU Lesser General Public License v2.1
272 stars 178 forks source link

Ignore formatting colors when parsing shop signs #503

Closed MrPowerGamerBR closed 2 years ago

MrPowerGamerBR commented 2 years ago

Is your feature request related to a problem? Please describe.

I always wanted to use formatting colors because plain black colored shop signs are boooring, something like:

§1Player Name
Quantity
§aB 10§f:§4S 10
§9Item Name

However, while you could set the colors on the sign via an external plugin, ChestShop ends up not recognizing the sign ("The shop cannot be used!"), even if the text itself is still the same, because ChestShop doesn't strip the chat colors from the sign lines before trying to parse it.

So it would be nice if ChestShop ignored formatting codes when parsing the sign, to allow custom colors on the sign lines themselves.

Describe the solution you'd like

Strip chat colors from signs before parsing them via ChestShop. I don't think this would cause issues with current shops (in my experience, I didn't have any). Doing this would also open new doors for features like the one described in #365.

Currently I use my own fork to do this:

But it could be better, my version is too hacky and non customizable.

Describe alternatives you've considered

While players can already dye their shop signs, but in this case I want to set the color themselves to be consistent.

Dyed signs work because the sign color is not set via formatting colors on the sign lines, they are set in the sign NBT itself.

Agreements

Additional context

thanks for reading :3

Phoenix616 commented 2 years ago

The commit should now at least allow shops which's lines had formatting added externally but creating it with formatting directly on the sign will still not be possible due to the plugin setting the lines to non-formatted ones on creation. I'm unsure if this should/can be allowed moving forward with format-able signs or if a global formatting config like requested in other places previously would be a better (and cleaner) way to handle that.

This is kinda related to #237 too I guess.

MrPowerGamerBR commented 2 years ago

@Phoenix616 I tested it with a very simple event handler that listens to the PreShopCreationEvent and then prepends chat colors to each line:

    @EventHandler(priority = EventPriority.MONITOR)
    fun onChange(e: PreShopCreationEvent) {
        e.setSignLine(0, "§1" + e.getSignLine(0))
        e.setSignLine(1, "§e" + e.getSignLine(1))
        e.setSignLine(2, "§a" + e.getSignLine(2))
        e.setSignLine(3, ChatColor.of(Color(179, 255, 219)).toString() + e.getSignLine(3)) // let's throw a RGB color in here too why not

        e.signLines.forEach {
            println(it.replace("§", "&"))
        }
    }

image

image

(would be nice if the API supported Adventure components but hey if it works I ain't complaining 😛)

And it seems that it works fine! :3 I only wanted to colorize the signs, but keep the sign formatting, so your changes are already good enough for me.

However I haven't tested on my public server yet to see if there are going to be any issues there, but I think this will work fine for my needs! If I end up finding any issues when testing it on my public server I will be sure to tell it here.

But yeah: For non programmers it would be nice if there was a configuration section to set the color formatting there.

But thanks for implementing this! Now I don't need to keep my hacky ChestShop fork :3

MrPowerGamerBR commented 2 years ago

And here's a very barebones implementation of @bricefrisco's original idea described in #365 :3 It only checks if the shop doesn't have B stock in the chest, not S space in the chest, but that shouldn't be hard to implement in the code.

https://user-images.githubusercontent.com/9496359/154605534-e2e8259b-519a-4d43-a7dc-b0e3dea88110.mp4

class ColorizeShopSignsListener(val m: DreamChestShopStuff) : Listener {
    // https://github.com/ChestShop-authors/ChestShop-3/issues/503
    @EventHandler(priority = EventPriority.MONITOR)
    fun onPreShopCreation(event: PreShopCreationEvent) {
        val itemTradedByShop: ItemStack = StockCounterModule.determineItemTradedByShop(event.getSignLine(ITEM_LINE))
        val chestShopInventory: Inventory = uBlock.findConnectedContainer(event.sign).inventory
        val numTradedItemsInChest: Int = InventoryUtil.getAmount(itemTradedByShop, chestShopInventory)

        if (numTradedItemsInChest == 0) {
            event.signLines = event.signLines
                .map {
                    "§c" + ChatColor.stripColor(it)
                }.toTypedArray()
        } else {
            // Owner
            event.setSignLine(0, "§1" + ChatColor.stripColor(event.getSignLine(0)))

            // Price
            event.setSignLine(
                2,
                ChatColor.stripColor(event.getSignLine(2))
                    .replace("B", "§aB")
                    .replace(":", "§0:")
                    .replace("S", "§4S")
            )

            // Item
            event.setSignLine(3, "§9" + ChatColor.stripColor(event.getSignLine(3)))
        }
    }

    @EventHandler
    fun onInventoryClose(event: InventoryCloseEvent) {
        val inventoryLocation = event.inventory.location
        if (inventoryLocation == null || !ChestShopSign.isShopBlock(inventoryLocation.block))
            return

        for (shopSign in uBlock.findConnectedShopSigns(event.inventory.holder)) {
            if (ChestShopSign.isAdminShop(shopSign))
                return

            updateSignColorBasedOnStockQuantity(shopSign, event.inventory)
        }
    }

    @EventHandler(priority = EventPriority.HIGH)
    fun onTransaction(event: TransactionEvent) {
        if (ChestShopSign.isAdminShop(event.sign))
            return

        for (shopSign in uBlock.findConnectedShopSigns(event.ownerInventory.holder)) {
            updateSignColorBasedOnStockQuantity(shopSign, event.ownerInventory)
        }
    }

    // From the StockCounterModule class
    private fun updateSignColorBasedOnStockQuantity(sign: Sign, chestShopInventory: Inventory?) {
        val itemTradedByShop: ItemStack = StockCounterModule.determineItemTradedByShop(sign) ?: return
        val numTradedItemsInChest: Int = InventoryUtil.getAmount(itemTradedByShop, chestShopInventory)
        if (numTradedItemsInChest == 0) {
            // No items in the chest, make everything red!
            for (i in 0 until 4) {
                sign.setLine(i, "§c" + ChatColor.stripColor(sign.getLine(i)))
            }
        } else {
            // Items in the chest, update it to be our custom ChestShop sign color!
            // Owner
            sign.setLine(0, "§1" + ChatColor.stripColor(sign.getLine(0)))

            // Quantity
            sign.setLine(1, ChatColor.stripColor(sign.getLine(1)))

            // Price
            sign.setLine(
                2,
                ChatColor.stripColor(sign.getLine(2))
                    .replace("B", "§aB")
                    .replace(":", "§0:")
                    .replace("S", "§4S")
            )

            // Item
            sign.setLine(3, "§9" + ChatColor.stripColor(sign.getLine(3)))
        }

        // TODO: We could check if the sign really needs to be updated, instead of calling the update method every time
        sign.update(true)
    }
}
MrPowerGamerBR commented 2 years ago

@Phoenix616 tested the new ChestShop version on my public server, and they seem to have worked fine! 😊

I also made some changes to my previous code example:

Of course, my changes are tailored to my own server, however if anyone is stumbling upon this issue wondering how I implemented those changes, here it is (the repo is licensed under AGPL-3.0 but tbh do whatever you want with the code I don't really care, just that if you do something cool and epic with the ChestShop signs please share with everyone 😄): https://github.com/SparklyPower/SparklyPower/blob/624ab68f178e380c5902634045d4dee5d69da09e/bukkit/DreamChestShopStuff/src/main/kotlin/net/perfectdreams/dreamchestshopstuff/listeners/ColorizeShopSignsListener.kt#L34

Anyway, thank you @Phoenix616, this may seem like a small change in the grand scheme of things but it really makes the ChestShop signs be more colorful and fun to the players! If I end up finding an issue, I will reopen the issue :)

(PS: I sent a smol tip for you for implementing this :3, thank you for maintaining ChestShop)