#adventure-help

1 messages · Page 12 of 1

grim bear
#
miniMessageLimited = MiniMessage.builder()
        .tags(TagResolver.builder()
                .resolver(StandardTags.color())
                .resolver(StandardTags.gradient())
                .resolver(StandardTags.rainbow())
                .resolver(StandardTags.decorations(TextDecoration.BOLD))
                .resolver(StandardTags.decorations(TextDecoration.UNDERLINED))
                .resolver(StandardTags.decorations(TextDecoration.STRIKETHROUGH))
                .build())
        .editTags(builder -> builder.tag("db", (args, ctx) -> StandardTags.color().resolve("dark_blue", args, ctx)))
        .editTags(builder -> builder.tag("dgreen", (args, ctx) -> StandardTags.color().resolve("dark_green", args, ctx)))
        .editTags(builder -> builder.tag("da", (args, ctx) -> StandardTags.color().resolve("dark_aqua", args, ctx)))
        .editTags(builder -> builder.tag("dr", (args, ctx) -> StandardTags.color().resolve("dark_red", args, ctx)))
        .editTags(builder -> builder.tag("dp", (args, ctx) -> StandardTags.color().resolve("dark_purple", args, ctx)))
        .editTags(builder -> builder.tag("dgray", (args, ctx) -> StandardTags.color().resolve("dark_gray", args, ctx)))
        .editTags(builder -> builder.tag("lp", (args, ctx) -> StandardTags.color().resolve("light_purple", args, ctx)))
        .editTags(builder -> builder.tag("grd", (args, ctx) -> StandardTags.gradient().resolve("gradient", args, ctx)))
        .editTags(builder -> builder.tag("rb", (args, ctx) -> StandardTags.rainbow().resolve("rainbow", args, ctx)))
        .build();

This is my instance now, is this a giant yikes? Wondering if there is a better way to do it (I'm pretty inexperienced with consumer type stuff)

#

and is there a way to allow these shortened colour tags to also work inside gradient tag usages? e.g. <gradient:db:dr> would be equivalent to <gradient:dark_blue:dark_red>

sweet hornet
sweet hornet
#

Just check whether the initial builder instance (MiniMessage.builder()) comes empty or with standard tags built-in. If is starts empty, that's fine, if all standard tags are pre-registered, then you need to first remove them with something like MiniMessage.builder().tags(...empty...).editTags(...)

#

I just can remember how easily you can make an empty tag resolver to clear them

#

Also, you might want to define yourself an helper function like:

private static void defineAlias(TagResolver.Builder tags, String alias, TagResolver resolver, String realTag) {
    tags.tag(alias, (args, ctx) -> resolver.resolve(realTag, args, ctx));
}

So you could just do like:

defineAlias(tags, "db", StandardTags.color(), "dark_blue");
defineAlias(tags, "dgreen", StandardTags.color(), "dark_green");
...
boreal orchid
sweet hornet
boreal orchid
#

Ah, I see what you mean now, I accidentally put the gradient tag as alias there. Fixed that

sand drift
#

That would rely on the color provider which afaik doesn't currently properly support that

sterile star
#

Just imagine how nice it'd be

shadow wyvern
#

:) made a hytale platform implementation myself

shadow wyvern
#

I can upstream this if I clean it up

cloud vapor
#

Not worth upstreaming it until they actually release their API

shadow wyvern
#

Yeah I guess so, and they are probably going to implement more features for messages soon enough, there's no proper way to do hover events currently (but of course maybe not)

robust wharf
#

the main issue is that we couldnt publish it

#

idk why they dont publish an api jar

#

it just makes everybodies life harder than it needs to be, I thought modding was a focus?

sweet hornet
#

I guess is "modding" the way they intended (through they own built-in tools) that is a focus

#

Like, not modding for developers, modding for content creators (making and adding assets)

cloud vapor
#

iirc they are going to publish an api jar and open source the server but currently they're focusing on moving fast and breaking things

sweet hornet
#

Quotes from their EULA:

Where we provide you with official APIs, SDKs, or tools pertaining to the Game, your use is subject to the EULA

You may not: (a) reverse engineer, decompile, or disassemble the Game except as permitted by law;

Nothing in this EULA limits your rights under applicable law to conduct reverse engineering solely and to the extent necessary to achieve interoperability between the Game and independently created software, provided such activity is strictly limited to what the law permits and does not disclose or misuse our proprietary information.

#

So they say that they provide an official API, somehow. But we can't compile or reverse engineer it. Except to create interoperable software (i.e. mods)!

sand drift
#

Well, the official deployment of stuff is coming; Once that comes people can build against it, until then, there is no artifact to build against which wouldn't be somebody redistributing their software

shadow wyvern
#

Yeah they said it'll be published to maven central. I've been using lucko's repository for it for now

last horizon
#

as far as i understand it lucko breaks the eula by publishing the jar himself
i made eula compliant "tooling" for it because i needed it for ci
i cant rely on adding the jar manually myself

hardy estuary
steady osprey
#

half an hour ago 😁

sweet hornet
#

I haven't looked at it at all, just remembered someone asked about that here, so it connected the dots

stark badger
radiant shadow
shadow wyvern
#

I guess I'll open a PR

#

My HytaleComponentSerializer is questionable

#

but works very fine (and with translations)

shadow wyvern
#

Need to fix all checkstyle things tho

cloud vapor
#

publishing the api jar != releasing and relatively stabilizing an api

#

i wouldn't have anything in adventure until they've released stuff, started documenting, released some sort of policy for evolution/deprecation, etc

#

for now it would make a nice community library

shadow wyvern
#

I opened a PR, should I make it a draft? Or are lingering PRs disliked?

#

They've marked a lot of stuff deprecated already to steer what you should do and what you shouldn't which I would take as a hint that undeprecated things are not going to change. The only thing that a stabilized API in the platform implementation would really matter is the message format

sterile rampart
#

I wouldn't trust that, tbh should probably grow as a separate repo for a bit

hardy estuary
#

In Component is there a way to colorize it with gradient instead of using Minimessage?

#

like Component.text(Some text)....

sour totem
#

there is not

hardy estuary
#

oh kk

#

mostly my main issue is that I have a replacement for {something}. But if before {something} somebody puts a <gradient> I am not able to recognize anymore {something} with TextReplacementConfig.

boreal orchid
#

it would change the format from {something} to <something> but hopefully that isn't an issue

hardy estuary
#

Example

#
final var textReplacementConfig = TextReplacementConfig.builder().matchLiteral("{something}").replacement(object.getReplacement()).build();

String input = "Dear <gradient:...>{something}</gradient>";
Component inputToComponent = Minimessage.deserialize(input);

inputToComponent = inputToComponent.replaceText(textReplacementConfig);
boreal orchid
#

the idea would be to not use text replacement config at all

#
var input = "Dear <gradient:...><something></gradient>";
var parsed = MiniMessage.miniMessage().deserialize(input, Placeholder.unparsed("something", object.getReplacement()));
hardy estuary
#

mmm but if the object.getReplacement() has minimessage tags inside it, will those get parsed?

boreal orchid
#

you can use Placeholder#parsed in that case I believe

#

I never remember whether one has to use parsed or unparsed in that situation

hardy estuary
#

nono I don't want to trust the getReplacement input

boreal orchid
#

then the other one is fine

hardy estuary
#

but Im trying now, thanks for the suggestion

mint path
#

Does adventure support the playerhead/itemstack components now?

boreal orchid
mint path
#

wasn't immediately seeing how to do it yet

#

yeah i'm just now updating from 1.21.8

sweet hornet
#

Well, considering they were added in Minecraft 1.21.9, that's logic

boreal orchid
#

if you're using MM, then the respective tags for those should be listed in the format documentation

mental vineBOT
mint path
#

Would just be using raw adventure for starters, gotta see about how to use an ItemStack, particularly one with custom model data from our resource pack

sweet hornet
#

That's not how it works

boreal orchid
#

if you have a resource pack, then you'll have to provide a sprite for your custom thing

#

it doesn't take the actual texture of the item in question

sweet hornet
#

Object components doesn't handle item stacks, they handle sprites. And unfortunately, it's up to you to find the sprite corresponding to the item

mint path
#

i mean we've been just using the unicode character for it for now which i suppose still works just fine

sweet hornet
#

Most items are defined from a simple item texture, so in those cases it's nearly a 1:1 mapping between the material and the sprite, but there are more complex cases. And custom models are one of them

mint path
#

But would like to start using vanilla mc items as well in things

#

so the key would more or less probably be the lowercased material name?

sweet hornet
#

For some of them, yeah. But while it is the case for most of items, it's certainly far from most of other materials (blocks)

mint path
#

Ah, very handy!

sweet hornet
#

But be careful, if the itemstack has an item_model defined, you should use that material instead. And if you have custom item textures, you should provide your own mappings, and maybe I could improve the code so provide an extension point to help with this, but I'm not familiar with custom item textures

shadow wyvern
sterile rampart
#

why would it need to be a fork? it could be a standalone library

shadow wyvern
#

A standalone library inside the adventure/paper organization? That's basically my question, because if so, that can be made a reality

sterile rampart
#

and realistically there's no point putting anything new into the adventure-platform repo, it's basically maintenance mode at this point

shadow wyvern
#

What would it be called when it would include implementations for other games?

sterile rampart
#

probably adventure-platform-hytale or sth

sterile star
#

Idk, I am not convinced that the Adventure platform can be implemented ontop of hytale

#

They are different games with way different UI elements

shadow wyvern
#

You could implement them all things Minecraft has in Minecraft-style as you can create UI elements server-side in Hytale to polyfill those. But that does go over what I would consider adventure's job

sterile rampart
#

i mean i've thought about doing up an adventure-platform-jline for a 'console' platform before

#

adventure-platform-hytale is no less realistic

sterile star
#

For the Component parts, yes, but not the actual UI elements

#

Good luck getting a bossbar to show in console

shadow wyvern
#

Components are the most important, for me adventure has been in my common module in plugins, so to add Hytale support I really didn't have to do much as to just port some libraries. This is the same for all Minecraft things too

sterile star
#

Adventure (and audiences) include stuff like books, bossbars, resource packs, sounds, action bars, titles, player list stuff

#

I don't know how many of those are in hytale. And sure, you could re-add them, but this still feels to me more like something you'd want tailored specifically for hytale (maybe rip out the components part of adventure?)

#

I am just saying you'd end up with a ton of unimplemented methods, which, if we remind ourselves of the Audience implementation in Velocity, can be a bit annoying for devs if they don't read the JD and just go off of methods

#

Something something sounds and books

#

Oh yeah also in components: object components, translatable components, hover style, click style, obfuscated style, text shadow, any sort of NBT, score, or other server-resolved components

hardy estuary
boreal orchid
sterile rampart
#

@shadow wyvern You are not kyori, do not publish software in the net.kyori namespace please.

shadow wyvern
mint path
#

Since LEGACY_COMPONENT_SERIALIZER.serialize can't handle Component.object(), how can I strip those out before doing a serialization of one?

sterile rampart
#

don't we let you pass a custom flattener in the legacy serializer builder?

knotty laurel
#

does adventure nbt not have a mergeCompound or similar method?

boreal orchid
#

you could technically do someCompound.put(otherCompound) and it'll overwrite tags as necessary

