#adventure-help

1 messages ยท Page 6 of 1

sweet hornet
#

Please provide an example of what you're trying to achieve, because it seems unclear

frozen tree
#

For example I have a component which is already parsed, how would I translate its papi placeholders now? (Without turning it back into a String)

sweet hornet
#

Why can't you parse the placeholders during the same time you parse your component?

frozen tree
#

Performance

tawny bolt
#

How would that make any performance difference, huh

hallow tangle
#

Components are immutable

frozen tree
#

I would imagine parsing 100 components each second take a little server performance

tawny bolt
#

nah

frozen tree
tawny bolt
#

I do that once per tick for my scoreboard, no issues with 100 scoreboards

#

Parsing is fast

frozen tree
#

Mhh

#

Well, thanks for helping

sweet hornet
#

Did you actually encountered any performance issue?

tawny bolt
#

I recommend trying and profiling it for your usecase, and then see if its really an issue. Because that by far is the easiest way of doing the PAPI placeholders

robust wharf
fossil crest
#

oh ok sorry

ember quiver
#

When trying to read raw playerdata from playerdata folder

#
File playerDataFile = new File(playerDataFolder, uuid + ".dat");
prisma mason
#

Packetevents is the failing plugin, not yours

ember quiver
#

considering that ideally paper should've brought it

#

didn't notice from the first read, thank you

obsidian nimbus
wet kestrel
#

Are you sure you're running this on paper and not perhaps spigot or aaaancient paper?

rare sage
#

paper does not bundle adventure-nbt anyway

carmine plinth
#

I had the same issue. don't shade packetevents. use the snapshot version

#

the experimental jars

#

and plus being bad + adventirous shouldn't lead to a crash?????????????????

sand drift
#

wat

carmine plinth
#

yeah

#

being adventurous sometimes isn't safe. yeah be safe out there don't dig straight down

rare sage
#

they didn't shade PE lol, and that isn't a crash either

sweet hornet
#

Is there a component serializer for the new 1.21.5+ SNBT format?
I have a tool on 1.21.4 for my staff members allowing them to copy the components from an existing item's tooltip so they can use it when making other items, and I used the JSON component serializer because it was what Minecraft used in commands, but now we're upgrading to 1.21.7 and they need the SNBT encoding instead of JSON so they can still use in Minecraft commands

cloud vapor
#

What platform?

sweet hornet
#

Paper

cloud vapor
#

PaperAdventure has a codec somewhere

#

or is it AdventureCodecs

sweet hornet
#

Do I need something other than io.papermc.paper:paper-api:1.21.7-R0.1-SNAPSHOT ?

sand drift
#

it's an internal class

sweet hornet
#

Because I can't find such class (or at least, IntelliJ's autocompletion can't)

#

Ah

#

There is no way I can just serialize a Component into a SNBT String from the API? Sad

sand drift
#

SNBT is minecraft specific, and we don't expose SNBT inside of the paper API

sweet hornet
#

Hmm, and raw NBT bytes maybe? Serialization to SNBT is not an issue for me

quaint monolith
#

The bytes API is more comfortable because the API doesn't actually promise those bytes are in any particular format

#

Doing anything with that byte[] other than saving it to provide back to the API unmodified is out of scope, if it breaks you get to keep both pieces

sand drift
#

there is some work on adventure for looking to expose a means of dealing with NBT, just, really unstable format

sweet hornet
#

Yes I know this for items, but is it accessible for raw components, or would I need to create a fake item with my component as display name so I can then extract it from NBT bytes after (which is a bit of a hack)

#

I don't really "care" about the unstable format, because I don't use this for storing. I just want it to be up-to-date format with the current in-game version, so that it can be used back in commands right after

sand drift
#

that does become a huge issue when writing a serialiser, however, which is the issue

#

if you're on paper your easiest option is going to be to use userdev and just poke internals for output

sweet hornet
#

Hmm ok I'll see how it turns out then, thx

cloud vapor
#

Haven't had a chance to look at it myself

stable siren
#

I'm updating my plugin to the newest adventure libs, and testing on newest Paper for 1.21.7

You are running the latest version

I've noticed messages to the action bar, and hover JSON components messages sent to the player are not functioning (no hover component when hovering over them) in my testing. I'm not seeing any stacktraces in console (maybe I need to enable logging levels? Would appreciate info on that if so.) nor were there any compiler errors or anything prior to testing. Just simply updated Paper for my test server, and updated the dependencies of all the adventure libraries I was using.

Any tips on how I can get to the bottom of what might be happening? When this has happened in the past I usually need to add some new dependency to my shadowed JAR that adventure has incorporated, but I would expect potentially an error or something to help identify that.

Thanks ๐Ÿซก

wet kestrel
stable siren
#

I am using bukkit-platform
Testing on 1.21.6 also had the same issue, but I didn't mention it since 1.21.6 was around so briefly

wet kestrel
#

-# Also just move to Paper API! :3

stable siren
#

I'll test it

#

@wet kestrel well I wanted to test, but the sonatype repo from md5 wants me to do some user/pass login stuff for some reason

   > Could not resolve net.md-5:bungeecord-chat:1.15-SNAPSHOT.
     Required by:
         project :adventure-platform-bukkit > com.destroystokyo.paper:paper-api:1.15.2-R0.1-SNAPSHOT:20201203.195914-323
      > Could not resolve net.md-5:bungeecord-chat:1.15-SNAPSHOT.
         > Unable to load Maven meta-data from https://oss.sonatype.org/content/repositories/snapshots/net/md-5/bungeecord-chat/1.15-SNAPSHOT/maven-metadata.xml.
            > Could not GET 'https://oss.sonatype.org/content/repositories/snapshots/net/md-5/bungeecord-chat/1.15-SNAPSHOT/maven-metadata.xml'. Received status code 401 from server: Unauthorized

I don't know the process to get an account with auth for that repo

#

actually that wasn't the only repo to reject me

wet kestrel
#

Oh, sonatype nuked snapshots repo didn't they kek

rare sage
wet kestrel
tawny bolt
#
if (spigot) {
 dont(); }
wet kestrel
rare sage
#

are you telling me fuuid exclusively supports modern versions of paper?!?!

wet kestrel
#

No, and let's stop misusing a help channel :3

rare sage
stable siren
#

Looks like I've run into some unfortunate timing

#

after the build is updated for the new repos, I don't mind testing that PR
I changed the build locally, but it's not finding the artifacts, I suspect I made a mistake in my changes and it's probably my fault, or perhaps these artifacts are somehow not available yet (maybe unfortunate timing from today being the day it got nuked)

sweet meadow
#

Just want to ask before i spend hours trying to do this to realise its not possible
Is it possible to use adventure nbt to (de)serialize things like block states (or block data, whatever is needed to copy the exact data of the block)
if so, is it platform agnostic (will it work with serializing paper block state and deserializing as a fabric block state)

#

if the answer to all that is yes,
are there any libraries that do this or am i going to make my own serializers

cloud vapor
sweet meadow
#

yeah worded this badly sorry, is there built in methods to convert native bukkit objects to nbt

sweet hornet
#

Adventure does not know about any bukkit stuff

sweet meadow
#

paper knows about adventure though and there is converters for text related things

vocal dove
#

Is there a way to convert an Adventure component to an NMS component?

midnight spire
#

that's something that would be in adventure-platform, not sure if it's exposed in some form of API though

#

I kinda doubt it tbh

#

ok apparently MinecraftComponentSerializer exists and seems accessible

rare sage
#

it depends on the platform yes

#

not all platforms have a MinecraftCS

#

e.g. -platform-modded has asAdventure/asNative methods in the MinecraftAudiences type, -platform-bukkit has MCS, native platforms will have their own ways too

mint path
#