#

but if your idea of merging them is to merge their values, then that'd be more tricky

#

if CompoundBinaryTag#stream flattens the containing compound tags, which I doubt, you could just do it with a stream then collect it into a compound tag

#

though flattening the stream yourself shouldn't be hard either

#

well, I guess that'd end up with a flattened compound if you just collect it like that

knotty laurel
# boreal orchid but if your idea of merging them is to merge their values, then that'd be more t...

if I were to merge these two:
{components:{"minecraft:enchantments":{"minecraft:sharpness":2}}}
{components:{"minecraft:enchantments":{"minecraft:knockback":2}}}
I would expect a result of
{components:{"minecraft:enchantments":{"minecraft:sharpness":2,"minecraft:knockback":2}}}

and if I merged that result with
{components:{"minecraft:enchantments":{"minecraft:sharpness":3}}}
I would expect it to overwrite sharpness with that level
{components:{"minecraft:enchantments":{"minecraft:sharpness":3,"minecraft:knockback":2}}}

#

and if it was merging with a list I think it should just add that value to the nbt list

#

another nbt library, nbt-api has a method that does this (by calling nms)

sterile rampart
#

I mean dfu has something like that, it's not the wildest ask

#

could be pr'd

robust chasm
#

Hey, I've been looking for the Adventure API's branding icon/logo, if anyone could direct me or help me find it it would be amazing

#

Nvm, I think I found it

sterile rampart
#

what are you using the logo for?

robust chasm
#

I’m making a website to showcase a project I’ve been working on. Just wanna show what is being used

vast oxide
#

nevermind

cloud vapor
#

Yes we migrated the URL early last year

#

or maybe it was earlier than that i cant remember

vast oxide
#

oh really? that url always worked for me

#

i had it bookmarked for a long time and i use it very often

#

i thought maybe i'm getting blocked

#

but nah

robust wharf
#

maybe I should offer it under a papermc domain too so that I can acutally remmeber it, lol

sand drift
#

"it's adventure but without any of the vowels after a"

mint path
# sterile rampart don't we let you pass a custom flattener in the legacy serializer builder?

I don't fully understand how flatteners work. I see that I probably want to do something like this: java LegacyComponentSerializer.legacySection().toBuilder() .flattener(ComponentFlattener.builder() .mapper(ObjectComponent.class, component -> //???) .build()) .build(); but I don't know what to pass through to just strip (or replace with empty) this kind of stuff: Component.object(ObjectContents.playerHead(uuid))

cloud vapor
#

just do empty component

#

or replace with Component.text("bob's head") or w/e

mint path
#

It requires a string

cloud vapor
#

"bob's head"

mint path
#

i tried just "" but that kinda nulled out the entire component

cloud vapor
#

what are you trying to do

mint path
#

How would i extract the text content of that component?

cloud vapor
#

what text content

mint path
#
@BsonIgnore
public Component getHeadAndName(TextColor color) {
    if (headComponent == null) {
        headComponent = Component.object(ObjectContents.playerHead(uuid)).color(NamedTextColor.WHITE);
    }

    TextComponent name = text(" " + this.name);
    if (color != null) {
        name = name.color(color);
    }
    return headComponent.append(name);
}``` basically in legacy serialization the playerhead thing displays wrong so i need to remove it
cloud vapor
#

that's not wrong, that's how we did it

#

matches vanilla

#

but if you wanna remove it then yeah do ""

#

but you wanna build off an existing flattener otherwise you're just ignoring every other component type

#

e.g. ComponentFlattener.basic() or w/e

mint path
#

do i need to combine both? just doing empty string (well, "test") basically does this

#

it yeeted everything

cloud vapor
#

you are making a flattener that says "map objects to an empty string and ignore everything else" so yeah it's gonna be yeeting everything else

#

see ComponentFlattener#toBuilder to turn an existing flattener into a builder you can then modify

mint path
#

Gotcha, works. Thanks

#

now for a trickier one, is there a nice way for me to somehow also remove that whitespace i... forced in: #adventure-help message ?

#

eh probably just up to me to handle smarter

boreal orchid
#
return Component.textOfChildren(headComponent.appendSpace(), name)

like so

sterile rampart
#

that won't change the flattener output

boreal orchid
#

welp, I was thinking maybe you could do it with a complex mapper that doesn't consume the children of the object component but that sounds complex and probably not a good solution

mint path
#

everybody still rolling their own word wrapping? I seem to have a ComponentSplitter and I don't know where I got it from but i doesn't support ObjectComponents so it needs updating

sterile rampart
tulip wedge
#
        TextReplacementConfig.Builder replacer = TextReplacementConfig.builder();

        for (Var variable : vars) {
            replacer.matchLiteral(variable.name);
            replacer.replacement(variable.value.toString());
        }

        return component;
    }```this is obviously not gonna work like this but, how can i make something like this?
#
        for (Var variable : vars) {
            component = component.replaceText(replacer -> {
                replacer.matchLiteral(variable.name);
                replacer.replacement(variable.value.toString());
            });
        }

        return component;
    }```previously it was like this but i thought its not good
cloud vapor
#

I'd suggest using a proper placeholder system like MiniMessage

sand drift
#

I mean, suuuure, but ^

tulip wedge
#

i already suffered converting everything to Adventure

#

i like the Var system i wanna keep it 😭

sand drift
#

replacing stuff inside of components is generally asking for some headaches especially if you want to start introducing some other features, it won't match across components, for ex

tulip wedge
#

simple placeholders

sterile rampart
#

ya if there's a bunch of placeholders from user input just go with MM

#

don't sunk costs yourself

cloud vapor
#

yeah the solution to a good placeholder system is to use mm - your second solution would kinda work mostly ig but jank

tulip wedge
#

😭

granite spindle
#
TagResolver resolver = TagResolver.resolver(
        Placeholder.unparsed("queued", String.valueOf(QueueService.get().getQueueSize())),
        ...
);

if (state.equals(ProfileState.IN_QUEUE)) {
    QueueEntry queueEntry = QueueService.get().get(player.getUniqueId());
    if (queueEntry == null)
        return resolver;
    Division kitDivision = profile.getGameData().get(queueEntry.getKit()).getDivision();
    resolver = TagResolver.resolver(resolver,
            Placeholder.unparsed("kit", queueEntry.getKit().getDisplayName()),
            ...);
    if (kitDivision != null)
        resolver = TagResolver.resolver(resolver,
                Placeholder.unparsed("kit_division", kitDivision.getDisplayName()));
}

is there a better way of doing conditional placeholders?

cloud vapor
#

you could do that logic inside a tag

#

so make your own tag resolver, check if your queue entry or w/e is null and then return that tag

granite spindle
#

i do want to keep this in one function, otherwise it could get pretty complicated

cloud vapor
#

then ig that's fine too

boreal orchid
#

I am not sure how to feel about that deeply nested tag resolver

granite spindle
#

me neither :/

boreal orchid
#

well, not that deep, probably just 3-4 levels but still

granite spindle
#

this is just a small part of the code lol

boreal orchid
#

I would have a List<TagResolver> where you add all your resolvers and only at the end wrap it in a single resolver

granite spindle
#

is there a caveat to doing what i'm currently doing though

boreal orchid
#

I don't think it matters either way

#

one just looks more iffy than the other, since I don't know how well MM deals with deeply nested resolvers but I think it might just flatten them into a sequential tag resolver

granite spindle
#

that's what i'm hoping

#

also with components, how are we supposed to set PAPI placeholders? replaceText?

boreal orchid
#

ideally you just set them before you parse the text into a component

sterile star
#

Alternatively you could use a tag resolver for PAPI placeholders

boreal orchid
#

people do that too ^, but it means changing the format to something like <papi:luckperms_prefix> instead of %luckperms_prefix%

sterile star
thin osprey
#

how do i strip some tags from a string but keep all the others?

#

like i want to strip away click but keep the color tag

#

is it possible

#

please @ me on response

cloud vapor
#

make an instance with the tags you want to strip, call stripTags on the string

boreal orchid
#

There’s stripTags which takes a tag resolver

cloud vapor
#

but like, this feels like an xy - you can just make an instance that ignores tags you don't want to ignore

boreal orchid
#

Ah but that’s just for additional tags

thin osprey
#

yeah i want to strip built-in ones

boreal orchid
cloud vapor
#

get a builder, set the tags to only specific ones you want in StandardTags

thin osprey
#

tag or tagresolver does not have striptags only my minimessage instance has it

#

ah you meant mm instance

#

not a tagresolver

#

let me see

tulip wedge
#

i remember mojang adding something for showing material icons in chat, does adventure support that yet? how do i do it?

sterile rampart
#

Component.object(...)

tulip wedge
#

what do i give to that method tho 😭 couldnt find anything in docs

#

ohhh i see

#

mb

#

Component.object(ObjectContents.sprite(Key.key("minecraft:items"), targetSword.get().getKey()))

#

🤔

#

tried directly giving the material key too

#

figured it out okay

sweet hornet
hardy estuary
#

Is there a way to use a TagResolver against a Component? Mostly to avoid calling component = component.replaceText(......);

cloud vapor
#

No

hardy estuary
#

so only solution is calling component = component.replaceText?

cloud vapor
#

Why do you have a component in the first place?

hardy estuary
#

Its from the ChatEvent

cloud vapor
#

Turn it into a string then - plain text serialize it or smth

hardy estuary
#

mmm no yeah its okay I mean, but why not use replaceText?

cloud vapor
#

idk, you were the one who said you wanted to avoid it :p

#

it's a bit slower and more object churny than mm - plus a whole lot less powerful than mm, and you basically would have to write an entire reimplementation of mm to get the same behaviour

#

but like if you're just doing simple stuff it's probably fine

hardy estuary
#

so you think its faster to serialize and deserialize against a TagResolver with Minimessage?

boreal orchid
#

If it is for a chat renderer, you don’t have to serialize the component into a string, you can just make it a placeholder of a mm format string. That’s what people usually do

#

It allows you to offer a config option for the message format which is nice

slim cloak
#

hello, if i use TranslatableComponentRenderer and say no resource bundle had a key in it, does it skip that one and leaves it to client or something else?

hardy estuary
#

Hello, I need to dispatch chat to other connected servers and I have this doubt.

Right now I have a format with <message> inside of it. I Use Minimessage and TagResolver with Placeholder.component() to replace the <message> in the format, this way if there is untrusted input, it won't get deserialized by MiniMessage.

What safety tips should I take care of for serialization before sending and deserialization when servers receive it? To avoid the untrusted input being parsed.

Should I use JsonComponentSerializer or Minimessage?

cloud vapor
#

That's basically it, if you just insert content as components or unparsed strings MiniMessage won't even look at the contents

#

For serialising components over the wire, you should use the JSON serializer as the MiniMessage one is slightly lossy when it comes to certain object components and click events

hardy estuary
#

Thank you, so from my understanding its safe to trust the incoming serialized input and deserialize it. All with Json serializer. Right?

sweet hornet
#

The user has no impact on the JSON encoding of the component, they only control the encoded content

#

It would be an issue with the JSON serializer otherwise

hardy estuary
#

No im not talking about user

sweet hornet
#

What safety are you talking about then?

hardy estuary
#

incoming = serialized input coming from server A to listening server

#

so when it arrives, the procedures described before arriving to the final Component have already taken place

sweet hornet
#

I mean, if your communication channel is secure, yeah

hardy estuary
#

and is JsonComponentSerializer resilient against possible breaks? if users finds a way by typing "{ }" to break the JSON

hardy estuary
#

Thanks guys

dawn pewter
#

i have got a custom mm instance with a bunch of custom styling tags and want to add a tag that adds a pipe "|" in a specific color.
ideally this would be ⁨<pipe:green>⁩ for example would result in ⁨<green>|</green>⁩. But i also have custom colors e.g. ⁨<pipe:customcolor>⁩ is there a way how i can achive this?
I am as far as defining a custom tag with an argument queue but how would convert that color string that can have a custom color to a TextColor?

robust wharf
#

Check if it's a text color, if so use that, else use you own parsing

#

Or first check your map of custom colors and then the named text colors

#

And if you need to handle hex, check for that too

dawn pewter
#

dang

boreal orchid
#

There’s a PR open for custom named colors but I doubt it is gonna get merged

sterile rampart
#

why do you doubt that?

dawn pewter
#

Probably because it waits 4 months to get merged

cloud vapor
#

4 months = forever ok yes taking notes

tulip wedge
#

can i somehow cache TagResolvers?

#

i just gave a quick look bc im about to go out but couldnt see

#

so I'd have a tag resolver that resolves "player" and I'd feed it with content whenever i need it, without creating a new object

prisma mason
#

cache as in what?
Have a tagresolver that takes a Player argument and uses the <player> tag or make a tagResolver that is used everywhere without duplicating it?

#

@tulip wedge

cloud vapor
#

You can store a TagResolver whole or you could make a TagResolver that caches the content it returns

cosmic loom
#

Is there a way to use choice tags with a minimessage translator?

#

ah I see, ⁨Argument.tagResolver(Formatter.choice(...))

hexed field
#

I am attempting to make a sprite from the items atlas but it is not displaying correctly. Any thoughts on what I am doing wrong?
<sprite:"minecraft:items":partyrealms:item/emerald_necklace>
I can see the texture in the minecraft_textures_atlas_items (minecraft:items) atlas:
partyrealms:item/emerald_necklace x=714 y=346 w=16 h=16

#

I can generate a sprite from a minecraft texture using the following and it renders correctly
<sprite:"minecraft:items":item/wooden_sword>

sand drift
#

forgot to quote the right side of that?

#

Given the : in there

hexed field
#

yup that fixed it. thanks cat!

tulip wedge
#

Basically Placeholder#parsed(key, value) without the value in creation time

#

so i wouldnt create a tag resolver instance every time i need

#

currently its like this, run on every GUI open and it shows up a lot in profiler

#

i dont think caching the placeholders wouldn't do a lot in this case but better than nothing

#

the gui has a lot of items in it with long lores so its kinda heavy

frigid plaza
#

Heyo!

I am having issues with Adventure's translation capabilities. When I try to translate text, it fails to fill in placeholders from the translations.
⁨```java
ComponentSerializer serializer = PlainTextComponentSerializer.plainText();

TranslationStore translations = TranslationStore.messageFormat(Key.key("test", "test"));
translations.register(
"multiplayer.player.joined",
Locale.US,
new MessageFormat("%s joined the game!", Locale.US)
);
GlobalTranslator.translator().addSource(translations);

Component untranslated = Component.translatable("multiplayer.player.joined")
.arguments(Component.text("Username"));
System.out.printf("Untranslated: %s%n", untranslated);
System.out.printf("Untranslated (Serialized): %s%n", serializer.serialize(untranslated));

Component translated = GlobalTranslator.render(untranslated, Locale.US);
System.out.printf("Translated: %s%n", translated);
System.out.printf("Translated (Serialized): %s%n", serializer.serialize(translated));


This snippet outputs:
⁨```
Untranslated: multiplayer.player.joined
Translated: %s joined the game!
```⁩

Whereas my expected output would be:
⁨```
Untranslated: multiplayer.player.joined
Translated: Username joined the game!
```⁩

Is there anything that I am missing to achieve my desired output?

Thank you! <3
cloud vapor
#

Message format is {n} for placeholders, where n is the index of the argument

cloud vapor
#

Spark screenshots are useless so I can't help you unfortunately

frigid plaza
rare sage
#

that is the translation format for resource pack translations

#

oh dear that was a while ago

#

oh yeah that example is wrong

boreal orchid
#

I don't think it is a matter of the placeholder creation though, if anything ends up being "expensive" there it'd be the underlying TagResolver#resolve calls

#

I'd try and do a binary search as to what placeholder resolution is the worst performing, and work with that

wet kestrel
#

0.15% of a tick is 75 μs

tulip wedge
#

I'll send the report when im on pc again

native ledge
#

how does one make/use an audience?

boreal orchid
#

if it is in Paper, all entities implement Audience

native ledge
#

oh so calling things like ⁨sendActionBar⁩ on players would call the audience method instead of the deprecated player method?

boreal orchid
#

same for any of the other deprecated methods

native ledge
#

would I need to pass in an Audience as a parameter or can I just use a Player (or list of Players)?

boreal orchid
#

you can just use Player

native ledge
#

ok thank you very much!

bright remnantBOT
digital goblet
#

Hello how can I get a component from nbt?

raven crag
#

Do you have a String or a CompoundTag?

digital goblet
#

CompoundTag

raven crag
#

I might have missed something, but searching around I'm not seeing an easy way. If you could convert your CompoundTag into a JSON string (like what you can use in /tellraw) then it'd be a simple case of using GsonComponentSerializer.

sweet hornet
#

First, why are you trying to do that? Then, do you really need it?

digital goblet
#

i mean ya I need it I need to load the default item components

sweet hornet
#

What component are you talking about? Can you give more context, and maybe an example plz?

digital goblet
#

DataComponents in ItemStack

#

like maxstacksize etc

#

minecraft

#

so for example inventory module knows how to stack items

#

its fine ill just code my own then

sweet hornet
#

But that's no related to adventure then?

#

I think you missunderstood "item data components" and "text (and other) components"

digital goblet
#

it is bc im using adventure?

#

Im using adventure nbt and stuff

#

its just trying to read a text component form a CompoundTag

#

theres a data component called item_name it needs a text component

sweet hornet
#

Ok, first why are you in this situation, then which platform are you using? Paper?

digital goblet
#

none custom

#

my own server

#

but im using advanture as a lib
for nbt and text components audience etc

sweet hornet
#

If you have no platform, what would you expect to transform your NBT data into?

digital goblet
#

net.kyori.adventure.nbt.CompoundBinaryTag -> net.kyori.adventure.text.Component

sweet hornet
#

So you're only talking about the custom_name item data component value (and similar, lore...)?

digital goblet
#

my problem happens with parsing those yes

sweet hornet
#

Ok I get it know. Then you'd want a component serializer for NBT, which I think I've already heard of, but I can't remember where for now. It might be in a platform implementation, I'll have a quick look

digital goblet
#

ok thanks

sweet hornet
#

I can't find it anymore sorry

restive spruce
#

<@&748618676189528155>

bright remnantBOT
strange drift
quick urchin
#

too slow

supple copper
#

in the latest papi version

tardy mirage
hardy estuary
#
MiniMessage serializer = MiniMessage.builder()
  .tags(TagResolver.empty()
  )
  .build();

Is this the correct way to create a MiniMessage serializer who doesn't resolve any known tag? Like all default tags (<color><hover> ... etc)

cloud vapor
#

That would effectively be a plain text serializer yes

cloud vapor
#

Uh no

rare sage
#

that is different from what they shared above

cloud vapor
#

That would resolve every standard tag, they want a serializer that doesn't resolve any tags

#

so kinda the opposite :p

tardy mirage
#

Oh

#

My bad

#

PlainTextSerializer?

cloud vapor
#

basically yeah

hardy estuary
wicked torrent
#

does anyone have some code handy to turn the vanilla Language instance into a Translator? working on something a little cursed

cloud vapor
wicked torrent
#

basically in the ghostty window is a little java app that connects to a server over a socket and gives you a full-featured console

#

I use json to send component logs over the socket, so that I can use the ANSI serializer client-side with the client app's terminfo

#

but I need to render vanilla/mod translations from Language on the server side

cloud vapor
#

ok so i'd instead make an AbstractComponentRenderer

#

and then copy that code from the paper flattener into that

wicked torrent
#

looking in vanilla code their equivalent for client rendering also works kind of like the flattener where it linearizes the message

cloud vapor
#

the flattener is good for component -> string but if you want component -> component then the renderer is good

#

basically you're just turning vanilla translatable components into normal text components then sending the whole thing over the wire and letting the client app flatten it with the ansi serializer right

wicked torrent
#

yeah exactly

#

gonna try again with adapting the flattener logic for my renderer

#

wondering if I could get away with something even dumber like just try to resolve the key and put the result in the translatable fallback field

#

with mapComponentDeep or whatever

#

now I also need to hook into the ComponentLogger PepeLa

wicked torrent
#

ran into a small problem with that

#

pretty sure it could be added as a simple callback in #log of the wrapping logger

#

I could copy out the class but would need to do it for all supported platforms, at which point I think an upstream hook makes sense

sterile rampart
#

ya i think that sort of hook could be reasonable

wicked torrent
#

the main annoying thing for paper was getting this log pattern to go over the network

#

*socket

wicked torrent
#

so I will put ComponentLogger compat on hold for now

sterile rampart
#

I guess you could send ANSI over the socket and just conditionally strip or downsample in the client? maybe?

wicked torrent
#

definitely an option, would probably remove the need for the renderer as well

nova igloo
#

Hi! I recently discovered the Options in Adventure, but they seem to be immutable, yet the name makes me think they shouldn't be. Is this normal?

cloud vapor
#

yes

nova igloo
#

So, how would it be interesting to use them?

cloud vapor
#

if you don't have a specific use case for them then they aren't useful

#

they solve a specific purpose of having effectively a schema of options

granite spindle
#

what's the instance where typecasting Component to TextComponent is unsafe?

cloud vapor
#

where component is anything other than a TextComponent

#

casting to TextComponent generally smells like you're doing something unsafe

granite spindle
#

actually yeah i was just wondering, didn't see other types of components

#

is it possible to apply tag resolvers on top of a pre-existing component?

#

do i have to turn it into plain text then deserialize?

boreal orchid
#

that being said, what is your goal with this?

#

I assume it is something to do with chat, that's when people usually find themselves doing what you want to do

granite spindle
boreal orchid
#

because if it comes from a config or something, you could just do the clickable part on MM too, like <click:run_command:whatever>My clickable text</click>

granite spindle
#

i see, that could definitely be a better alternative

#

this should be fine right?

#

<kit> being replaced by a tag resolver

boreal orchid
#

I believe it should, you might have to quote the argument though

#

&a eyesSquint

granite spindle
#

but i didn't set this up, im just contributing

boreal orchid
granite spindle
#

yeah the code converts legacy to minimessage for people who prefer it

boreal orchid
#

it also doesn't represent much by itself, usually what I do when it comes to localization is provide configurable tags like <bg>, <fg>, <accent>

#

that way you give users freedom to define a design system

granite spindle
#