How do you properly parse unicode glyphs? I use something like this atm: java if (unicode != null && unicode.contains("uE")) { unicode = StringEscapeUtils.unescapeJava("\\" + unicode); but that doesn't work with Adventure. /tellraw works but my usage of some unicode chars becomes empty content and doesn't work.

cloud vapor
#

what do you mean by "parse"

mint path
#

well they come in like this

cloud vapor
#

sounds like your file encoding is borked

mint path
#

nvm i had some unicode strings with a lowercase e so that .contains("uE") wouldn't fire on em

cloud vapor
#

what im saying is you don't have to do any parsing or unescaping logic if you just have your file encoding set correctly

oak hamlet
#

I've had the same error on the other project that was built with gradle.kts and relocating adventure solved it. The version is the same - 1.17.1 but the error still stays

cloud vapor
#

You cant relocate adventure and use native paper component methods

#

java.lang.NoSuchMethodError: 'void org.bukkit.inventory.meta.ItemMeta.displayName(pl.karoldronia.sponges.libs.adventure.text.Component)'

#

See how it's looking for this method which definitely doesn't exist

oak hamlet
#

yea I see

#

but what should I do to fix it?

cloud vapor
wet kestrel
#

tl:dr stop shading and relocating adventure. It's in paper.

oak hamlet
# wet kestrel tl:dr stop shading and relocating adventure. It's in paper.

okay I don't know if I do it correctly but this is my pom:

       <dependency>
            <groupId>net.kyori</groupId>
            <artifactId>adventure-platform-bukkit</artifactId>
            <version>4.3.1</version>
        </dependency>

        <dependency>
            <groupId>net.kyori</groupId>
            <artifactId>adventure-text-minimessage</artifactId>
            <version>4.18.0</version>
        </dependency>

I am not including adventure-api and I am not relocating anything
Error:

#
public interface MiniMessageHolder {

    MiniMessage MINI_MESSAGE = MiniMessage.miniMessage();

}
upper tinselBOT
wet kestrel
#

I can't open attachments easily on mobile

#

Also share your full build script

oak hamlet
#

gimme a moment

#

pom

cloud vapor
#

paper already ships all that so idk why you're including it anyway

#

and if you're not using paper, then dont use paper

oak hamlet
#

so jsut remove all adventure dependencies?

wet kestrel
#

I suspect that you're building against a much newer adventure than the one bundled in the ANCIENT (outdated, unsupported, exploitable) version of paper you're using.

oak hamlet
#

org.bukkit.plugin.InvalidPluginException: java.lang.NoClassDefFoundError: net/kyori/adventure/platform/AudienceProvider

cloud vapor
#

Paper includes adventure - Player is an audience, you don't need an AudienceProvider

wet kestrel
#

I feel like you haven't removed your adventure deps if you're even able to build with that...

oak hamlet
obsidian nimbus
#

what version you running?

oak hamlet
#

server is on 1.17,1

wet kestrel
#

You're in such ancient territory there. Not sure anybody remembers specifics. You should upgrade off a server full of issues to modern.

obsidian nimbus
# oak hamlet server is on 1.17,1

Either upgrade to the latest paper version, or either use adventure-platform with relocation. (you will lose ability to use native methods)

cloud vapor
#

Yeah we can't provide support for legacy paper builds

upper tinselBOT
frank glacier
#

any forecast to support 1.21.7?

deep grotto
#

There is no ETA

wet kestrel
frank glacier
#

yes

#

4.4.0

wet kestrel
#

Okay, then you want #adventure-platform-mod-help where you can see conversation about testing the PR adding that support. Adventure itself has been fine for a whiiile.

scenic cloak
#

HELP, server on 1.21.7
player.sendMessage(
Component.text("test")
.hoverEvent(HoverEvent.showText(Component.text("here")))
.clickEvent(ClickEvent.runCommand("/say test"))
)
clickEvent doesn't work but other events work

cloud vapor
#

What platform?

sterile rampart
#

isn't that just a signed argument thing?

wispy wagon
#

how can I serialize a component as adventure nbt?

wispy wagon
molten berry
#

I didn't know Kotlin had async await kekw

wispy wagon
wispy wagon
gritty tundra
#

can I send a translationkey or translatable component as a moonshine @Placeholder or do I need to make a custom resolver for that

wicked torrent
#

iirc moonshine does not integrate directly with adventure at all

#

so it's kind of up to you to choose how to fit them together

#

but you can definitely do that

obsidian nimbus
#

isnt moonshine dead

gritty tundra
#

pretty much

fossil prawn
#

What's the best way of detecting whether an audience can use clickable components or not?

#

Which is typically just console

quaint monolith
#

Console doesn't work with clicks? I guess I could see the URL part being hard/impossible but run and suggest command should be doable

#

That's doing to be dependent on the platform implementation though and I don't think there is any way for you to know

fossil prawn
#

Are certain terminals meant to work with clickable components?

quaint monolith
#

They could, I don't know if any of them actually do work though

fossil prawn
#

hmm ok. Thank you

quaint monolith
#

Whether or not console can click on things is going to depend on the kind of click event, the platform, and what terminal you're running the game in

cloud vapor
#

why do you need to detect it?

quaint monolith
#

Heck even URL click events would work if they just called out to xdg-open

smoky wadi
#

Like this

sweet hornet
#

If the PR isn't merged, then no

#

You could technically do it yourself, or up-vote the PR and share your thoughts about it to help the team

#

And, as we can read in the description:

Done as a quick tech demo, would need a bit of actual design work and cleanup if we want to actually incorporate this into MM
It's not gonna be merged like this, so you should rather leave a comment explaining why you consider such feature to be useful, and worth investing some time to integrate it properly

robust wharf
#

Can also copy and adapt the tag from the PR into your plugin

quaint monolith
#

Huh, that's way better than gradient on the text itself

green monolith
#

Yeah, that looks really pretty

sweet hornet
#

iirc when I tested it, it looked nice on white text with (multi-)colored shadow, but any text color other than white was not that good in terms of results

merry valve
#

Hello, how can I reset text decoration like &r in Component.text(...?

sweet hornet
#

.decoration(TextDecoration.ITALIC, false)

merry valve
#

so that disables italic? do I understand right?

sweet hornet
#

That's it, if you need to remove other decorations, you can just replace ITALIC by something else

merry valve
#

Thanks!

tough peak
#

What does MiniMessage.miniMessage().serialize(component); do? please provide an example

robust wharf
#

what do you think it does? lol

#

it turns a component into a minimessage string

tough peak
#

ok thank you

obsidian nimbus
#

lmao

livid blade
#

So I do not know if im blind, but im trying to find the docs to do with the click events for adventure?

I checked the adventure docs quite a few times and feel daft for not finding the right page

livid blade
wet kestrel
frozen tree
#

Hey, why does the LegacyComponentSerializer not preserve the reset tags(&r and <reset>) upon deserializing a legacy string.

My code:
miniMessage.serialize(legacySerializer.deserialize(msg))

wet kestrel
#

Those two things (reset tag and legacy r) are not identical. It makes more sense to deserialize the legacy to something that makes sense as a tree in components, and then minimessage serializes the tree.

#

-# Also <reset> is not something you should encourage others to do often :3

livid blade
stable siren
#

@wet kestrel I was able to compile the build now for blood's PR for platform-bukkit and I was able to confirm it working in Paper 1.21.7 builds, I left a comment on the PR. Sorry I was unable to test it the other day (unfortunate timing with that snapshots repo being sunset... or nuked or whatever)

wet kestrel
frozen tree
wet kestrel
#

Yes. I am describing what your code is doing. It deserializes the legacy stuff into a tree. The tree lacks the concept of "reset". Then it serializes the tree as minimessage.

livid blade
#

Also semi neat / odd thing question... do you use dark mode on the docs by chance mbax?

wet kestrel
#

I do not. Never bothered to hit the button. My OS defaults to light.

frozen tree
wet kestrel
frozen tree
#

Why? I mean, how would one reset for example strikethrough without it?

fiery oracle
#

components have no concept of "resetting"
the &r in legacy text basically just means "wrap the following text with an explicitly set style (white text, no formatting or events)"

#

this is also notably different than the MM <reset> tag, which closes currently open tags

wet kestrel
#

Strikethrough is a different code from r and should process fine.

frozen tree
#

Okay, well, thank you for the help

rustic pumice
#

What does component.color(); return if multiple NamedTextColors are used in the component?

rare sage
#

a component can only have one colour

#

however, a component can have children which have different colours

#

Component#thing() will return you the thing that one component in the tree directly holds

smoky girder
#

you could analyze all the colors in use using the ComponentFlattener

rustic pumice
# rare sage however, a component can have children which have different colours

Im guessing .append() makes those component children? also .thing() doesn't seem to exist at all, looked through javadocs

I feel like this is really dumb, but is it possible to get a List of (or at least separate) components that have .append() in it?
What im trying to do is get the colour of the player's name from displayName() in Paper, with other text being in the display name

rare sage
#

.thing() was an example that applies to any one property of a component

#

children, content, style or style elements like colour or decorations etc

#

.thing() is not literally an actual property of a component

#

i'm not entirely sure what is it you're asking, components are a tree, you can traverse them with the various iterator/iterable methods on Component, or with a ComponentFlattener

slate current
#

Would a PR to adventure NBT adding something like

List<MyData> values = ...;
ListBinaryTag.Builder builder = ListBinaryTag.heterogeneousListBinaryTag().initialSize(data.size());
for (MyData data : values) {
    builder.add(StringTag.stringTag(data.thing());
}

be fine? basically just, a way to initialize builders with a set size for when you're directly copying another list/map into it.

#

(Or is that already a thing somewhere and I missed it?)

cloud vapor
#

Do you have a particular reason for wanting this?

slate current
#

Just some potentially hot code that I'd like to optimize all the wayโ„ข, I know it's not the sort of thing that'd make a massive difference, but any easy & non-messy optimization is a good optimization

sage river
slate current
#

Also unrelated question - is there a reason a lot of defaultValue parameters are @NotNull? compound.getCompound("key") returns an empty compound if the key is missing, so I was gonna do .getCompound("key", null), but ^

slate current
cloud vapor
sand drift
#

Nope

slate current
#

It doesn't enforce it, but like, it's an IDE warning

cloud vapor
#

then yea just an oversight, happy for the param to be nullable with a contract annotation on the return types

slate current
#

Still has some redundant list copies, but that is probably just micro optimization at that point (and I assume you wouldn't want a fromUntrusted(List) either way)

sweet hornet
#

Just out of curiosity, what is approximately the size of your lists you're talking about?

slate current
#

Any size, which is why I preferred to do it like this - could be very big, could be very small

cloud vapor
#

yeah just stick a param on the builder methods

#

would be fine for both

slate current
#

Alright, thanks!

slate current
#

If the second param is null it may return null, if the second param isn't null it will never return null

sweet hornet
#

iirc the first part is useless, because it does not specify anything about the return value

slate current
#

Ah, makes sense

sweet hornet
#

Only _, !null -> !null is needed to say that, whatever is the first value, if the second one is not null, then the return value won't be null

slate current
#

Yeah I see, thanks - it already knows it might be null because it's nullable, just need the contract to tell it when it isn't

sweet hornet
#

In this case, yes. But it could also be the other way around, in some other cases: _, null -> null for example, says that the result will always be null if the second param is null. Is says nothing about when it won't be null, meaning it can still be null even if the second param isn't. In this case obviously this is not true, but I was just showing you an example. The method could be "get the property of that user, which might exist or not, but will always return null if the user is null"

cloud vapor
#

you need _, null -> null; _, !null -> !null

sweet hornet
#

Wait, no? The result won't always be null when the default value is: There is the case where the requested value exists and is returned

#

Unless I'm missing something, I just gave a really far look at the problem

rare sage
#

_, null -> null doesn't make any sense

#

you're saying it will always return null if the second param is null

#

it's just _, !null -> !null

cloud vapor
#

that's not what contract does, null just indicates the return type is nullable

rare sage
sweet hornet
#

No, I really don't think so, the nullability of the return type is indicated with the @Nullable on the method

rare sage
forest meteor
#

when will adventure be ready for 1.21.7? im having a bug with the gson serializer and im not sure how im going to handle it im ngl

#

here is the error im having

#
public static final GsonComponentSerializer GSON_SERIALIZER = GsonComponentSerializer.gson();```
#

literally whats failing rn

slate current
rare sage
#

you are not relocating net.kyori.option

forest meteor
slate current
# cloud vapor then yea just an oversight, happy for the param to be nullable with a contract a...

PRed these two, but I have another question - is there any way to get a builder from a compound tag (other then making an empty builder and adding the values from the tag)?
The put methods on CompoundBinaryTag copy it and return a new one (which is very useful actually), but then when editing multiple values at once it'd be creating a copy every time, which isn't great.
So something like

CompoundBinaryTag edited = tag.createBuilder().put(x, y).putInt(x, y).remove(x).build();

that'll create a builder directly from the compound's map could be very useful (if it doesn't already exist)

round fox
#

Is there any version of a MiniMessage parser that's able to be ran outside of Minecraft? Like on a non-minecraft app

sand drift
#

I mean, MM is tied to adventure itself, it's just a serialiser

#

it's the component handling which is where platform stuff starts to come into play

round fox
#

I see

#

I know there's a minimessage web viewer so I thought maybe there was a 'generic' implementation somewhere

sand drift
#

Well, yea, that's just MM + Adventure

cold junco
#

I have
<click:run_command:/kick <player>> and replace <player> using tag resolver. <player> is parsing, but <click> is not.

btw if I do <click:run_command:'/kick <player>'> <click> is parsing, but <player> is not

how to fix it?

wet kestrel
#

What kind of resolver is player? I make sure to use placeholder.parsed, so I don't mess it up.

cold junco
#

hm, it worked with parsed. thanks

wet kestrel
#

Yep! ๐Ÿ™‚

livid blade
#

Is there a way to use the ClickEvent of a component to enact a lambda function / method on click? If so how? If not, is there a reason why that was never added? It seems like a reasonable thing for it to do considering how Paper-entire is based around methods called on event based logic ๐Ÿ˜…

e.g: imagine having a class defining some custom function, and you can set the click event to call a method within that class if the component is clicked?

sand drift
#

ClickEvent.callback or something

livid blade
#

See this is why I politely suggested maybe the docs need a tiny bit of elaboration / a few examples of ClickEvent being used in various use-cases.

As I just looked it up and it says the param is a ClickCallback<Audience> which is taking me further down the "undocumented (other than javadocs) abstractions" rabbit hole ๐Ÿ˜…

sand drift
#

I mean, the docs always need more love, be the change you want to see

livid blade
#

*I would if I knew what to change.

Hope you see the issue here haha

sand drift
#

Pretty sure ClickCallback is just a functional interface

livid blade
#

There is a certain level of "Ive figured it out" fatigue.

By the time you brute force it or bash head up wall till it works, you usually dont have the energy to go fix the docs.

Sometimes we just need someone a bit more knowledgeable to come in and add an example for us poor unfortunate sods haha

sand drift
#

Yea, can basically just ClickEvent.callback((audience) -> { audience.sendMessage(text("boo"));};

livid blade
#

On a slight tangent, the Tauri documentation is rife with "Ive figured it out fatigue".

So much effort goes into getting stuff to work, theres no energy left to fix the docs haha

#

Cheers Electro

livid blade
#
/**
 * Represents a collection of messages that can be shown in bulk to an Audience.
 */
public class MessagePage {

    /**
     * The title of the page.
     */
    private final Component title;

    /**
     * The main content of the page.
     */
    private final List<Component> content = new ArrayList<>();

    /**
     * The footer (the final message at the bottom of the page).
     */
    private Component footer = Component.empty();

    public MessagePage(Component title, Component footer) {
        this.title = title;
    }



    /**
     * Adds a new component to the content of the page (placed directly below the previous line of content).
     * @param content The component to add.
     */
    public void addContent(Component content) {
        this.content.add(content);
    }

    /**
     * Shows the page messages, in the correct order, to the specified Audience.
     * @param audience The audience to show the page to.
     */
    public void showPage(Audience audience) {
        TextComponent.Builder builder = Component
                .text()
                .append(title)
                .appendNewline();

        audience
                .sendMessage(addContent(builder)
                        .append(footer)
                        .build()
                );
    }

    public void setFooter(Component footer) {
        this.footer = footer;
    }

    private TextComponent.Builder addContent(TextComponent.Builder builder) {
        if(content.isEmpty()) return builder;
        for (Component component : content) {
            builder.append(component).appendNewline();
        }
        return builder;
    }
}

#
public class MessageStack {
    private final List<MessagePage> pages = new ArrayList<>();
    private int currentPage = 0;

    public MessageStack() {}

    public boolean addPage(MessagePage page) {
        return pages.add(page);
    }

    public boolean addPage(Component title, List<Component> contentLines) {
        MessagePage page = new MessagePage(title);
        for (Component content : contentLines) {
            page.addContent(content);
        }
        return pages.add(page);
    }

    public void showCurrentPage(Audience audience) {
        if (pages.isEmpty()) return;

        MessagePage page = pages.get(currentPage);
        page.setFooter(generateFooter());
        page.showPage(audience);
    }

    public void nextPage(Audience audience) {
        if (currentPage < pages.size() - 1) {
            currentPage++;
        }
        showCurrentPage(audience);
    }

    public void previousPage(Audience audience) {
        if (currentPage > 0) {
            currentPage--;
        }
        showCurrentPage(audience);
    }

    private Component generateFooter() {
        TextComponent.Builder builder = Component.text();

        Component pageLabel = Component.text("Page " + (currentPage + 1) + " of " + pages.size())
                .color(NamedTextColor.GRAY);
        builder.append(pageLabel).append(Component.text("   "));

        if (currentPage > 0) {
            Component prev = Component.text("[Previous]")
                    .color(NamedTextColor.YELLOW)
                    .decorate(TextDecoration.UNDERLINED)
                    .hoverEvent(HoverEvent.showText(Component.text("Go to previous page")))
                    .clickEvent(ClickEvent.callback(this::previousPage));
            builder.append(prev).append(Component.text(" "));
        }

        if (currentPage < pages.size() - 1) {
            Component next = Component.text("[Next]")
                    .color(NamedTextColor.GREEN)
                    .decorate(TextDecoration.UNDERLINED)
                    .hoverEvent(HoverEvent.showText(Component.text("Go to next page")))
                    .clickEvent(ClickEvent.callback(this::nextPage));
            builder.append(next);
        }

        return builder.build();
    }

}

Im pretty happy with that as an MVP (will be changing the formatting of the page buttons obviously, but the concept is pretty neat) ๐Ÿ™‚

#

Nice little collection of messages / logs / whatever components you fancy into a "page" of messages you can flick between nice and easy.

#

Wish there was a slightly more performant way to do page footers than re-do them constantly every time you flick the page.

Maybe builder pattern for the MessageStack, so when the footers are added there is 0 chance of new pages being added?

fiery oracle
#

is that bottom most private method in the 1st one supposed to still be there or

#

oh and the first one could implement ComponentLike instead of having a method to show to an audience

#

same with the 2nd one if the page moving is separated out from the showing

wet kestrel
livid blade
livid blade
#

Jokes aside it couldn't hurt.

A good example is i have no idea what ComponentLike is, so im gonna pop both to the docs and javadocs haha

sweet hornet
# livid blade Why would I want to not show the audience via the class itself?

It would allow you to instead of msgPage.showPage(audience) you would do audience.sendMessage(msgPage). The main difference being that you could easily replace sendMessage by any other method, and also merge it with other components or anything.
An ComponentLike is just something that can be used as a component (thanks to the method asComponent)

livid blade
#

What other commands would be useful to have do to a page other than send Message?

sweet hornet
#

Idk you exact use-case, but I could imagine showing it through a book, a dialog, or doing other kind of component-level operation such as appending a prefix / suffix, or replacing texts, colors, stylesโ€ฆ

raven tusk
#

Can I get translated item name as String using minimessage?

sweet hornet
#

What do you mean? What are you trying to get? The plain text of the name? The MiniMessage-encoded component? Something else?

raven tusk
sand drift
#

MM just deals with serialisation

#

if you wanted to have the localised names in there, you'd need to flatten them

sweet hornet
#

Furthermore, "translated" in which language? English? Korean? iirc on Paper they bundle the English locale file, but in other case you'd need to include and maintain the translation file as well if you want to do server-side translation

raven tusk
#

So, is there no way to use a Translation Component for item names with Bukkit/Adventure in Spigot either?

sand drift
#

that stuff will work as much as spigot allows it to work

#

adventure mostly covers UX related stuff, it's just a conveinent library that we're able to adopt into the paper API across the board; I don't think that there is a public adapter for non UX stuff;

sweet hornet
#

A translation component contains a translation key with translation arguments (the values for the "placeholders" inside translated content), as well as the style (color, decoration...). You can very much use it, but it won't give you the translated content alone: you need to use a translator, fed with the translation file of the language you want to translate into

#

But it seems that what you want to achieve is unclear, even maybe for yourself. Please explain a little bit more (with context) about your use-case so we can better understand your goal to actually hepl you achieve it

sand drift
#

Yea, I was gonna say, assuming I even understand what you're asking; But, adventure platform doesn't deal with items; idk if they come with a flattener preconfigured to be able to use mojangs built in localisation file for english either

slate current
# slate current PRed these two, but I have another question - is there any way to get a builder ...

And two more things actually -

  1. would you be open to adding CompoundTag#containsKey(String) and CompoundTag#contains(Key, Type) utility methods?
  2. is there any way to get a BinaryTagType by its byte id? I can see an internal method, but as far as I can see it isn't exposed anywhere - would be nice if that could be made public, or at least a way to get a list of all BinaryTagTypes so that I could build my own mapping.
#

Sorry for all of the NBT questions btw lol - migrating a pretty big project from an old NBT lib to adventure NBT, so I'm just trying to PR some stuff that I'm missing

daring wyvern
#

Hello yall i got a question im tryna learn plugin making with paper on kotlin but i cant quite figure out whats the correct return type after i call ClickEvent.callback(foo()) for foo()

#

for context this is the foo function im trying to call

robust wharf
#

Nothing

#

Wait that looks strange

#

Please share more of your code, what is that function supposed to do and why do you want it to return a click callback

daring wyvern
#

this is more of a test to see if i can understand how it works so its veeery ugly

#

but my main goal is to fire handleClick when i click the text

#

my main problem is it excpects a return value and if i make it nullable it errors out on the callback

sterile rampart
#

ClickCallback is the functional interface type

#

you're invoking your callback when creating the click event. you should be passing that callback function in instead

robust wharf
#

So like, blah.clickEvent { handleClick(ctx) }

daring wyvern
rare sage
#

that's just pseudocode example

#

look at the method in the interface, that's the signature your lambda has to look like

daring wyvern
#

bruh im so dumb lmao

robust wharf
#

Sorry would be blah.clickEvent(ClickEvent.callback ({ handleClick()}))

#

Or does kotlin let you extract the lambda from there? Idk, kotlin weird

daring wyvern
#

very clean but my small brain cant keep up

robust wharf
#

It's not super beginner friendly

#

It was written by senior java devs to speed up writing code I guess

slate current
daring wyvern
#

thx for yall help anyways

cloud vapor
#

but if it's not too much hassle just PR it and we'll see

slate current
slate current
cloud vapor
#

yeah that also sounds good to me

slate current
#

Is there a cleaner way to do this?

ListBinaryTag listTag = compoundTag.getList(key, BinaryTagTypes.STRING);
for (BinaryTag tag : listTag) {
    materials.add(((StringBinaryTag) tag).value());
}
#

(As in, without having to cast the tags, since we know the list is of that type)

prisma mason
#

Is this possible?
<start_date:'<date_format:'dd.MM.yyyy':'EEEE'>'>

#

first one being resolved by a date resolver and the second being a booleanChoice

wet kestrel
#

Why not just have your statt_date take in the ddMMyyy stuff and not have it run through two resolvers?

prisma mason
wet kestrel
prisma mason
wet kestrel
#

What do you mean? No differently from any other tag resolver you make.

prisma mason
#

what...

wet kestrel
cloud bison
#

How would I use a custom click event type via Minimessage? I get something like <click:custom:...> but not sure how to format the "..." since the payload is more complex

smoky girder
#

honestly i don't understand much more than that, if the point is to run code when the text is clicked then classically run_command is used

#

trying to figure out where the server receives the custom payload and i dont see anything

#

ah! here we go

cloud bison
#

Yeah, appreciate it, though I know about the event and everything. The reason for the custom action is so that you can run custom code without having to register a custom command to do so

#

Just trying to see how to do it through minimessage, I've tried the things that make sense to me but can't get it working

smoky girder
#

so its not like you can pass the key and then the NBT

cloud bison
#

I believe the NBT is optional for custom events

#

But then I'd think something like this would work "<click:custom:'minecraft:test'>Hey</click>", but it doesn't seem to

fiery oracle
#

the minimessage tag requires a string value
it doesn't work at all with the custom type because the tag only operates on strings

smoky girder
#

you can always write your own tag resolver that works in the way you'd like

#

it could even prepend a namespace of your choice, to avoid the escaping issue

#

so <mycustomtag:foo> would create a custom click event with key mynamespace:foo and empty NBT

cloud bison
#

I guess I'm just surprised because hover:show_item also needs to accept a key, which it accepts as a string, but doesn't work for custom whose only required field is id which is also a namespaced ID

#

But that makes sense, custom resolver seems like a good approach so I can do that, cheers gang

cloud vapor
#

is the custom click event even implemented in minimessage

#

I don't think I did it

slate current
#

With BinaryTagIO, is there any way to unwrap lists as you load them?

#

Kinda like NMS loading logic does:

#

(And if not, would that get accepted as a PR? otherwise you'd have to have loop over every tag in every tag to make sure they're all unwrapped as far as I can see)

slate current
hoary plume
#

Question:
Would there be a way to detect if a specific feature is actually available on the server/proxy Kyori is being used on?
Like in my case would I like to know, if a Server/Proxy runs a version supporting Dialogs to use it.

#

Also, is there any form of tutorial or example on how to use Dialogs in Adventure?
I want to make a platform-agnostic Dialog system, so that I only have one core code base for it that works on proxy and server (In my case would it run on either Paper, Velocity or BungeeCord (using the platform library), tho I consider droping the last one).

sweet hornet
#

Adventure does not yet provides dialogs

#

Some platforms do (Paper)

slate current
#

^ I think there's only DialogLike stuff for platforms to extend, but not a full API yet

hoary plume
#

Rip

sweet hornet
#

And it's not likely to happen soon

#

It will, at the end, be the case. But when it will be stable

hoary plume
#

Guess I'll have to make platform-specific code then to create the Dialogs...

sweet hornet
#

For now, you have to use Paper's implementation if you want to use them, and idk about other platforms for now

wet kestrel
#

Dialogs are too potentially in flux. Paper's implementation has the whole package marked experimental.

hoary plume
sweet hornet
#

Are you talking about detecting the presence of an implementation (depending on the platform), or the version of the platform (Paper...) being < 1.21.7 (or whatever version dialogs first came out)?

hoary plume
#

I simply want to make sure that when I want to use Dialogs, that the platform the server runs on is actually a version that could support it.

sweet hornet
#

Well, since implementations are provided by platforms, if the platform provides one, then it certainly exists, otherwise no. If you're talking about backward compatibility, then you need to check in which version of each platform the dialogs implementation came out, and simply test that version (or, if you don't want to bother checking version, you could technically test for the presence of the specific implementation class, yes)

#

But you cannot reliably platform-agnostically determine whether dialog implementation exist or not, since dialog implementations are provided by platforms. The best way you can do is assume there's not, and for specific platform you know there's one, then use it

prisma mason
#

I know I've asked this before, but can I make nested tags in a choice tag or should I just use a custom tag resolver?

#

For the datetime thing I mentioned before I used a custom tag resolver

forest meteor
#

yo, after updating adventure click event doesn't work for older versions

#

idk if thats because of Adventure or Adventure Platform

#

but what i know is that it works for 1.21.7 but not older versions

wet kestrel
forest meteor
#

if i have a decoration/style that is set to false rather than unset.. how do i make it unset

hoary plume
#

Is there any form of info/guide for how I could create some own Dialog implementation using Adventure?
Would like to implement some basic system for Velocity to display Dialogs to a player.

cloud vapor
#

You would need the platform to implement it - adventure only provides the framework for platform dialog API until we've added a dialog api of our own

hoary plume
#

Guess I have to wait until Velocity has something...

sand drift
#

The issue I have with velocity is, well, time, but, also; Do I implement something that I will likely then need to deal with again in the future to make it conform to the adventure API

small cloud
cloud vapor
#

Yes, there's methods on the string based translation store to read from a path iirc

opal nimbus
#

Hi everyone!
I'm working on a project that needs to parse sign block-entity data.
My goal is to display them on a website with HTML, so the text, colour and glowing-ness need to be extracted, so I can insert it into the HTML template.
I used to do all the NBT parsing myself, with manual handling of edge cases, like some plugins putting data where it shouldn't normally be, according to the vanilla spec. But I try to handle these things as best as I can anyway.
I also support many Minecraft versions, all the way back to 1.13
So I've been wondering whether using Adventure would be beneficial for me here.
Could it handle (at least a part) of this parsing for me?

forest meteor
#

yo

#

my gson serializer is serializing weird for 1.21.4

#
{"color":"yellow","click_event":{"action":"open_url","url":"https://store.servername.net"},"text":"[โžฅ Store]"}```
#

look at this

#

click_event instead of clickEvent

#

url instead of value

torpid robin
#

yeah you're serializing to a newer version's format than 1.21.4

forest meteor
#

ye why is that

#

I just use GsonComponentSerializer#gson

sand drift
#

Well, what are you doing?

torpid robin
#

probably using a version of adventure not made for 1.21.4

forest meteor
#

its latest adventure

sand drift
#

Okay, but what binding?

#

because the output is version dependent

forest meteor
#

.. wym binding

#

i just use #serialize(Component)

sand drift
#

Okay, but, you are likely using adventure on some form of platform

forest meteor
#

oh paper

sand drift
#

what version of paper?

forest meteor
#

1.21.4 idk

#

latest one

#

but i relocate adventure

sand drift
#

So, you're not using paper adventure, you're likely using adventure-platform or whatever

forest meteor
#

yes

#

but thats not the problem tho

rare sage
#

it might be

forest meteor
#

im not sending it to the player yet

sand drift
#

Well, adventure isn't magical, it doesn't know what version of MC you're serialising for

forest meteor
#

how do i make it figure it out then

sand drift
#

so it's just going to use some default, given your complaint, the default is likely for the latest version

rare sage
#

the serializer serializes based on the current server's capabilities, native adventure integration does not have this problem, platforms kinda need to detect that

forest meteor
#

okay how do i help it out tho

#

like how do i provide a version somehow

#

idk much about server capabilities

forest meteor
sand drift
#

I'd guess the question is, why are you using the gson serialiser directly?

#

idk how the version detection stuff works in adventure-platform, so, I'm kinda out

forest meteor
#

gson-serializer is separate module from adventure-platform

rare sage
#

i see adventure-platform tries to set the serializer version so it should be fine if the server is the version you claim it is

#

actually, yes you are using the serializer directly

#

that will always be at latest version

#

if you want the version specific serializer you need to get it from that class
but the fact you are manually serializing a component is kinda sus

forest meteor
#

I can use BukkitComponentSerializer#gson

slate current
# opal nimbus Hi everyone! I'm working on a project that needs to parse sign block-entity data...

Well, you can use adventure-nbt to parse the data if you aren't already - beyond that it depends on what exactly your system is; are you getting the data while the server is running? if so you could probably use NMS to load the NBT with Mojang's logic and avoid needing your own handling.
As for what adventure specifically can do, beyond the NBT bit you could use it to parse the components, but I think that's about it, it's not really meant for handling block entity data or anything like that.

opal nimbus
#

Thanks for the reply!
I didn't know there was an nbt deserializer ๐Ÿ‘€ Somehow I wasn't able to find it before...

I can't use NMS, because this project will have to work on other server software than just Paper
And it even has to work without a server at all, running completely externally.

rare sage
#

i mean, you can totally use adventure-nbt to handle block entity data if you so desire, it's just an nbt parser after all, if it can read it, you can fiddle with it

opal nimbus
#

I see

#

I do already have an NBT Parsing library I'm very happy with, but it doesn't do more than parsing the NBT, like properly deserializing everything into text components and such

#

I'd have to deserialize everything myself, manually

#

Which seems like a rather daunting task

rare sage
#

adventure is no different

opal nimbus
#

๐Ÿ˜”

rare sage
#

it just reads the binary and gives you a BinaryTag

opal nimbus
#

I see

#

I was hoping I could use it to handle the text component stuff for me

#

Because sign text has been changed many times over the versions
Sometimes even including JSON for extra "fun"

slate current
#

Is there no way to use e.g. the gson serializer detached from a server? don't actually know how it works internally

#

Or alternatively, just run a server as your backend

sand drift
#

I mean, your issue is DFU if your issue is the upgrade stuff

#

well, maybe; getting the structure is one thing, being able to load it on the server is another, as they just deserialise it into a json element tree and then run it through their codec

opal nimbus
#

I have indeed been suggested this:

#

But that sounded rather cursed to me, so I was hoping there'd be a better way than this

#

(BlueNBT is the NBT library I am using)

opal nimbus
sand drift
#

I mean, when you have the NBT one, transforming to gson and parsing it is doable, mojang already supports that through DFU codec funkery

opal nimbus
#

Or do you mean fixing up the data at runtime, without modifying it on the actual files on disk?

slate current
#

^ that's what the DFU is

opal nimbus
#

Aah, I see

#

I must admit I don't have any experience with it

sand drift
#

I mean, it really depends on what you want to do, part of the reality is that the format is evolving

#

if you wanted to use the servers built in serialisation stuff, you would need to run the underlying data through DFU somewhere so that it can parse it

opal nimbus
#

Myeah

slate current
# opal nimbus I must admit I don't have any experience with it

It's Mojang's system, very rough explanation but basically just - all data is saved with an data version int, and when loaded the data is ran though a list of fixes determined by comparing the data's version to the current version to make it match modern format

opal nimbus
#

But there won't always be a server when my code runs

#

So I cannot rely on it

opal nimbus
#

It's essentially like a CLI tool that runs on the world files themselves directly

sand drift
#

Well, Mojang does have some gross codec stuff to convert NBT to Json ๐Ÿ˜„

#

But, I mean, once you have it in json iirc adventure is fairly adept at decoding it

sand drift
#

There is DataConvertor, idk how detatched it is from MC

#

not entirely, because ofc it needs access to mojang stuff to deal with parsing data, NBT, etc

opal nimbus
short kelp
#

is it normal that mm crashes with negative rainbow phase? ๐Ÿค”

<rainbow:-1>1234567890</rainbow>

    at net.kyori.adventure.util.HSVLikeImpl.requireInsideRange(HSVLikeImpl.java:61)
    at net.kyori.adventure.util.HSVLikeImpl.<init>(HSVLikeImpl.java:36)
    at net.kyori.adventure.util.HSVLike.hsvLike(HSVLike.java:51)
    at net.kyori.adventure.text.minimessage.tag.standard.RainbowTag.color(RainbowTag.java:105)
    at net.kyori.adventure.text.minimessage.tag.standard.AbstractColorChangingTag.apply(AbstractColorChangingTag.java:126)
    at net.kyori.adventure.text.minimessage.MiniMessageParser.handleModifying(MiniMessageParser.java:271)
    at net.kyori.adventure.text.minimessage.MiniMessageParser.handleModifying(MiniMessageParser.java:273)
    at net.kyori.adventure.text.minimessage.MiniMessageParser.treeToComponent(MiniMessageParser.java:248)```
#

๐ŸŽฏ

quaint monolith
#

As mentioned in #paper-dev you could argue that MM itself should be throwing some kind of parsing exception instead but it should be expected for it to fail when you feed it invalid data

robust wharf
#

Normally MM just ignores the tag for exceptions iirc

#

Idk, open an issue I guess and we can see

quaint monolith
#

Hmm, I dunno if it would be better to just strip the rainbow tag in that situation

#

More robust but more confusing

devout sage
#

From a design standpoint, if I'm hotswapping between two boss bars (ie removing one from a player and adding another one in the same tick), is it better to create brand new instances or modify the existing boss bar with new color/text/progress

cloud vapor
#

Don't think it really matters too much, whatever you prefer really

cloud vapor
slate current
kind jungle
#

How does logging components to a console work under the hood in adventure?

#

how is Windows support and checking terminal capabilities done? How do you convert minimssage into something a console can understand? What does the fallback process look like? (Full color range -> 256 colors -> ANSI colors -> strip colors?)

cloud vapor
#

We have an ANSI serializer that does all of that

robust wharf
#

fyi, motd preview on the minimessage webui is currently broken

robust wharf
worthy adder
#

hey, can i use <click:suggest_command ...> and replace placeholders inside the command thereafter?
So <click:suggest_command:'/snapshots restore <username> <snapshot_unique_id>'>Restore</click>, and replace the <username> etc to the actual variables?

cloud vapor
#

yes

#

use preparsed placehodler

worthy adder
#

do u have an example or smth?

keen wraith
#

I'm here for an issue I'm encountering:
you see, i have to modify my shadow color in order for my item description to look clean, so I use <!shadow>. but I want to reactivate the shadow, so I just put a <reset> tag, but the shadow doesn't go away like it's supposed to. am I doing something wrong here, or am I just dum ?

wet kestrel
sweet hornet
keen wraith
#

<shadow:#FF08FFFE><#FF08FF>Mining Fortune: <lang:space.71><reset><#53F52F>+65<lang:space.7>

sweet hornet
#

Oh wait no, I just inverted in my head

sweet hornet
#

Tbh, I find those two names (parsed vs unparsed) a bit confusing when looking at them from a distance. Because on one hand, parsed inserts the literal string into the parser, but on the other hand, if you want to get the literal value untouched, you want unparsed. Both have something to do with raw/literal values, but not in the same way

#

Maybe it is clearer than I think for native English speakers tho, and it is only amplified by the language barrier

wet kestrel
#

You want the string parsed by the parser? Parsed

You want it not parsed by the parser, and untouched? Unparsed

keen wraith
sweet hornet
#

Yes but look at the above example : We want the player name not to be "parsed", we want it to stay as a string (so the first thing to come in my mind is unparsed). That's why

wet kestrel
sweet hornet
#

I think the misleading part is the fact we don't want to parse tags inside the string (in that case, there should be none, but in a general case)

#

But I agree about the correctness of the names from the parser point of view

#

And maybe it's just me who is having trouble every time I need to choose, and I always go inside the code of either one to identify which one I need

fiery oracle
#

it's probably an issue from parsed/unparsed being able to be both "should be parsed/unparsed" and "is parsed/unparsed"

rare sage
#

The fact that this discussion is currently taking place is indicative in and of itself that the names are confusing

sterile rampart
#

the split between the two types of tags is imo a design flaw anyways

jolly sage
#

I would like to put some translatable messages into .properties or .json file (like minecraft does in the lang folder) but am confused by the docs and all methods that exist, for example there is this one but I'm unsure how to get a StringBased translation store and also there is no other method that takes a resource bundle

I took this code from docs.advntr.dev Localization:

#

Is using resource bundles the right way to do this anyway? i did this by right clicking on resources then new then Resource Bundle in Intellij

cloud vapor
#

A component translation store isn't a string based translation store

#

You want either TranslationStore.messageFormat or MiniMessageTranslationStore

jolly sage
#

I thought Component.translatable method works only with a component translation store :/
Still, how do I put in a resource bundle? Or any other way of reading keys and appropriate translations from various files

#

The method is still not showing ๐Ÿ˜ฆ

cloud vapor
#

Again, you need a TranslationStore.StringBased - you're just not using that in your type

jolly sage
#

OH that's it

#

i'll try now

jolly sage
cloud vapor
#

did you register your translation store

slate current
jolly sage
jolly sage
#

thanks for the previous help ๐Ÿ™Œ

#

it's showing me the default one instead of localized :( nvm i just got confused by Locale.FRANCE and Locale.FRENCH (tested by setting french ingame)

vivid bobcat
#

Hello, I have my own MessageTranslator class that translate messages into components, everything is OK. All the messages are mapped on a Map<Locale, Map<String, String>> messages; that I load from a json:

{
  "messages": {
    "en_us": {
      "hello.player": "<green>Hello, <player>!"
    }
    "pt_br": {
      "hello.player": "<green>Olรก, <player>!"
    }
  }
}

But I'm wanting to do something spicy, I want to create a TagResolver "ref" to reference messeges between themselves, example:

{
  "messages": {
    "en_us": {
      "player": "player",
      "command.ban.syntax": "/ban \<<ref:player>>"
    }
  }
}

How can I create a TagResolver like that? should I implement Modifying interface? I wanna make it even more spice, if possible, by adding some arguments, for example: ref:player:to_upper_case or some regex replacements.

alpine marlin
#

Does someone know why the date does not get displayed in the message?

last horizon
#

.

#

@alpine marlin

alpine marlin
#

that's kinda wierd, but thank you ๐Ÿ˜„

last horizon
#

it was explained a few messages after mine if you are interested about the why

fiery oracle
rare sage
#

so you need to pass a zoned temporal accessor, Instant is not it

vivid bobcat
rare sage
#

thonk what

#

you can totally register a minimessage translator into the global translator

vivid bobcat
#

can I use that for lores? Because currently my MessageTranslator class have the method .translate(TranslationRequest) that returns a TranslationResult, then I can do toComponentList() or toSingleComponent() or toLegacy() toPlainText() etc

quaint monolith
#

ItemStacks can't have server-side translations

fiery oracle
#

the automatic translation of the global translator does not operate on items (at least on paper, not sure about other platforms)
but you can still manually invoke the global translator

quaint monolith
#

Well, yeah, I suppose you could manually replace the component with the translated version on the server

fiery oracle
#

as for the list thing, not exactly sure what you mean by that
you pass a component to the global translator, and it renders it using its registered translators

#

you get a component back, with any translatable components translated if a registered translation is found

#

you can still have your overall system, but it'd likely be easier to let the global translator handle the key + locale -> translation part

#

(and the global translator will auto translate messages sent to players, along with some other areas, just not items)

vivid bobcat
fiery oracle
#

wdym

#
vivid bobcat
#

how to use it? it would be something like that?
player.sendMessage(Component.translatable("hello.player"))?

fiery oracle
#

ye, that's all you'd have to do, if your platform supports the global translator

#

if you have arguments you'd have to pass them as well

vivid bobcat
fiery oracle
#

you can pass tagresolver arguments with the minimessage translator

fiery oracle
ripe tulip
#

is it possible to get the <namespace> placeholder to be filled in this minimessage string, or should i rework how i am making this message?
<hover:show_text:"<ash>Click to view info."><click:run_command:"/module <namespace> info"><tyrian><module>

return Component.translatable(
        "message.module.module_name",
        Argument.string("namespace", namespaced()),
        Argument.string("module", formatted())
);

<module> works but i assume <namespace> isn't because its nested in a click tag

wet kestrel
#

I don't know what Argument.string is doing but it should be returning a tag resolver that produces a pre process parsed tag if you want <namespace> to get processed, like how Placeholder.parsed works.

ripe tulip
quaint cedar
#

hi, i'm having issues using mimimessage to create messages, font and hover and click tag do not work at all

Context:
Version:
This server is running Paper version 1.21.8-6-main@782ce95 (2025-07-18T20:26:58Z) (Implementing API version 1.21.8-R0.1-SNAPSHOT)

Code:

       Component component = MiniMessage.builder().build().deserialize(builder.toString());
        if (player != null) {
            getAudiences(plugin).player(player).sendMessage(component);```

Text sended:
<font:minecraft:alt> Font</font>
<hover:show_text:'<gray>This is a tooltip!</gray>'> <gold>Hover over me</gold> </hover>

plugin.yml libraries

libraries:

  • net.kyori:adventure-platform-bukkit:4.4.0
  • net.kyori:adventure-text-minimessage:4.23.0```

pom.xml

        <!-- MiniMessage -->
        <dependency>
            <groupId>net.kyori</groupId>
            <artifactId>adventure-text-minimessage</artifactId>
            <version>4.23.0</version>
        </dependency>
        <dependency>
            <groupId>net.kyori</groupId>
            <artifactId>adventure-platform-bukkit</artifactId>
            <version>4.4.0</version>
        </dependency>```
#

Am I missing something? Any tips would be really appreciated ๐Ÿ™‚

wet kestrel
quaint cedar
wet kestrel
cloud vapor
#

if that makes sense

worthy adder
#

is it possible to add a translation to my holograms plugin so that i can register a minimessage key via plugin, e.g. <t:TEXT>, and then the player will see the translation of TEXT depending on their language? So without packets

worthy adder
#

kinda, but i need to use my own translation system for this, not the default minimessage translator with a file or smth

cloud vapor
grim bear
#

I use CarbonChat which has a feature where you can link items in chat as a hover event. Is there a way I can find these hover events in a message, and edit them to also show the quantity of the item that was linked? Or is that data lost at this point

sterile rampart
#

That feels possible, might be worth talking to Josh directly though and seeing if you can just modify carbon to do that when it's inserting the hover events in the first place

grim bear
#

I raised a suggestion for it a while ago but it hasn't been looked at, so I'm thinking about just adding it in my plugin in the meantime

obsidian nimbus
grim bear
#

probably harder than what I want to do here, assuming it's possible

fiery oracle
opal nimbus
# opal nimbus

this is indeed the path i have taken, and it seems to be working very nicely!
currently, i'm just serializing the text with the plain text serializer, and my signs are looking very pretty
except they don't have any colour...
so now i want to properly serialize the net.kyori.adventure.text.Component into an HTML string, instead of using the plain text serializer
does anyone have any hints on how to beging doing that?

#

for starters, i can't seem to find a getter to access the actual text of Components

sand drift
#

Not all components are text components

opal nimbus
#

oh

sand drift
#

You would generally want to take a look at the component serialisers and how they work

opal nimbus
#

i have been looking there a bit

#

but it's a loot of code

sand drift
#

Well, yea, it's a lot of fun

opal nimbus
#

i thought i'd try being inspired by the ansi encoder

sand drift
#

You'd mostly want to be walking over the component and their children

opal nimbus
#

but eehh

#

mhm

#

yea

#

but how do i get the actual content

#

i couldn't discern that

sand drift
#

You would basically need to branch depending on the type of component

opal nimbus
#

in the plaintext serializer i see a StringBuilder

sand drift
#

Well, yea, as that's mostly just using a flattener

opal nimbus
#

but i can't actually see where it's calling that append

sand drift
#

that's the flatteners doing

opal nimbus
#

even in here, i don't see it

#

or does it happen in the .handle( method?

opal nimbus
#

is that where the sb::append function gets actually called?

sand drift
#

I would imagine that flattener.handle calls the component method there

opal nimbus
#

but intellij can't find any implementers of this interface

#

so i can't track it down any further

sand drift
#

I mean, an implementation of that is the sb::append call

opal nimbus
#

whaoh

#

okay hold on i need to process that

#

functions, like sb::append, can implement an interface?

sand drift
#

Yes

opal nimbus
#

wow

#

i did not know that

sand drift
#

it's a functional interface, i.e. an interface with only one method, which can be implemented using a lambda

opal nimbus
#

๐Ÿ˜ตโ€๐Ÿ’ซ

sand drift
#

has the "basic" flattener

opal nimbus
#

ooh that's where i have to look

sand drift
#

I mean, I'm not ultra familiar with this stuff, just cursory glancing

#

if I was going to start on something that poops out html I would basically start with a span tag, and every time it calls pop/push style, I'd basically de/nest a span tag or something with that info

opal nimbus
#

yeah that's also what i was planning

sand drift
#

would probably be horrible but I would hope that would give me enough familiarity of how it works to be dangerous

opal nimbus
#

but didn't know where to start at all

#

thank you for the information!

#

i really appreciate it ๐Ÿ’œ

rare sage
#

i guess you can look at how the minimessage web viewer does it

opal nimbus
#

for tonight, i'm going to just use this:

public class HTMLComponentSerializer {
    //TODO: Do not use this Plain Text Serializer.
    //This needs to properly support nesting.
    private final static PlainTextComponentSerializer PLAIN_TEXT_COMPONENT_SERIALIZER = PlainTextComponentSerializer.plainText();

    private static final HTMLComponentSerializer INSTANCE = new HTMLComponentSerializer();

    public static HTMLComponentSerializer html() {
        return INSTANCE;
    }

    public String serialize(Component component) {
        //Get Text
        final String text = PLAIN_TEXT_COMPONENT_SERIALIZER.serialize(component);

        //Get Colour
        TextColor componentColour = component.color();
        final String colour;
        if (componentColour != null) {
            colour = componentColour.asHexString();
        } else {
            colour = null;
        }

        //Generate HTML
        if (colour != null) {
            //The colour for this specific line has been overridden
            return "<span style='color:" + colour + ";'>" + text + "</span>";
        } else {
            //There are no overrides, so glowing here is not necessary. It is handled by the parent sign
            return "<span>" + text + "</span>";
        }
    }
}

i will improve this to actually handle nesting later...

#

it's already starting to look really good, though!

#

using adventure was a very good decision

#

this library is awesome!

#

i was able to remove a lot of custom parsing code \o/

#

in exchange for custom encoding code

#

but i had to do that anyway

#

even for my previous version which didn't use adventure

opal nimbus
# opal nimbus for tonight, i'm going to just use this: ```java public class HTMLComponentSeria...

i have now expanded it to this: https://github.com/TechnicJelle/BlueMapSignExtractor/blob/4645b538257a81a5ac6d28746868155ea3f69a60/src/main/java/com/technicjelle/BlueMapSignExtractor/HTMLComponentSerializer.java
what do y'all think?

as far as i've seen in my tests, sign text is generally just normal TextComponents, so the instanceof TextComponent that i'm doing isn't the most evil think, i think...

GitHub

Minecraft Paper plugin and BlueMap addon that adds markers for all signs - TechnicJelle/BlueMapSignExtractor

#

although it may also have Translated Components

#

i think i have a region file somewhere that has those, so i'll throw that into my testing suite now and see how it deals with it

wicked torrent
#

you probably want to sanitize that output

#

the serializer in squaremap api uses some google library

naive sphinx
#

Is there adventure to html converter?

devout sage
#

Probably not what you want, but the minimessage format is xml

#

If you're asking about actually replicating minecraft ui formatting on a web browser, uh, hope you can code

naive sphinx
#

I have text with color: and etc

#

Which I use in website and server

#

In website I currently stripr all the <>

#

Maybe it's possible to convert those tags to html elements with colors

cloud vapor
#

Scroll like two messages up lol

#

and also yes, adventure-webui serializes to HTML via a public API you can use or you can see how it does the serializing yourself

naive sphinx
#

Yea, i'm looking more for a php converter, for websites

cloud vapor
#

PHP just spits out HTML

robust wharf
#

Basically, we don't wanna reimplement the MiniMessage parser in other languages in fear of stuff not being aligned, so you should just use the API to get the html

hoary plume
#

I'm really confused regarding NBT in Adventure.

I got the exception that I need to use a Compound Tag for the "additions" in a dialog, but I can't just use CompoundBinaryTag.builder()...build() because it wants me to provide a BinaryTagHolder.

Looking at the Javadocs, it tells me to check net.kyori.adventure.nbt.impl for a platform agnostic implementation, but this isn't linking to anything and also doesn't make it very clear where exactly I should check (I assume one of the GitHub Repositories, but the main adventure one doesn't seem to have such a path anywhere? Is it referring to the archived NBT repo?)

#

tl;dr: How would I convert a CompoundBinaryTag into a BinaryTagHolder?

cloud vapor
#

it's referring to the adventure-nbt module

hoary plume
#

That isn't helping me much here

cloud vapor
#

net.kyori.adventure:adventure-nbt

hoary plume
#

Well....

cloud vapor
#

it's an nbt library

hoary plume
#

Does it have the source anywhere to check?

sweet hornet
cloud vapor
#

source for what?

hoary plume
#

The stuff it mentions in the docs but doesn't bother to link properly

cloud vapor
#

Feel free to submit a PR to correct the docs

hoary plume
cloud vapor
#

I've linked you to the javadocs for adventure-nbt and you've also been linked the source too

#

do you have a specific question?

sweet hornet
#

I think that jd comment is just wrong, and the impl subpackage does not exist. However, ...Impl classes are present in the nbt package

hoary plume
#

The docs imply there is a impl package in the NBT library when there isn't

cloud vapor
#

Yes and you're free to submit a PR that fixes that if you would like, otherwise you're just complaining when we're waiting here to help you with any actual problems you have :p

sweet hornet
#

Since this commit, the impl subpackage was merged into its parent

hoary plume
#

So.
I apparently need to provide a Compound tag according to the exception I've received.
Tho, in the method where I need to do that does it require me to provide a BinaryTagHolder, which seems to be some form of common interface here?
My current question is, what the best aproach would be to make a Tag that satisfies the BinaryTagHolder requirement while also being a compound tag.
Would I need to make my own implementation (Like the CompoundTagImpl example), or would there be a simpler aproach available in Adventure.
I use adventure through paper, if that is of any significant importance.

sand drift
#

BinaryTagHolder is something that just holds a tag, it's not a tag

#

it looks like there is a method on BinaryTagHolder that lets you create an arbitary holder

cloud vapor
#

You can create an instance using BinaryTagHolder#binaryTagHolder(String) where the parameter is the snbt

hoary plume
#

And I assume I would call some asString method or similar in the compound tag to convert it into a valid snbt string?

cloud vapor
#

See BinaryTagIO

hoary plume
#

This is so confusing....

#

I don't get how BinaryTagIO is helping me here....
Like if I look at Readers I only see methods for getting CompoundBinaryTags, which is something I can get using the Builder already...
And when I check the Writer I can see void methods that need Paths or OutputStreams or similar, which I doubt is what I need here?

sage river
#

I suppose there could be some kind of DirectBinaryTagHolder that would hold BinaryTag instance in adventure-nbt library to make it simplier ๐Ÿคท

cloud vapor
#

You can write a created binary tag to whatever output stream way you want to get a string

#

plenty of different methods to turn output streams to strings and w/e

hoary plume
#

Seems kinda overcomplicated to me...

cloud vapor
#

Not really, it's kinda Java IO 101

#

But like this is just a suggestion of what library to use, obvs you can use whatever nbt library you want as long as it can output snbt you can throw into BinaryTagHolder

#

or make your own one, or use nms, or whatever really

hoary plume
#

All I seriously want is, to have one single integer added to a BinaryTagHolder, so that I can later extract it for further use

#

Nothing more

cloud vapor
#

why?

#

can't you just use click callbacks and just hold the reference to whatever int you want during the dialog?

hoary plume
#

I'm using Paper's custom click event

sand drift
#

I mean, from a 2 second glance, you'd create the compound tag, then use TagStringIO and toss the output into a BinaryTagHolder?

cloud vapor
sage river
cloud vapor
#

just use ClickEvent.callback

hoary plume
sage river
#

where

hoary plume
hoary plume
sage river
cloud vapor
#

so clean you have to include an entire nbt library haha

sage river
#

you have outdated adventure-nbt

hoary plume
cloud vapor
#

don't reinvent the wheel, ClickEvent.callback is a user-friendly alterantive to doing it yourself

sage river
#

what

cloud vapor
#

Paper doesn't ship adventure-nbt

sage river
#

Paper doesnt include adventure-nbt

hoary plume
#

K...

sage river
#

and it doesnt have to match adventure api version

hoary plume
#

Then screw this honestly... I won't shade in/download nbt on runtime just for this...

#

Wanted to use the Event but guess this stuff is just too annoying to setup properly.

cloud vapor
#

Good idea, you're saving yourself a world of hassle by using the nice clean click callback system we made haha

hoary plume
#

Not too much

#

But whatever

cloud vapor
#

click callbacks are a wrapper around the custom click event - so it does the nbt, serialization/deserialization, filtering, event handling all for you

#

if you wanna do that all yourself then go ahead we're not stopping you

#

even has more logic for custom expiry and uses as well

sweet hornet
#

Just a side question on this topic, I am just wondering, when showing a dialog to a user, with multiple click actions (with callbacks), he only click one of them, and we show him an updated version of the dialog. Aren't we "accumulating" callbacks into memory, that will never be used?

#

I.e., is setting a really short-lived expiration a good practice to prevent this?

#

(a few minutes)

#

(and of course single use, but that only work for the one that is clicked)

cloud vapor
#

hm - i mean i cant see it actually being a problem

#

but yeah maybe - or we could have a "group" system so that other callbacks with the same group expire when one does or smth

sweet hornet
#

I did not dig into the implementation, but I guess each time we send a callback, Paper needs to remember it somewhere, in a Map or something, no?

cloud vapor
#

yeah

#

i cant remember how paper implements it either

sweet hornet
#

So, in a scenario of a user-controlled trigger (like, a dialog showing/updating based only on user input), wouldn't it be possible for a malicious user to "fill" the memory with unused callbacks?

cloud vapor
#

you'd probably want a sensible expiry anyway

sweet hornet
#

(of course not limited to dialogs, it would also apply to chat-based callbacks)

#

Yes, but the default one being 12 hours, I something stumble across code where I forgot to lower it, and I always had this question of whether it would be a possible attack vector or not

#

I guess it is probably not the most obvious way an attacker could think of, I admit it

cloud vapor
#

yeah idk, hard to say really

#

i do remember being not very impressed with paper's implementation of the click callback stuff, but then my ideal solution is just throw it in a nice easy caffiene cache haha

grim bear
#

is it safe/recommended to store an object with Key fields in json files? or is it better to have them as strings and create keys from them when needed in runtime? it seems to work fine, but that doesn't always mean it's the best approach

#

the keys I'm saving are DamageTypes and EntityTypes

#

I'm using the following Gson serialiser in case that's relevant, because my object also contains Component fields

cloud vapor
#

I don't see any particular reason why not to

grim bear
#

as in, why not to do it the way I'm already doing it?

cloud vapor
#

Yeah

#

nothing wrong with using keys anywhere

tranquil moth
#

can legacy symbols be converted to minimessage format?

#

like the string
&cHello world
becomes
<red>Hello world
or will I have to do that manually?

sand drift
#

MM doesn't "convert" anything

#

you would need to deserialise it with the legacy serialiser and then throw it into minimessage

wet kestrel
#

Your earlier question was:

Is it possible to deserialize both legacy and minimessage format in the same string?

This is not going to work out happily. Like, there's no solution that results in predictability or joy.

If you have legacy stuff from an earlier version of the plugin, first do a one-time migration from legacy to minimessage. Then you can start using minimessage going forward. Don't mix and match.

tranquil moth
#

kk

#

is there a website or something I can use to copy n paste my messages to convert the legacy to minimessage? or do i have to manually find and replace?

#

(for that one-time migration)

wet kestrel
#

You should read both messages cat wrote instead of just the first one. The legacy serializer can deserialize to component, and then you can serialize to minimessage to save it.

tranquil moth
#

nvm its just like 4 things i have to change. thanks lol

#

Slightly confused now. For some reason my messaging system doesn't deserialize the minimessage string.

commandSender.sendMessage(MiniMessage.miniMessage().deserialize(message));
#

instead I just get the raw string.
(e.g. <red>Hellow world)

sand drift
#

Did you run the MM string through the legacy serialiser or something?

tranquil moth
#

nope

sand drift
#

probably want to print out the raw string before you deserialise it, hard to say with the info provided

wet kestrel
#

Also note that, if just doing default minimessage deserialization, you can do commandSender.sendRichMessage(message) which is waaaaay shorter.

tranquil moth
#

nvm im an idiot. i forgot to rebuild the plugin-

wet kestrel
#

And even sendRichMessage(message, TagResolver) if adding any, actually! Forgot about that one. :3

tranquil moth
#

what do tags do?

wet kestrel
#

So basically, unless you're doing a non-default MM instance (which is rare) you can save a lot of time.

tranquil moth
#

oh you mean the <xyz> tags

wet kestrel
#

Yes

tranquil moth
#

ah ok that makes sense

wet kestrel
#

commandSender.sendRichMessage("Hello <name>!", Placeholder.unparsed("name", "SpyCoderX")); would send you "Hello SpyCoderX!"

tranquil moth
#

oh cool

wet kestrel
#

Check the MM docs/javadocs for info on that.

safe epoch
#

hi, i tried using MiniMessageImpl#deserialize in every tick for updating scoreboard for each player and it just generate too much memory usage. i need to be able to format text and minimessage does the job
is there any reason it should use so much RAM? any alternavite or suggestion please?

grim bear
#

is there a way to translate DamageType? I can't seem to call Component#translatable on them

fiery oracle
#

damage types don't have associated translation keys

#

what exactly are you trying to do?

grim bear
#

Display top 5 causes of death in a hologram. I have a damage type key stored for every death

#

I guess I can just map my own translations

upper tinselBOT
final nimbus
#

hello guys. I'm right now trying to achieve text with translations. I've got a .yaml file where I get my translations on MiniMOTD format.

game:
  round:
    started: "<white><gold><b>The game has started!</b></gold></white>"

  over:
    no_winners: "<white><red><b>Game over!</b></red> No winners this time.</white>"
    single_winner: "<white><green><b>Game over!</b></green> <aqua><b>{player}</b></aqua> is the winner!</white>"
    multiple_winners: "<white><green><b>Game over!</b></green> Multiple winners survived!</white>"

Doing

player.sendMessage(
        Component.translatable("game.scoreboard.title"))
  );

works neatly and as intended. but I'm trying to add tags. for example in game.over.single_winner, how could I dinamically change {player} to whatever I want via code?

#

I've seen I could tweak the deserializer to achieve my result, but I'm unsure how I could go on about it

#

any help would be greatly appreciated!

fiery oracle
#

by "MiniMOTD format", do you mean minimessage?

final nimbus
final nimbus
fiery oracle
#

are you registering your translations using the minimessage translator stuff?

final nimbus
#

sorry lol

final nimbus
fiery oracle
#

yes, but is it using the minimessage translator stuff?

final nimbus
#

oh s- I see now what you mean

fiery oracle
#

or using a MiniMessageTranslationStore?

#

if either of those 2, what you sent is how you'd specify custom tag resolvers, yes

final nimbus
#

yeah that's the problem I was only implementing the interface

#

yeah dude you're 100% right, I feel so stupid right now lol, thanks!

fiery oracle
final nimbus
#

okay that's just what I needed

#

I can't believe I was stuck on hours for this lmao

#

thanks man

white sundial
#

Does <newline> supposed to work in item lore?

#

Something seems off

#

Oh, discord search tells me it isn't supported in lore. Suggestion: make the web editor not imply that it does work.

cloud vapor
white sundial
#

I guess a small red text on the top could do fine when the input string contains the tag

#

Or in the docs, just put it somewhere, I think it is an important note

cloud vapor
#

Feel free to submit a PR!

tranquil moth
#

Or you could create a function which splits a component at every newline, returning a list of components?

rare sage
#

Easier said than done, but feel free to submit a PR for that too!

cloud vapor
#

it's much easier to just have a list in your config/whatever

tranquil moth
sterile rampart
#

serialize to what, json?

tranquil moth
#

String

#

Minimessage

rare sage
#

no, the process is more complicated than that due to the tree nature of components

sterile rampart
#

yeah you have to maintain the full tree, no real benefit to serializing when all the info exists in the deserialized tree anyways

tranquil moth
#

Well, if you are doing it as a component tree, you just need to split components which have a newline in them into two components with the same position in the tree and same properties (color, style, etc.)

rare sage
#

yes, which again is easier said than done

#

no-one has PRd a fully working solution to adventure and many have tried, otherwise it'd be in the api

tranquil moth
#

Hmm

rare sage
#
text("green text", GREEN)
  .append(text(" red text in the first line\nred text in the second line", RED))
  .append(text(" also green in the second line"))

is enough to give headaches, and it's a single level deep

sand drift
#

You can't just cleanly split, you need to iterate over the tree and create new trees with the splits that you need

rare sage
#

let alone when a single component in itself is a single newline that could have its own style for whatever reason

#

it's not an impossible problem, mojang has solved this issue on the client text decomposition :p but it is not a trivial enough problem for the contributors' free time

tranquil moth
#

I see

#

From what I can tell, youโ€™d only need to iterate over the tree and replace single components with newlines in them into multiple components with the same properties, but only the last one keeps the โ€œextraโ€ component list.

cloud vapor
#

and all of this is why i always say "just put a list in your config" haha

tranquil moth
rare sage
#

not necessarily only the last one would have the children

#

if you have multiple styles spanning multiple lines and depths

cloud vapor
#

i dont even think it's a nicer solution, i would hate being an end user and having to write everything on one long line bc you made a fancy splitting solution

tranquil moth
#

No because the whole point of newline splitting would be so you can do this:

Component.split(โ€œโ€โ€
This
can
split
โ€œโ€โ€);

and that would allow for writing things like lore in one component .

rare sage
#

sure but if you are taking it from a configuration file, unless you allow for both options you are also forcing the user to not have them tidy if they desire ยฏ_(ใƒ„)_/ยฏ

tranquil moth
#

๐Ÿคท I see problem, I solve problem. The user can do what they want lol

rare sage
#

they can't do what they want if you don't give them the freedon

sterile rampart
#

i mean config file is easy, it's just like:

my_item:
  lore: |
    <red>first line
    <bold>second line
tranquil moth
#

Butโ€ฆ wouldnโ€™t it be a function the user calls in their code?

rare sage
#

by user i mean end user of the application using adventure, where the application takes the "lines" from a configuration file the end user configures

tranquil moth
#

Ah

rare sage
#

which is why kezz keeps saying "take a list in your configuration file"

sweet hornet
rare sage
#

which is the simple enough solution

sweet hornet
#

Huh

sterile rampart
#

read lore as a single component, then split it

sweet hornet
#

Wait, what was the point of your example?

sterile rampart
#

the split should preserve style across lines

sweet hornet
#

Oh ok

#

Yes yes yes

#

I thought you were illustrating the way we could ask the user multiple lines of lore, then parse each one individually

#

But for your example to work, we would need the holy graal Component#split

tranquil moth
#

Imma think on this

cloud vapor
#

and the alternative that doesn't require a WHOLE bunch of code lol

my_item:
  lore:
    - <red>first line
    - <red><bold>second line
tranquil moth
#

When you encounter a newline, wouldnโ€™t you just copy the current list of colors and styles in order, exit out of the current json component, and create a new stack of components with the same styles and order, but with their text set to โ€œโ€?

#

And then youd just have to integrate the remaining unsplit/unprocessed components into the newly created one.

sterile rampart
#

"just" is doing a lot of work there

rare sage
#

this is why i keep saying it's easier said than done, lol

#

the theoretical process is easy to think about at a high level

#

but actually putting in the time and writing all the gross state-tracking code is the challenge

tranquil moth
#

Couldnโ€™t you copy the current nodeโ€™s parent tree but skip anything before it and then set all of its parents text to โ€œโ€?

rare sage
#

components don't keep track of their parent

#

do you know what "easier said than done" actually means btw?

sterile rampart
#

if, instead of spending all this time talking, you went and tried to implement something, you'd understand the issues way better

tranquil moth
wet kestrel
#

Go enjoy the pool then

tranquil moth
#

XD

white sundial
#

I only wanted newlines to work in lore because I need to create some idiot/crowdin format proof config. So every lore would be just one line and splitting on new lines. But yeah this seems kinda complicated to do. Instead I decided to use wrapping which also seems kinda complicated to do, but found a gist which looks like is working perfectly fine or at least I couldn't break it yet
https://gist.github.com/Minikloon/e6a7679d171b90dc4e0731db46d77c84

white sundial
final nimbus
#

hello everyone! I'm using currently Translation components and I'm trying to use them for Item's names. Here's a minimal working example of my code so far

ItemStack sword = new ItemStack(Material.DIAMOND_SWORD);
ItemMeta meta = sword.getItemMeta();
meta.itemName(
  Component.translatable("event.give_special_item_sword")
);
sword.setItemMeta(meta);```
However, in game, they only show the raw string `event.give_special_item_sword`. what do I have to do in this case?
#

I'm using a custom translator btw, and it seems to be working well so far

sand drift
#

Item components canโ€™t be translated as that would require modifying the item and would break a bunch of stuff

final nimbus
grave smelt
#

How can I create a system where I have a color gradient over a message but also if [item] is in the message, that's replaced by a placeholder without allowing any other tags to work in the message

cloud vapor
#
  1. use <item>
  2. create a mm instance with the tags you don't want a player to use
  3. run stripTags with that instance on the input string
  4. create a new mm instance with the item tag
  5. prepend your input string with the gradient tag you want
  6. using the instance in step 4, use that to make your resulting component with the new input string made in step 5
thin condor
#

is it not advised to use the keys defined in papers extended Sound interface with adventure's sound api?

#

the docs use string literals for sound and i was thinking it would be nicer to use the ones provided by this interface as a sort of enum? is there any supported way of doing that or is that discouraged for some reason

sterile rampart
#

the adventure docs do not assume the existence of paper, but ya it implements Sound.Type for a reason

thin condor
#

idk why i didn't think of that that makes a lot of sense

#

ty

grave smelt
rare sage
#

you can build your own instance, MiniMessage.builder().tags(TagResolver.resolver(... base tags)).build()

grave smelt
#

So here's the thing, this works but not really. my tag in the middle is computed as part of the gradient when it shouldn't be so I lose half of the gradient to the tag.

[01:42:42 INFO]: <gradient:#00ffa6:#fc4efc>adsjkfhjkahdsfjkh <2b055d2b-aef0-4ab0-8de4-c73b95328070> nasdfnfjasdnjk
[01:42:56 INFO]: <gradient:#00ffa6:#fc4efc>fajhfjdbjasbnfjhkbakjsldfn
wet kestrel
grave smelt
wet kestrel
#

You were saying your tag shouldn't be computed, so put the </ before the tag.

grave smelt
wet kestrel
grave smelt
#

I understand, of course I could do that but the important part here is that the tag is a placeholder that the user puts in the middle of their text

#

I just don't want the tag to take from the gradient

wet kestrel
#

You have users manually entering entire UUIDs into chat? Sorry, I didn't see that coming ๐Ÿ˜†
I'll let someone more skilled in minimessage help further

grave smelt
#

a user says [item] in chat (or whatever, it's a regexp pattern), I replace that with <$randomUuid> so that it's picked up by my custom tag handler

#

in chat the person wrote ...text...[item]...text...

wet kestrel
#

Okay, and then you're slapping a <gradient> on the front of it?

grave smelt
#

yeah

#

that's their chat color

#

<chatcolor>.....text.....[item]......text.....

wet kestrel
#

Intense! Thanks for the clarification. Outside of the below thought, I'm out of ideas. Someone else may have a better idea.

I would remove the tag, process to minimessage, walk the tree until I find the place the tag belongs and insert its component. I don't have an answer for how because I've never done that but that seems like a logical strategy for it. May not be the best one though.

#

Heck, maybe not fully remove but put in some character players can't send, and use that to find it?

grave smelt
#

the solution is just to fix the bug in Minimessage's gradient parser code to ignore tags

wet kestrel
#

If you PR that, awesome!

naive sphinx
#

If the issue is associated with minimessages, do I need to reproduce it on paper?

robust wharf
#

I mean, thats the easiest

#

but web viewer will work the same for us

naive sphinx
#

The issue is:
A few months back I said that minimessages performance was horrible. At that time I used legacy colors, new colors and a lot of gradients. I was notified that gradients with legacy colors can be the issue.
We now removed all of legacy colors from the server, and on that server reduced the gradients to a minimum. Texts that update each second don't have gradients.
There is a bit over 4000 text displays, by my calculations up to 1500 updates each second.

1 player in a survival server with almost everything vanilla, normal mob spawning, playing as usual, is using up to 1ms of tick
1 player just standing in a boxpvp server with all those text displays, with no other active entities, no random tick time, is using up to 5ms of tick
Will send a spark report a bit later

#

I don't understand why, but the spark report is messed up

cloud vapor
cloud vapor
naive sphinx
#

1500*

#

Timers, tops, etc

sand drift
#

I mean, doing stuff takes time

naive sphinx
#

Will need to double check the tops, maybe update each minute

#

But mine timers needs to be each second

sand drift
#

Not really aware of there being any real performance issues when MM is used in a sensible manner, any parser will bog down, especially when dealing with anything more complex than basic string manip

cloud vapor
#

We're also only looking at 38 ticks there over 6 minutes

#

You're likely just picking up ticks where gc hit in

naive sphinx
#

I'm afraid that with increased player count the issue will be way worse

#

More text displays

cloud vapor
#

1500 pieces of information updating every second for one player online is still a bit insane

#

I'd suggest not doing that

cloud vapor
naive sphinx
#

Limiting it via distance in such a small place isn't logical, especially when with more players the distance will be irrelevant as players will be more spread out.
But yea, need to check with more players. Maybe processing all that text will always take 5ms, and player count won't have that much of an impact

cloud vapor
#

Well yea, more players isn't going to make a static amount of work take longer

#

But again, 38 ticks

sand drift
#

I misread part of the report, just under 2/3s of the the report is literally converting it to be stored on the entity

#

i.e. memory churn and potentially a "you're expecting magic from overly complex components" territory

cloud vapor
#

You can see your mspt avg is 1.4ms so it's not taking 5ms for the majority of the time

sand drift
#

That too, yea, you'd basically need to benchmark it using something other than a sampler if you wanted to see how much time it was actually taking to do stuff

naive sphinx
#

Got it

#

Okay

fathom mulch
#

how can i make a custom tag resolver that replaces the text inside of it with different text?

prisma mason
#

Isnt that just Placeholder.unparsed or Placeholder.component?

sweet hornet
#

You're most likely going to need to implement Modifying, but can you tell more about your use case please?

fathom mulch
#

im trying to make a custom tag that takes the contents and turns them into the small caps font

#

as far as i know that font is not built in

sweet hornet
#

I did a prototype for this few times ago, and yes you have to create a tag implementing Modifying, and paye extra care about the fact that not all components are text (thus, you cannot modify everything)

sweet hornet
#

I suggest you first try to do it "simple" like by just using String#toUpperCase() for example, so you can test your text modification logic, and then you can improve it by adding the small caps conversion logic

#

Because Modifying are powerful, but also quite surprising ๐Ÿ˜„

#

(Just to save you some time, but you'll see it yourself, you need to clear the children of the component if you don't modify it, for example, because they'll get re-added by the implementation)

fathom mulch
#

not sure what you mean by most of this

#

i'll see what i can do, thank you

obsidian nimbus
#

i got you covered

#

oh im a bit lae

fathom mulch
#

Brotha you ain't late

zealous meadow
#

I think this example code maybe doesn't match with example image. is my though right?

fathom mulch
#

yours is def better, i dont think mine preserves the style

#

many thanks!

regal frigate
#

Hey, is there a reason why source removing from the global translator returns false?

final GlobalTranslator globalTranslator = GlobalTranslator.translator();
if (translationStore != null) {
    plugin.getSLF4JLogger().warn("Removing existing translation store");
    final boolean removed = globalTranslator.removeSource(translationStore);
    plugin.getSLF4JLogger().warn("Removed: {}", removed);
}

Console output:

[12:45:13 WARN]: [MyPlugin] Removing existing translation store
[12:45:13 WARN]: [MyPlugin] Removed: false

It is definitely registered, but it's populated with translations after being registered in the GlobalTranslator.

Full method:

// ...
private MiniMessageTranslationStore translationStore;
// ...
private void initializeTranslationStore() {
    final GlobalTranslator globalTranslator = GlobalTranslator.translator();
    if (translationStore != null) {
        plugin.getSLF4JLogger().warn("Removing existing translation store");
        final boolean removed = globalTranslator.removeSource(translationStore);
        plugin.getSLF4JLogger().warn("Removed: {}", removed);
    }

    translationStore = MiniMessageTranslationStore.create(TRANSLATIONS_STORE_KEY);
    translationStore.defaultLocale(Locale.ENGLISH);

    plugin.getSLF4JLogger().warn("Adding new translation store");
    final boolean added = globalTranslator.addSource(translationStore);
    plugin.getSLF4JLogger().warn("Added: {}", added);
}
// ...
regal frigate
#

Well, it seems that if the TranslationStore was mutated after registration, it can no longer be unregistered using the same reference. Even though it has a key that uniquely identifies it.

cloud vapor
#

that's really bizarre

#

what an odd bug, thanks for reporting!

tough peak
#

Hey what is the use of ClickEvent.custom() and how can I use it?

sweet hornet
#

Recently (1.21.5 i think?), Mojang added a new "custom" click event, where the client just sends a packet with arbitrary NBT data

#

So this click event is just the implementation of that new feature, allowing you to use it

little elbow
#

its main purpose is dialog form feedbacks

tough peak
#

oh

#

ok then

little elbow
#

also, the callback system in paper is implemented with it now, not with a command click event wrapper

tough peak
#

thought it used to call an event or something

little elbow
#

Paper has an event that does fire when the custom payload is received, yes

nocturne marsh
#

Hey,
is there a way to convert a com.mojang.brigadier.Message to a Component ?

prisma mason
#

MessageComponentSerializer I think

#

But that's only on paper IIRC

nocturne marsh
#

thanks that's what I was looking for
I use paper

devout sage
#

why is EntityType.getTranslationKey() deprecated? What should I use instead?

quaint monolith
#

EntityType#translationKey()

vivid bobcat
#

how can I remove MiniMessage default tag resolvers? is it possible?

rare sage
#

you can build your own instance, MiniMessage.builder().tags(TagResolver.resolver(... base tags)).build()

wet kestrel
#

Please do not misuse the help channels.

devout sage
#

Is there convenience api for generating reference components to entities/players the same way vanilla death messages and chat messages do? for example:

"<insert:hjk321><click:suggest_command:'/tell hjk321 '><hover:show_entity:player:f90efb8f-6362-43f0-ab7c-6be7f8ec242b:'hjk321'>hjk321"

"<insert:27348008-73cd-4ffd-8791-6d7d5d7d1fa5><hover:show_entity:skeleton:27348008-73cd-4ffd-8791-6d7d5d7d1fa5:'<lang:entity.minecraft.skeleton>'><lang:entity.minecraft.skeleton>"
#

it's easy enough to construct myself but is rather annoying to do so