that does sound like a cool concept

#

thanks for helping me with this

granite spindle
#

what would be the best way to do something like this:
have a lore - <members> then when we get the lore, this same line is duplicated for each member so it turns into something like

- member1
- member2

would I have to make my own placeholder system to accommodate this? or is there an easier way while maintaining customizability through configs

#

there would be other lore above and below it

boreal orchid
#

it comes down to component splitting which ends up being more involved than one would think

#

one thing I did at a point was just using Pkl for the configuration instead, which allowed me to do things like:

lore = [
  "Members:",
  for (m in members) { "- <red>\(m)" }
]
granite spindle
#

do color tags inside hover tags not work? it just displays hover tags with color as-is

#

when i remove the color tag, hover works fine

#

- '&bYou have been invited to &f<leader>''s &bparty <hover:show_text:<green>Click to join party</green>><click:run_command:/party join <leader>>(ACCEPT)</click></hover>'

cosmic loom
#

it would probably have to be in single quotes but why are you using legacy colour codes

wet kestrel
#

Yeah, the legacy code bit is a sign something is wrong here.

obtuse ruin
granite spindle
#

and yeah it's in single quotes that's it i guess

boreal orchid
#

And splitting on new lines leads to style splitting issues

granite spindle
#

i got the hover to work now that i have added the single quotes, but why doesn't click work?

#

okay nvm i forgot i didn't add the /

#

nope still the same

#

ok im a little slow i had to add the single quotes to click too

#

didn't see it on the docs

cosmic loom
granite spindle
cinder pike
#

I'm trying to figure out how to add custom placeholder replacement using TagResolvers, but not all messages in the plugin have 1 tag, some have 2. If I put 2 in formatText, it has to be 2, but I can't figure out how to make them dynamic.

https://pastes.dev/YdyBXTVxKt

boreal orchid
#

you don't have to build the MM instance every time, you can just pass the tag resolver(s) as param of the deserialize method

cinder pike
boreal orchid
# cinder pike So I remove the Builder part, right?
private static final MiniMessage MINI_MESSAGE = miniMessage = MiniMessage.builder()
                .tags(TagResolver.builder()
                        .resolver(StandardTags.color())
                        .resolver(StandardTags.decorations())
                        .build()
                )
                .build(); 

public static Component formatText(String message, @NotNull TagResolver... placeholders) {         
  return MINI_MESSAGE.deserialize(message, placeholders);
}

would recommend something like this. That way you can do:

formatText("<idk>hi <name>", Placeholder.component("idk", ...), Placeholder.parsed("name", ...));
cinder pike
# boreal orchid ```java private static final MiniMessage MINI_MESSAGE = miniMessage = MiniMessag...

I did that, and it works, meaning that it lets you put in more placeholders, but I didn't understand the part about Placeholder.component being parsed. What's the difference between the two?

    private static final @NotNull MiniMessage miniMessage;
    private static final MiniMessage MINI_MESSAGE = miniMessage = MiniMessage.builder()
            .tags(TagResolver.builder()
                    .resolver(StandardTags.color())
                    .resolver(StandardTags.decorations())
                    .build()
            )
            .build();

    public static Component formatText(String message, @NotNull TagResolver placeholders) {
        return MINI_MESSAGE.deserialize(message, placeholders);
    }
}
        if (mainConfigManager.getServerInfoMessageEnabled()) {
            player.sendMessage(MessagesUtils.formatText(mainConfigManager.getServerInfoMessage(),
                            Placeholder.component("prefix", mainConfigManager.getPluginPrefix()),
                            Placeholder.parsed("server_version", serverVersion)
            )
            );
        }
boreal orchid
#

but in short, Placeholder#component lets you insert a Component directly into the string as a placeholder, and Placeholder#parsed lets you parse a MiniMessage String into it

cinder pike
boreal orchid
#

Usage examples if that makes it any more clearer:

// player.displayName() -> Component
player.sendMessage(formatText("Hey! <name>", Placeholder.component("name", player.displayName())));
// lets assume serverVersion is "<red>1.2.3"
// these two are technically equivalent, however it is probably preferable that you insert things via a TagResolver instead of just appending it to the format string
player.sendMessage(formatText("Your version is: " + serverVersion));
player.sendMessage(formatText("Your version is: <version>", Placeholder.parsed("version", serverVersion));
boreal orchid
#

if you're making configurable messages, I would recommend using Adventure's internationalization features

cinder pike
boreal orchid
cinder pike
cinder pike
cinder pike
#

Strangely, this gives me an error because I have one below the other.

        if (mainConfigManager.getServerInfoMessageEnabled()) {
            player.sendMessage(MessagesUtils.formatText(mainConfigManager.getServerInfoMessage(),
                            Placeholder.parsed("prefix", mainConfigManager.getPluginPrefix()),
                            Placeholder.parsed("server_version", serverVersion),
                            Placeholder.parsed("version", versionPlugin),
                            Placeholder.parsed("server_api_version", serverApiVersion),
                            Placeholder.component("displayname", displayName)));
        }
wet kestrel
wet kestrel
# cinder pike

Ah, look at the difference between what javier kindly spoonfed you and what you have for the parameters of that method

cinder pike
#

In this way, he intended to insert them using a TagResolver. I'm not sure if I understand correctly.

    public static Component formatText(String message, @NotNull TagResolver placeholders, 
                                       TagResolver.@NotNull Single serverVersion, 
                                       TagResolver.@NotNull Single version, 
                                       TagResolver.@NotNull Single serverApiVersion, 
                                       TagResolver.@NotNull Single displayName) {
        return MINI_MESSAGE.deserialize(message, placeholders);
    }
sour quarry
cinder pike
sour quarry
#

I'm not sure what you mean by that?

cinder pike
# sour quarry I'm not sure what you mean by that?

In the file above that Javier sent

// lets assume serverVersion is "<red>1.2.3"
// these two are technically equivalent, however it is probably preferable that you insert things via a TagResolver instead of just appending it to the format string

sour quarry
#

If you're fine not having the message format being configurable then yeah that works, but building a MM string by appending is way more difficult to modify down the line, and essentially impossible to make user-configurable in any sane way - that's why they (and I for that matter) strongly recommend using proper placeholders instead

cinder pike
cinder pike
# wet kestrel You're missing the varargs...

I did that, I don't know if I understood correctly, but the advice was to have it directly in coins without having to do that huge block every time formatText was used:

public class MessagesUtils {

    private static final @NotNull MiniMessage miniMessage;

    private static final String prefix = ExamplePluginAPI.getMainConfigManager().getPluginPrefix();
    private static Player player;
    private static final Component displayName = player.displayName();
    private static final String serverVersion = ExamplePluginAPI.getServerVersion();
    private static final String versionPlugin = ExamplePluginAPI.getVersionPlugin();
    private static final String serverApiVersion = ExamplePluginAPI.getServerApiVersion();

    private static final MiniMessage MINI_MESSAGE = miniMessage = MiniMessage.builder()
            .tags(TagResolver.builder()
                    .resolver(StandardTags.color())
                    .resolver(StandardTags.decorations())
                    .resolver(Placeholder.parsed("prefix", prefix))
                    .resolver(Placeholder.parsed("server_version", serverVersion))
                    .resolver(Placeholder.parsed("version", versionPlugin))
                    .resolver(Placeholder.parsed("server_api_version", serverApiVersion))
                    .resolver(Placeholder.component("display_name", displayName))
                    .build()
            )
            .build();

    public static Component formatText(String message) {
        return MINI_MESSAGE.deserialize(message);
    }
}
wet kestrel
#

Every time you paste something you are moving further and further away from the solution, and I'm starting to doubt you understand java fundamental or how to google considering your responses to my remarks.

cinder pike
wet kestrel
#

You should really check out some java resources

upper tinselBOT
#

To create plugins, learning Java beforehand is like learning how to write before creating a novel - it's an essential part of the process.

There is no shortcut to learning programming, just as there is no single, definitive way to approach it. Everyone learns differently. One of the best ways to learn is by doing and actively applying what you're learning as you go.

Learning Resources:

cinder pike
# wet kestrel You should really check out some java resources

I appreciate the resources, but I find the constant doubt about my abilities a bit unnecessary. I am well aware that I still have things to learn, like all of us, but errors in logic or implementation are not a sign of “lack of knowledge of Java”; they are just part of the development process. I would appreciate feedback that is a bit more constructive and less critical.

eager otter
#

Can I apply value or texture to <head>?

stark badger
eager otter
stark badger
#

you can use minimessage

#

but the tellraw command doesnt support it

boreal orchid
#

you can however add a tag that does it

eager otter
boreal orchid
# eager otter Can you get example 🙏
private static final Pattern TEXTURE_URL_PATTERN = Pattern.compile("^https?://textures\\.minecraft\\.net/texture/[0-9a-f]+$");

public static TagResolver headTextureTag() {
  return TagResolver.resolver("head_texture", (args, context) -> {
      var textureUrl = args.popOr("Expected texture url").lowerValue().strip();
      if (!TEXTURE_URL_PATTERN.matcher(textureUrl).matches()) {
        throw context.newException("Expected a valid minecraft texture URL", args);
      }
      var json = "{\"SKIN\":{\"url\":\"%s\"}}".formatted(textureUrl);
      var texture = Base64.getEncoder().encodeToString(json.getBytes(StandardCharsets.UTF_8));
      var contents = ObjectContents.playerHead()
                              .profileProperty(
                                PlayerHeadObjectContents.property("textures", texture)
                              )
                              .build();
    return Tag.selfClosingInserting(ObjectComponent.contents(contents));
});
#

you'd use it like this:

var message = "<head_texture:'http://textures.minecraft.net/texture/9d6bdd07abe3f398720e5f010648c2c194a2ba0f5ef3e27013b0670336eb4f3c'> Hey!";
player.sendRichMessage(message, SomeUtilClass.headTextureTag());
crystal quarry
#

Is there a JS/TS library for visualization? I'm building a plugin that heavily uses minimessage in its messaging and has a web editor for a lot of the configs

robust wharf
#

No, we didn't want to reimplement the parser and have a single source of truth

#

Our web editor just calls back to a backend that uses minimessage

crystal quarry
#

gotcha

robust wharf
#

(you may use those endpoints too)

sterile rampart
#

wonder how realistic it'd be to do something with say teavm or j2cl

boreal orchid
crystal quarry
boreal orchid
crystal quarry
#

are they public?

#

i.e docs or wiki or something

crystal quarry
boreal orchid
#

they have examples on how to interface with it on their github, so you can probably just use that

robust wharf
#

The API for MiniMessage to html is just websocket now :/

cloud vapor
#

I'm not against adding a plain ol' api endpoint

#

i should probably add some proper open api docs as well at some point

sweet hornet
#

I think that would greatly help yeah, not that it's particularily complicated, but at least it would serve as a great "hub of information" on the topic of web integration of MiniMessage

#

Maybe a JS package (or maybe a simple one file script since it's obvious) to demonstrate basic usage could as well be useful I think

cloud vapor
#

oh no we do have /api/mini-to-html

#

@crystal quarry ^

#

no i lied we dont it is websocket only

#

ill fix that

robust wharf
#

This I like the 3rd time I had that exact chain of thought kezz, lol

#

Just never got around to it

cloud vapor
#

ktor's openapi stuff is actually quite nice

cloud vapor
#

very nice, cant decide between redoc or swagger

sweet hornet
#

Personnaly I prefer swagger, but I guess it makes no real difference, it's really a matter of taste. As long as the OpenAPI file is accessible, it can be viewed in any client, right?

cloud vapor
#

yeah

#

could actually do both lmao

sweet hornet
#

That's what I was about to suggest x)

#

Does it represent a big maintenance cost for you?

cloud vapor
#

it's four loc and a single dep

sweet hornet
#

Swagger has a built-in "try it" button to execute requests and better understand the actual response, which redoc seems to not have

#

But redoc seems more oriented toward style customization if you want it to be highly integrated with the remaining of the documentation, as opposed to Swagger which is a pain to customize (I tried, long ago...)

cloud vapor
#

yeah ktor also only gives you the option of a single css file

#

for swagger customisation, no plugins or anything, which kinda sucks

#

like we couldn't even hide the explore top bar

#

which is fine but w/e

plush ginkgo
#

how do i use the PreProcess interface for adding a tag ? im trying to make a tag <smallcap> that will turn all text to a small cap unicode character

#

i tried the modifying tag but it didnt help, it added the text after the original text

#

Output: Configurations reloaded successfully!ᴄᴏɴꜰɪɢᴜʀᴀᴛɪᴏɴs ʀᴇʟᴏᴀᴅᴇᴅ sᴜᴄᴄᴇssꜰᴜʟʟʏ!

message before minimessage parse: <green><smallcaps>Configurations reloaded successfully!

cloud vapor
#

Modifying is correct, just be careful about the children

plush ginkgo
sweet hornet
#

Clear the children before returning the "modified" component

plush ginkgo
#

oh ok, let me try it

mellow veldt
#

What does this code appear as in 1.21.8: player.openWorkbench(null, true);

sterile star
cloud vapor
#

I feel like you're in the wrong channel, Adventure doesn't have an openWorkbench method - did you mean #paper-dev ?

granite spindle
#

"<aqua>You have been invited to <white><leader></white>'s party <hover:show_text:'Click to join party'><click:run_command:'/party join <leader>'><green>(ACCEPT)</click></hover>"

Using MiniMessage Placeholder. The first <leader> gets replaced with the correct name, but when I click the (ACCEPT) text, it sends /party join <leader> without replacing the placeholder.

boreal orchid
#

otherwise the tag resolver in question has to manually parse the respective arguments with the given context

wet kestrel
#

Presumably this click is something relevant to that line, I'd just do <click_join> or whatever as a custom tagresolver

granite spindle
#

ah it would be great if i just use tagresolver with arguments

#

colors would get parsed inside arguments in that case right

#

ok probably not

boreal orchid
#

you could technically deserialize it into a Component then serialize it into a String with the plain text serializer but that'd also strip color tags probably, which I doubt you'd want

granite spindle
#

should i do just a simple string replacement then?

boreal orchid
wet kestrel
#

custom tag resolver is much more user-friendly on readability

granite spindle
#

I had the wrong idea about custom tags lol, anyways, what do we do about hover then? make a different config entry just for hover text? If users ever need to use the placeholder inside hover

#

Some people might not even want hover

granite spindle
#

is there an in-built way to make placeholders render differently for each person? for example a relative-color placeholder where one message is broadcasted, and all team members see their own members' names as blue while enemies are displayed as red

#

or is it better to just send it for each player

sour totem
#

when deserializing with minimessage you have the option to provide a target (which would be done for each player), then in your TagResolver you can obtain that target from the context

cloud vapor
mint path
#

Is it possible to have localizable text as part of an itemstack's lore? And how would word wrapping work like that? We localize most of our text these days but not our custom items

cloud vapor
#

Assuming you are doing word wrapping yourself somehow as that's not part of Adventure, only you can answer that

#

But yeah nothing stopping you from localizing lore

sour totem
granite spindle
#
public void sendDeathMessage(Participant deadParticipant) {
    String deathMessage = deadParticipant.getDeathMessage();
    DeathCause deathCause = deadParticipant.getDeathCause();
    TagResolver.Builder resolver = TagResolver.builder()
            .resolver(TagResolver.resolver("player", getColoredNameResolver(deadParticipant)));
    if (deadParticipant.getLastAttacker() != null) resolver = resolver.resolver(TagResolver.resolver("killer", getColoredNameResolver(deadParticipant.getLastAttacker())));
    if (deathMessage.isEmpty() && deathCause != null) {
        broadcast(deadParticipant.getDeathCause().getMessage(), resolver.build());
    } else {
        broadcast(deathMessage, resolver.build());
    }
}

Implementation of getColoredNameResolver in a solo match:

public BiFunction<ArgumentQueue, Context, Tag> getColoredNameResolver(Participant participant) {
    return (ArgumentQueue args, Context context) -> {
        Player receiver = context.targetAsType(Player.class);
        Participant receiverParticipant = participant.getProfile().getMatch().getParticipant(receiver);
        MessagesLocale message;
        if (receiverParticipant == null) message = MessagesLocale.MATCH_SPECTATOR_TEAM_NAME;
        else if (participant == receiverParticipant) message = MessagesLocale.MATCH_OWN_TEAM_NAME;
        else message = MessagesLocale.MATCH_OPPONENT_TEAM_NAME;
        Neptune.get().getLogger().info("receiver: " + receiver.getName() + ", target:" + participant.getName() + ", message: " + message.getPath());
        return Tag.inserting(CC.returnMessage(receiver,
                message.getString(),
                Placeholder.unparsed("name", participant.getName())));
    };
}

I have a feeling I'm severely overcomplicating something here?

#

The final output:
Winner: winner was killed by loser (both names are in red)
Loser: loser was killed by loser (first name is in red, second is in green)

#

actually the final output seems to vary randomly, but one person sees both (killed & killer) names as their own name, the other gets both names correctly

cloud vapor
#

or they might not be using paper

cloud vapor
#

can you share some more code?

boreal orchid
granite spindle
cloud vapor
#

i still can't see where you set the target there

granite spindle
#

huh

#

i could've sworn-

boreal orchid
#

you need to set the target when sending the message/deserializing, that's what the deserialize overload that takes a Pointered is for

granite spindle
#

seems the code is outdated? what the hell, intellij shows it's up to date

#

oh wait

#

i linked to master

#

u might see some horrendous code 🙏

#
[14:00:07 INFO]: [Neptune] receiver: mallusrgreat, target:mallusrgreat, message: MATCH.TEAM_MEMBER_NAME.OWN
[14:00:07 INFO]: [Neptune] receiver: mallusrgreat, target:mallusrgreat, message: MATCH.TEAM_MEMBER_NAME.OWN
[14:00:07 INFO]: [Neptune] receiver: AspectPlayzX, target:mallusrgreat, message: MATCH.TEAM_MEMBER_NAME.OPPONENT
[14:00:07 INFO]: [Neptune] receiver: AspectPlayzX, target:mallusrgreat, message: MATCH.TEAM_MEMBER_NAME.OPPONENT

the target works fine
Neptune.get().getLogger().info("receiver: " + receiver.getName() + ", target:" + participant.getName() + ", message: " + message.getPath());

cloud vapor
#

then yeah that'll work fine

#

what specifically is the issue? your debugging should point you to any errors

granite spindle
#

for one person it says:
player1 won
player1 was killed by player1 (incorrect order, both are red)
player1 was killed by player2 (correct order, first is red, second is green)

#

this may not be adventure related...

cloud vapor
#

If the target is getting sent over correctly it's probably an issue in your logic somewhere

granite spindle
#

i understand that but the message was working correctly before I moved to this, this has gotta be a gotcha with adventure or something
i've carefully reviewed the logic and added a check which logs if the killed and the killer are the same, and it doesn't log, so it shouldn't say the same name

cloud vapor
#

There's no gotcha here, MiniMessage will only do what you tell it to

calm basalt
#
String input = "Roman Number <roman:3>";
Component component = MiniMessage.miniMessage().deserialize(input);
String reverse = MiniMessage.miniMessage().serialize(component);
System.out.println(input + " -> " + reverse);

Outputs
[11:31:18 INFO]: [STDOUT] Roman Number <roman:3> -> Roman Number \<roman:3>

Can it be disabled that it adds the \ before unkown tags?

cloud vapor
#

No, it's an intentional feature of the serializer to allow for round-trip serialization

tulip wedge
#
        ItemConfig itemConfig = menu.getProduct();

        TagResolver[] placeholders = new TagResolver[] {
                Placeholder.component("display_name", product.getItemStack().displayName()),
                Placeholder.parsed("price", String.valueOf(product.getSellingPrice())),
        };

        GuiItem item = ItemUtils.createItemBuilder(itemConfig, product.getItemStack().getType(), placeholders).asGuiItem();//.asGuiItem(e -> handleProductClick(player, product, e));
        gui.addItem(item);
    }```the display name component somehow gets [] to its start and end
cloud vapor
#

That's just what displayName does

#

You can look at the other name methods on ItemStack - but that's a #paper-dev question anyway

tulip wedge
#

right

#

sorry

cloud vapor
#

nw!

robust wharf
trim aspen
#

I ran into a problem with my tag resolver, where my custom tag which looked something like <%30> wasn't working, presumably because of percent sign, bcs <tint30> was working correctly. (yeah ik you should use arguments, like tint:30). is there a reason why percent sign doesn't work?

trim aspen
#

so should I use something like [%]?

sweet hornet
#

TL;DR: Tag names can only match this: [!?#]?[a-z0-9_-]*

trim aspen
#

oh, ok

boreal orchid
#

I'd advise using a proper tag instead of whatever you're doing right now

sweet hornet
#

Which means optionally ! ,? or #, followed by any sequence of alphanumeric (and - / _) characters

trim aspen
#

yeah, I understand that

trim aspen
wet kestrel
#

Time to go back

boreal orchid
cloud topaz
sour totem
cloud topaz
#

Oh I need to update my bookmark then

gentle pulsar
#

hey, which version of mc did bring objects inside components (player heads etc.)?

sweet hornet
#

1.21.9 iirc

trim aspen
#

is there any way to force children in a component to use certain formats from tags? some stuff can be done with Style, but not every tag has a Style representation. for example, gradients. Imagine I have a TextComponent and I would like to apply x tags on it. I would need to deserialize that component, wrap it with tags and then serialize it. But bcs of the order the tags are resolved something like <gradient...><red>hi</red></gradient...> would produce red "hi" component, so basically, instead of applying style if absent I would like to apply style overriding the initial one while using tags

sweet hornet
#

If you want to overwrite the style, consider discarding it first

#

Does that make sense for you or do you want me to elaborate?

boreal orchid
#

if you don't want red, then don't add the red tag to the input

trim aspen
# sweet hornet If you want to overwrite the style, consider discarding it first

well, incase of gradients, I would only want to discard the TextColor in Style, but it's impossible to tell which tag uses what kind of TextFormat, which I completely understand. But there's presumably no equivalent to forcing a style on a future component and its children with tags in minimessage, even though you can do this with adventure components

trim aspen
sweet hornet
#

If you have the component, you can basically iterate over it and each child to unset its text color, then serialize it

trim aspen
#

If I wanted to just make every inventory name green, I would just apply a TextColor to that inventory name, can't do that with gradients

trim aspen
#

since adventure components have exactly that, so there should be something like Tag#styleOverriding or whatever in minimessage. yeah that's another thing but related to the issue

rare sage
boreal orchid
#

something like <gradient_type:lunar> then have a config like:

gradients:
  lunar:
    - 0xc390d4
    - 0xc3904d
cloud vapor
dawn wharf
#

Hello ñ.ñ,

I recently started using the <head:%player_uuid%> format in a plugin called CustomFishing to display the player's head on generated items. However, this causes an error for Bedrock players.
I reported it to the CustomFishing developer, and they mentioned the issue originates from Mojang’s side, specifically how certain UUIDs are processed. I encountered the same problem in one of my own plugins and resolved it by avoiding direct processing of those UUIDs.
In my case, I detect Bedrock players (for example, UUIDs starting with 00000000-0000-0000, which are commonly generated by Geyser/Floodgate) and switch the head resolution strategy accordingly:

private boolean isBedrockPlayer(UUID uuid) {
    String uuidStr = uuid.toString();
    return uuidStr.startsWith("00000000-0000-0000");
}

String headTag = isBedrockPlayer(entry.getUuid())
        ? "<head:" + entry.getName() + ">"
        : "<head:" + entry.getUuid().toString() + ">";

This way:

  • Java players → <head:player_uuid>
  • Bedrock players → <head:player_name>

By doing this, I prevent Adventure (or the head resolver) from attempting to resolve synthetic UUIDs that are not recognized by Mojang’s services, which avoids the exception.
Would it be possible to implement a similar fallback mechanism directly in Adventure so these UUID edge cases are handled more gracefully at the root level?

Thank you.

mental vineBOT
sand drift
#

Adventure cares about serialisation aspects, the server resolving stuff with that data afterwards is 100% irrelevant to adventure

#

(MM has 0 context of platforms, or platform oddities, etc)

cloud vapor
#

I'm failing to see how that error you provided is a Paper issue

#

I'm not against adding functionality to safely handle any serialization errors or problems encountered but I don't really know what you're asking us to do here

sand drift
#

it sounded like they're expecting some form of logic somewhere to see that the UUID is technically invalid and try to resolve a player name or something to try to use that for the profile data in the serialised player head object

cloud vapor
#

The UUID isn't invalid, they are just not creating a valid component

#

{"hat":true,"player":"00000000-0000-0000-0009-01f576ef9696"} isn't a valid component, you specifically need "object":"player" otherwise it defaults to an atlas object type

#

I mean yeah it's an invalid UUID bc there is no version 0 - geyser or whoever should be using version 8 which is specifically for custom UUIDs

dense veldt
#

If I remember this correctly from when I implemented serialization for those (and assuming nothing changed since then) you don't need to specifically specify "object": "player". The issue is that the "short" form of {"player":"..."} only works with player names, if you want to use a uuid you have to put it inside a partial profile, e.g. {"player":{"id":...}}

cloud vapor
#

oh yeah that too - strings are only for names yep

dense veldt
cloud vapor
#

we could probably just move that to parse the UUID

#

that would fix what i assume they're also asking for, which is for it to not error like that

#

feel free to open an issue, or even better a PR @dawn wharf

worthy adder
#

Hey. I am trying to register a custom TagResolver to translate a string based on the player's language in my pluign, to use it in a FancyHolograms holo. Is there a way to do this?

cloud vapor
#

you mean like the lang tag?

mental vineBOT
boreal orchid
#

for reference

sterile star
#

Hey, I am doing cursed stuff! The cursed stuff consists of a way to execute commands on my server from my Discord server via a Discord bot command. For that to work smoothly, I added a way to obtain the command output and want to print that back to the user. For this, I have a List<Component> output, which contains the command output. I now want to serialize these components into ansi strings, so that I can print them back to the user with an ansi code block (to retain a minimal level of color formatting). Here is my current code for the ansi serialization: ```java
final String ansiOutput = String.join("\n", output.stream()
.map(line -> GlobalTranslator.render(line, Locale.getDefault()))
.map(line -> ANSIComponentSerializer.builder()
.colorLevel(ColorLevel.INDEXED_8)
.build()
.serialize(line))
.toList());

Whilst this makes quick work of styled text components, I am having issues with translatable components. As you might see, I am rendering the components through the global translator, however at the end this simply result in the translatable component's key being printed (for example: `commands.ban.failed`).

I took inspiration from Paper's `ComponentLoggerProviderImpl`, which also converts and translates components for display in the console, meaning it should work in a similar way, however it doesn't seem to do anything differently from what I am doing. For this reason I wanted to request help on what might be the issue.
cloud vapor
#

assuming you're talking paper, the global translator doesn't contain vanilla translations (assuming that's commands.ban.failed?)

wicked torrent
#

that GlobalTranslator call in the provider is actually redundant anyways

#

the Paper flattener handles Language and GlobalTranslator

cloud vapor
#

yeah you can grab paper's flattener from PaperAdventure or something like that

sterile star
#

Aha, that would probably be it. Can I somehow get the Paper flattener from API or do I need to access the PaperAdventure class for that?

cloud vapor
#

and then just set that flattener in the ansi serializer builder

wicked torrent
#

the ansi provider should be adding the flattener by default

cloud vapor
#

yeaah it should be using whatever the platforms' plain text serializer right

sterile star
#

If that's what it should do, then I am concerned that it doesn't

cloud vapor
#

no it doesn't, it just uses the basic flattener

sterile star
#

Okay fair, guess I am gonna grab it from PaperAdventure

cloud vapor
#

it's also in api in PaperComponents

wicked torrent
#

oh it seems like the provider is not implemented

#

why does my code work in endermux then

sterile star
#

cloud vapor
#

well that wouldn't matter in this case as he's building his own serializer from scratch anyway

#

rather than building off paper's one (assuming that does exist?)

sterile star
sterile star
#

Tbh I am not certain it is, considering the ansi serializer is not included in API

#

I had to manually include the dep as compileOnly

cloud vapor
#

yeah got no clue how yours works fine then jmp lol - no ansi provider in paper and the ansi serializer just uses the basic flattener by default

sterile star
#

Alright great, this works:

final String ansiOutput = String.join("\n", output.stream()
    .map(line -> ANSIComponentSerializer.builder()
        .colorLevel(ColorLevel.INDEXED_8)
        .flattener(PaperComponents.flattener())
        .build()
        .serialize(line))
    .toList());

Thank you!

#

Maybe I should put the serializer building into a static field

#

lmao

wicked torrent
#

someone should make a discord bot using endermux protocol

sterile star
#

What everything can you do with endermux?

#

Any description of it somewhere?

wicked torrent
#
> gfdgd
[10:24:19 INFO] [Server thread]: [LoggedPrintStream] [STDOUT]: TextComponentImpl{content="", style=StyleImpl{obfuscated=not_set, bold=not_set, strikethrough=not_set, underlined=not_set, italic=not_set, color=NamedTextColor{name="red", value="#FF5555"}, shadowColor=null, clickEvent=null, hoverEvent=null, insertion=null, font=null}, children=[TranslatableComponentImpl{key="command.unknown.command", arguments=[], fallback=null, style=StyleImpl{obfuscated=not_set, bold=not_set, strikethrough=not_set, underlined=not_set, italic=not_set, color=null, shadowColor=null, clickEvent=null, hoverEvent=null, insertion=null, font=null}, children=[]}]}
[10:24:19 INFO] [Server thread]: [MinecraftServer] Unknown or incomplete command. See below for error
``` yeah it's just passing this translatable directly to ansi and it gets translated
#

its on fabric but we dont implement ansi provider either

cloud vapor
#

you do seem to have a language renderer class

wicked torrent
#

not used anymore

#

that was when I was sending component json over the socket, now log events are fully server rendered

cloud vapor
#

how odd

wicked torrent
#

gonna set a breakpoint

#

ok wait there is one ```java
@AutoService(ANSIComponentSerializer.Provider.class)
public final class ANSIComponentSerializerProviderImpl implements ANSIComponentSerializer.Provider {
@Override
public @NotNull ANSIComponentSerializer ansi() {
return ANSIComponentSerializer.builder().flattener(AdventureCommon.FLATTENER).build();
}

@Override
public @NotNull Consumer<ANSIComponentSerializer.Builder> builder() {
return builder -> builder.flattener(AdventureCommon.FLATTENER);
}
}

#

find usages was failing me

cloud vapor
#

ah i didn't think to look for auto service

wicked torrent
#

someone can pull that out into a separate PR if they want it earlier

cloud vapor
#

@sterile star when that's merged you should drop your flattener setting as it'll be pulled in by the provider

sterile star
#

Sure, will do

wicked torrent
sterile star
#

Though it doesn't exactly hurt me if I keep it in even afterwards

wicked torrent
#

and colored component logger messages once that's implemented, since currently you'd be restricted to the host console color level when adding your own log4j appender

#

except for command feedback from the special sender api

wicked torrent
#

so I guess it's not that practical

#

and if endermux was in paper you could use it's log4j plugins for your bot even if it doesn't use the protocol

sterile star
#

I mean, my discord bot doesn't currently do any log forwarding

#

But for full log forwarding, I can see its usefulness

torpid robin
#

Is there any built-in way to convert a BinaryTag/SNBT to a nicely coloured Component? (like the output of /data get ...)

#

(and if not would that be a welcome PR?)

sterile star
#

I am not sure if that's exposed in any way though (it's not)

boreal orchid
torpid robin
#

Adventure has an NBT module 😛

boreal orchid
#

yeah but that isn't really used in Paper

sterile star
#

This is the adventure channel

boreal orchid
#

well, that's embarrasing. I really thought this was paper-dev lol. Apologies for the confusion

sterile star
#

rip sadge

boreal orchid
#

I do feel like there was a pretty print method in adventure-nbt

sterile star
#

I certainly cannot find it

boreal orchid
sterile star
#

Sure, but that's not what they are asking for

#

This is what they want, I believe

boreal orchid
#

Yeah, I was hoping there was more configuration options in TagStringIO but I guess that isn't its purpose

cloud vapor
#

that's nothing in adventure to convert nbt to a component

#

depending on the platform you're using, i can probably point you towards a good alternative, but nothing cross platform

sterile star
#

That's what the Vanilla /data command uses

cloud vapor
#

yeah if you've got nms code around, wouldn't work for e.g. velocity or minestom

sterile star
#

Yeah that's true

#

But at least you have a good base you can copy and make into your own impl

ocean agate
#

what does 5.0 bring us?

sterile rampart
#

its mostly removing deprecated api and bumping the Java version we build against

deep steppe
#

is there an issue with adventure's sound seed?
the java code wasnt working so i made this snippet for testing

import:
  net.kyori.adventure.sound.Sound
  org.bukkit.NamespacedKey
  org.bukkit.SoundCategory

command test:
  trigger:
    set {_key} to new NamespacedKey("minecraft", "entity.cow.ambient")
    loop 50 times:
      set {_sound} to Sound.sound().source(SoundCategory.MASTER).volume(50).pitch(1).seed(loop-value).type({_key}).build()
      player.playSound({_sound})
      wait 1 second

and it plays the same sound each time

#

happens with all sounds that have random variants

prisma mason
cloud vapor
#

but it's possible that 1-50 play the same sound yes

deep steppe
#

its playing seeds 1-50 with 1 second interval

#

i mean what are the odds that the first 200 seeds are same, something has to be wrong
and its still going after 200

#

it changes at 300~ 😬 nevermind

deep steppe
tulip wedge
#

sooo will newer 1.21.11 builds have adventure 5.0?

prisma mason
tulip wedge
#

thank god 🙏

cloud vapor
#

or possibly the release after that depending on how it's going

#

I mean it's looking like we're incredibly close to 26.1 dropping, giving devs a bit longer to get used to stuff isn't a bad thing, plus we've still got a few tasks left, plus I want to have a public paper pr with a jar for testing too

barren wolf
#

although urs is prolly in better format hehe

gray quarry
obtuse ruin
#

some years ago i did something with packets and components in scoreboards. but idk if theres a better way nowerdays

runic onyx
cloud vapor
cloud vapor
serene hare
#

When will we have component newline splitting in Adventure? 😭 😭

wet kestrel
hoary plume
#

Would there be any way for MiniMessage to support the properties feature in a Player object component?
Because being limited to name, UUID or texture path is... well... limiting.

cloud vapor
#

It's on the to-do list

serene hare
cloud vapor
#

Key per lore line is fine and really easy to do and very user friendly

#

just write a little util function that iterates through all existing "my.key.N" where N is any number

serene hare
#

What if I want to have a blank line?

cloud vapor
#

..then have a blank line?

wet kestrel
#

Certainly more readable than something with embedded line break symbols/tags. 😃

cloud vapor
#

it's how i do it, and it's really nice, easily lets you visualise how the lore is split up without having to rely on other tools or copying and pasting elsewhere, also let's you be really deliberate about styles so you don't get caught up in any traps

serene hare
cloud vapor
#

yeah

serene hare
#

I don't really like the key hanging like that

cloud vapor
#

i have even considered something that does it for you to the minimessage translation system, something like Component.translatable("my.key", Argument.multiline()) that would just run through all applicable keys and join them at the end

cloud vapor
serene hare
#

Ok, thanks, I'll see with what I'll come up.

gray quarry
#

cause they kind of just go together if you have tab you have sidebar

rich widget
#

Hey! Is the webui working?

sterile star
rich widget
#

Not loading at all for me, neither pc or phone

#

Is it happening to somebody else?

boreal orchid
#

seems to be fine for me

sterile rampart
#

fine for me too

fathom mulch
#

how can i get the length of a component?

boreal orchid
#

component length ultimately couldn't be measured if you have to include things that depend on the client such as translatables

#

if you only account for text components, then you can just iterate the tree and sum up the length of every text component

fathom mulch
#

it's probably better if i calculate the length before adding styling then

boreal orchid
fathom mulch
#

just trying to add x amount of characters to fill space and have a bunch of strings of the same pixel length

boreal orchid
#

I mean, that only really works with the assumption that the client hasn't changed the default font with a resource pack

fathom mulch
#

in my case i can assume that

fathom mulch
#

thank you anyway!

#

doing it beforehand is paying off

ocean agate
#

how can I replace a matched component with defined color? replaceText only accepts string

#

Like I have a component like this, I only want to replace the yellow player name, not the orange player name in the hover text

upper tinselBOT
ocean agate
#

That's not a xy, I want to replace a component in a component

sterile star
ocean agate
wet kestrel
#

third party plugin doing the other part?

cloud vapor
#

and what are you replacing it with

ocean agate
#

Another component?

sterile star
#

What's the content of that component

wet kestrel
ocean agate
ocean agate
#

Just want to know if it's possible to replace a component inside a component, if not I'll just use replaceText to replace all matched text in a component

boreal orchid
wet kestrel
boreal orchid
#

but in general, you'd probably have to use the condition method in order to index the one with a specific color or something, you can't match a Component exactly with replaceText. At best you could iterate the component to find the one you want but it gets annoying given you'd essentially duplicate the replaceText logic

noble grove
#

Might be in the wrong place to ask this, but with the sprite tag, is there a way to get a blocks texture?

#

but instead of it just being the flat texture, its the item model view of it

sweet hornet
#

No

boreal orchid
#

you could probably do that if you were to play around with shaders and a resource pack, but it will be quite hacky and messy

noble grove
#

gotchaaa, thanks yall!

noble grove
#

Another thing, can you nest a gradient within a text shadow key?

cloud vapor
#

i dont see why not

pastel berry
#

Im making a Minecraft Plugin and I saw this Scoreboard/Sidebar Icon Style (The Golden Apple and the Gold Block) the Server doesn't use a Texture Pack or a Mod to show this icons in the Scoreboard/Sidebar, if anyone knows how I can do to make the icons to show like that I would appreciate a lot 🙂

sweet hornet
#

Sprite component

cloud vapor
#

more specifically, object component with a sprite object

pastel berry
#

How do i add it to my plugin?

cloud vapor
#

what platform?

#

paper, velocity, spigot, bungeecord, minestom, fabric, forge, sponge, etc, etc, etc

pastel berry
#

Paper

cloud vapor
#

adventure is included by default

inner nest
#

Should we sign message for tell command?

#

and is it really possible to sign a command argument?

fiery oracle
#

(assuming your platform is paper)

boreal orchid
#

Yeah, though that has more to do with brigadier than with Adventure which I believe doesn’t deal with messages/signed messages

fiery oracle
inner nest
#

Thank you, yes platform is paper, i am mostly asking if it makes sense to sign player messages of /tell command.
Also, lets assume I do not use brigadier, is there a way to sign the message?

cloud vapor
#

no

inner nest
#

Thanks, so in conclusion, it does not really make sense to sign the message of /tell ?

rare sage
#

i would argue that it does, however if the command framework that you are using doesn't support such argument kind, you don't really have a lot of options

cloud vapor
#

yep, you should be signing any player text

elder forge
cloud vapor
#

Whatever fonts the client knows about

elder forge
#

How do I check it

cloud vapor
elder forge
#

Thanks

gray quarry
#

is it possible to do something like make a blank player head sprite and do like "<red><sprite>" and it'll color the sprite red?

#

or just like set texture of a player head sprite to an image I haven't figured out how to exactly do that

restive spruce
gray quarry
#

yeah thats what I am currently using but using heads makes a cool thing where for the head next to it theres no gap

sweet hornet
#

Yes you can

gray quarry
#

what

sweet hornet
#

You can actually recolor any sprite

gray quarry
#

how do I do it

sweet hornet
#

Just put the color in front, like you wrote

gray quarry
#

but if I did eg skull:OwlBe my skull would be a skull of an owl so what it would just turn red?

#

or have like a red overlay?

sweet hornet
#

Yes

gray quarry
#

hm let me test it

sweet hornet
#

If you take a completely white head (I’m sure there’s a lot on head database for example), it’ll be fully colored

drifting cypress
#

Hi, does anyone here happen to know how I can do this? (No resource pack or other texture-related items are used.)

Here is a record from SniffCraft: https://pastebin.com/n3T9PBxk

cloud vapor
#

you can see the json, it's all player objects

drifting cypress
#

Yes, but how do you create it?

cloud vapor
#

Upload a load of skins, use the object component with a player object

sweet hornet
#

You can use for example mineskin.org to upload the skins and get the textures url

drifting cypress
#

Yes, but how do I convert it to MOTD?

inner nest
cloud vapor
#

yes

inner nest
#

Thank you, that is what Im mostly worried about, since it is not very stable and sometimes player get kicked

kindred forge
#

Is there any possibility to "overwrite" the locale of an player?

arctic drum
#

Hi, I have a rather annoying bug.

For context, I want to implement my translation system using resource packs, so that translations appear in dialogs and item stacks. I've put all my keys in a resource bundle called langs, and in my .properties file, I've set the messages to MiniMessage to ensure optimal readability and color coding.
(This is a personal choice; there are simpler alternatives, yes.)
For example: command.fun.playtime.success=You have <light_purple>%s</light_purple> of playtime.

The problem is that the in-game colors don't display when there's an argument, whether in commands, menus, or dialogs.

Example output in the resource pack:
"command.fun.playtime.success": "You have §d%s§r of playtime."

So I did some research, and I think I might have found the original bug.

When I send a message with my plugin: MessagesManager.sendMessage(player, Component.translatable("command.fun.playtime.success", TranslationManager.getFallbackTranslation("command.fun.playtime.success"), Component.text(DateUtils.convertTime(timePlayed)).color(NamedTextColor.LIGHT_PURPLE)), Prefix.OPENMC, MessageType.INFO, true);
and by setting the color I want for my argument, it works.

However, I'd like to avoid hardcoding the argument's color in the code.

My guess is that Adventure might be setting the default color to white for the argument since my component that contains it was simply Component.text(DateUtils.convertTime(timePlayed)).

Am I wrong? Is this an adventure bug? Or am I just missing something?

cloud vapor
cloud vapor
#

wouldn't be surprised if something is breaking with your legacy text formatting

sand drift
#

legacy text is generally not consistent in how it "bleeds over", so that is pretty much going to be the issue; unless adventure was actually producing an improper component, this is 100% on the client

runic onyx
arctic drum
cloud vapor
#

I'll just reiterate that I wouldn't be surpised if it was an issue with legacy text formatting

arctic drum
#

So what can I do in this case?

rare sage
#

if you are going to work with resource packs, then you should do it the way vanilla does translations: translation strings are plain strings, if you want styling you need to style the argument, e.g. "command.fun.playtime.success": "You have %s of playtime." -> Component.translatable("command.fun.playtime.success", Component.text("one thousand hours", NamedTextColor.LIGHT_PURPLE))

arctic drum
#

Yeah, but that's precisely why I want to avoid hardcoding the argument's color in the code.

rare sage
#

that is just how the game works

#

translation strings are plain text strings, the styling goes onto the rich components

legacy style formatting is going to be removed one day and that ugly hack will stop working eventually

#

and it clearly is not working very well right now either

#

that's just how resource pack translations are done

cloud vapor
#

id consider just not using resource pack translations

rare sage
#

server-sided translations don't have that limitation because they don't use the vanilla translation mechanism at all, it's a totally different system

rare sage
arctic drum
#

🫠

cloud vapor
#

i mean you can translate everything yourself for dialogs and item stacks can have similar workarounds

rare sage
#

it becomes a huge pain to manage itemstacks tho

#

if they are transient it's whatever

#

but if they are persistent items that you can move around etc

#

good luck

arctic drum
#

Okay, I'll just add color to the argument. One problem solved, 10 found, as they say xD

arctic drum
rare sage
#

i mean, they did, it's called resource pack translations

#

this is not a minecraft problem, this is a problem inherent to the system being abused here

arctic drum
#

yeah

rugged leaf
#

Very stupid idea, but couldn't you technically split up the translation system to have both server side and client sided translations. Server side translation does coloration + other non text stuff, and client sided translation does text.

#

I think that assumes a bit too much on language patterns though

random latch
#

hey i'm curious if this is a supported pattern or something i can hack in:

i run 1.8.9 😰 (for shame, for shame; i know) [this issue happens to any version below 1.19.3, i think to broaden the scope beyond 1.8] and one persistent annoyance is not being able to play sounds at a consistent volume to a player that can move
-# (because if the player can move, they can move away from the sound source and thanks to the linear attenuation it gets quieter)

inspecting the source; i found that the way the sound falls off is a sound is at its quietest 16v (where v is the volume in [1..∞] [oversimplification]) blocks away.

using this fact if i play the sound hundreds of thousands of blocks (k) away in the sky i can set a "desired volume" anywhere from [0..1) to make it so that even if the player moves a ton the volume will barely change by nature of the gradient being thousands of blocks long.

you can compute the actual volume from the desired volume like so:

private const val k = 100_000f
private const val r = 16f
private const val maxVolume = 0.9999f

// yields the correct volume should the source be distance blocks away
private fun computeVolume(desiredVolume: Float, dist: Float = k) =
    dist / (r * (1f - desiredVolume.coerceIn(0f, maxVolume)))

-# (recall that i bound the desired volume to [0..1) because to play at 1 volume the sound needs to be AT the player but if i play the sound AT the player the issue is that when the player changes YAW the sound's "direction" sounds wrong)

what i need help with doing is making it work on a specific audience. it's on a 1.8.9 paper (fork) server and as such i assume the logic is in adventure-platform/platform-bukkit.

  1. is there a way to achieve this without custom dep + shade (aside from helper method)
  2. is there a way to modify existing plugins like (namely pgm) to support this (i.e. instrument playSound with just sound and audience param)

any help would be appreciated <3

cloud vapor
#

As documented in MC-146721, any stereo sounds will not play at a specific position or following an entity, therefore, the location or emitter parameters will be ignored.

#

use stereo if you want it consistent everywhere

random latch
# cloud vapor use stereo if you want it consistent everywhere

i can't just change sounds on my players' clients to make them stereo and also i want to generalize being able to play 'locationless' to all vanilla minecraft sounds, so i'm afraid (from what i can glean) this isn't super helpful for me without a custom pack 😦

cloud vapor
#

well then there's not much i can say other than you will just have to play it very loud and far away ig

random latch
# cloud vapor well then there's not much i can say other than you will just have to play it ve...

yeah; that's what i wrote about, but the question i have is about whether there's a way to make adventure 'do the work' for me through some api where i can change the behavior of the sound playing or if i have to just fork and custom dep + shade it. for all intents and purposes just imagine my post says "say i want to make every sound sent to my audience play x blocks away relative to the player at a huge volume"

cloud vapor
#

you will have to just do this yourself, we won't have any api to modify every sound that is played

#

whether you do that via a fork or in a util method or w/e is up to you

random latch
#

i'm looking at the say pgm in particular handles its audiences, is it perhaps possible through a forwardingaudience.single or similar? is there some idiom to downcast/convert one of these audiences to a Player to get its position and whatnot and override the playSound method (forgive my lack of knowledge about audiences and adventure in general, i'm learning)

cloud vapor
#

yeah you could wrap an audience in another audience that modifies the sounds played to it

#

how you get the underlying player would depend on the implementation of the audience

#

you'd likely want to cast and then do something

random latch
#

thanks! it looks like this was the solve. i'm not sure if it's good but it looks like this for now. looked at the docs and pointers ended up being super useful in this case!

cloud vapor
#

very nice!

wispy folio
#

how can I convert strings that contain legacy colors to adventure e.g. "&5hello"

sterile rampart
#

LegacyComponentSerializer

wispy folio
#

which should I look into 😨

sour totem
#

text serializer legacy

wispy folio
#

thx!

kindred forge
#

Why is adventure making out of "<white>[gradient:#e83920:#ffe5ddBedWars<white>]" the following using LegacyComponentSerializer

"§f[§x§e§8§3§9§2§0B§x§e§b§5§2§3§be§x§e§f§6§a§5§6d§x§f§2§8§3§7§1W§x§f§5§9§b§8§ca§x§f§8§b§4§a§7r§x§f§c§c§c§c§2s§f]"
Where the f*ck is "§x" coming from?

green monolith
#

The §x is to indicate the start of a legacy hex color

kindred forge
#

Ahhh okay, then it makes sense 😄

#

ty

green monolith
#

No problem

robust wharf
#

Where the f*ck is "§x" coming from?
questions you need to ask md_5, lmao

kindred forge
sweet hornet
#

It's not adventure's team who made such decision about legacy formatting of hex colors, don't worry you offended nobody here x)

jaunty cradle
#

Is there a way in adventure from Bukkit Material to component sprite ? (smth like : Component.object(ObjectContents.sprite(Material.DIRT)))

cloud vapor
#

Nope, I'm not sure we even could add one - I'm not aware of a clean mapping to a sprite like that

jaunty cradle
#

ok, so i need to have own mapping of material to sprite :(

sweet hornet
cloud vapor
#

if these can be generated at runtime im 100% okay with a SpriteLike interface being added

sweet hornet
#

Unfortunately not really (well, for a fixed version Minecraft yes, but not for any version), essentially I made a rule-based engine that do simple string manipulation processing on each material's name then checks for the existence of a sprite in the vanilla atlases (statically exported to files from client-side), then I wrote a set of rules that works for most materials, and finally I added "overwrite" rules for special cases where no 1:1 sprite mapping was possible, sometimes even relying on a custom player head because no texture was available as a sprite (for example, chests)

cloud vapor
#

So not possible without the client right

#

bc fixed version is fine for platforms like paper

sweet hornet
#

So currently it covers every materials of MC 1.21.11, but if new materials are added in next version, they may not be matched by any rule for example

jaunty cradle
#

wait so sprites keys are not consistent acros versions ?

sweet hornet
#

This is why I designed it that way, it's just a tools that generates the mappings for a given version (which depend on the atlases and rules you give him)

sweet hornet
jaunty cradle
#

damn mojang...

sweet hornet
#

Also, any resource pack could technically change the textures, and thus bring new sprites to atlases, but custom items are not really covered by my project

obtuse ruin
#

i have this translation

command.online = <prefix><gray>The server <gold><server> <gray>is currently <status:'false#<red>offline|true#<green>online'><gray>.

and im sendig it to a player with this

source.sendMessage(translatable("command.online").arguments(
        Argument.component("server", text(requested.getServerInfo().getName())),
        Argument.tagResolver(Formatter.booleanChoice("status", throwable != null || ping == null))
));

prefix and server are parsed correctly but the status choice is not beeing evaluated. how can i do this inside a translatble component

boreal orchid
obtuse ruin
#

well yea im dumb thanks

smoky wadi
#

I've been looking around some conversations here, and it seems like
<head:{base64 texture}>
is not yet supported, right?

But the docs do document it as a thing.

Am I doing something wring?

#

Clearing up that would be much appreciated 🙂

#

Unless I'm confused as to texture meaning from the texturepack rather than what vanilla json defines as texture (the base64 string)

cloud vapor
#

Yes it means from the texture pack

smoky wadi
#

Thanks!

boreal orchid
fervent grail
#

if its the same as player head so i should be able to use skin texture

#

not the base64 but the mineskin generated skin value

plain glade
sweet hornet
#

In case you really need it without waiting for that, you can still make your own tag for it, like I showed here

swift jetty
#

What's the proper way to Plain/Legacy .serialize(Component) using specific locale? Seeing there is no .serialize(Component, Pointered) method

Should I render the TranslatableComponents before serializing them or..?

robust wharf
#

The server only has the english locale available anyways, right?

cloud vapor
#

yep

steel pulsar
#

Howcome when I use tag resolvers to resolve coordinate, it only resolevs one and not the other for this?

<click:copy_to_clipboard:'<coordinates>'>You are at <coordinates>

wet kestrel
steel pulsar
#

Yea the second one is resolved only

#

Oh well

#

I guess the tag resolver I'm using is my own that I made

#

because it resolves locations

#
    public static String formatLocation(Location location) {
        return String.format("(%.1f, %.1f, %.1f, %s)", location.getX(), location.getY(), location.getZ(), location.getWorld().getName());
    }

    public static TagResolver placeholder(@TagPattern String key, Location location) {
        return TagResolver.resolver(key, (arguments, context) -> {
            return Tag.inserting(context.deserialize(formatLocation(location)));
        });
    }
wet kestrel
#

You can reoslve whatever you want - just can't be an inserting tag you use there if you want the same tag in both spots.

#

Alternative option, you could make a <clipcoord> tag that functions the same as the entire click you put in there, to make it more readable and harder for the user to mess up

gentle pulsar
#

can adventure serialize to tellraw format?

#

oh looks like gson serializer is what does it

fervent helm
#

Hello, I want to get half of the width of a Component and thats why I need all texts from a component with the font and the decorations. How can I get that?

sage river
#

you could use Component#iterator (or #iterable if you want a nice for each loop) and check for TextComponents

#

you can't really support other component types tho

#

however idk if the iterator includes the component itself or just the children

plain glade
fervent helm
#

alright, thanks

raven crag
fiery oracle
noble light
#

why is examination being removed from adventure in 5.0.0?

cloud vapor
#

not really needed anymore

#

records do a lot of that for you

noble light
#

fair enough

devout spruce
#

Hey guys, does anyone have a clue how Cytooxien renders its Chat-Heads/Player-Heads ?

tawny bolt
shadow wyvern
#

can I somehow do dynamic replacements in a my MiniMessageTranslator, because I'd like to pass dates in Component#translatable

cloud vapor
#

Yeah you can do entirely custom tag resolvers

#

See the Argument class

raven crag
#

Is there a simple way to remove all HoverEvents from a Component and its children?

#

I'm asking because I'm using pixel-width to try to roll my own left-pad logic, but I think pixel-width has a bug where HoverEvents get included in a Component's width calculations.

runic onyx
#

I think you could use a ComponentFlattener for that

sour totem
#

you think it does or you've confirmed it does? i happen to have been using that lib for a while and never noticed weird width calculations

raven crag
#

I think it does but I'm also slowly going crazy trying to convert this random component wordwrapper I found to support pixel-width so I'm not sure what exactly is the problem.

raven crag
#

Figured it out. Object components' size gets significantly overestimated. I assumed that if they were unsupported they'd be considered as if their width is zero, but I think it might be seeing the player head object component as [unknown player head] and using that to calculate their width.

sweet hornet
raven crag
#

Yep, I'm writing that part now.

boreal orchid
#

I guess only time that changes is when the fallback is used now

#

but there's no API for that yet so a problem for the future

raven crag
#

For maximum backwards compatibility the fallback should have been , which minecraft renders as 8 pixels wide.

#

For those at home searching chat history, here's the hack solution:

        val widthSource =
            PixelWidthSource.pixelWidth(
                ComponentFlattener.builder()
                    .mapper(KeybindComponent::class.java) { component: KeybindComponent -> component.keybind() }
                    .mapper(ScoreComponent::class.java) { component: ScoreComponent -> component.value() ?: "" }
                    .mapper(SelectorComponent::class.java) { obj: SelectorComponent -> obj.pattern() }
                    .mapper(TextComponent::class.java) { obj: TextComponent -> obj.content() }
                    .mapper(TranslatableComponent::class.java) { component: TranslatableComponent -> component.fallback() ?: component.key() }
                    .mapper(ObjectComponent::class.java) { component: ObjectComponent -> "∅" }
                    .build())

-# i'm sorry for using kotlin