#adventure-help

1 messages · Page 8 of 1

sand rover
#

If I understand correctly, MiniMessage and Components are the Paper things we call “modern”, but Minecraft still uses the § symbol (which is the “legacy” term in Paper)?

wet kestrel
#

Depends on what you're doing with the component

boreal orchid
#

if you feel like it, when it is hardcoded strings like these I personally don't see the point

serene hare
wet kestrel
#

Minecraft moved on from the section symbol, the legacy symbol, in 2013. It still handles it in some spots on the client because they're afraid to break it. But when a plugin uses the legacy symbol in something like the outdated and deprecated send message string method, the server has turned that into components since 2013. I wrote that code for Bukkit in November 2013 :3

#

@sand rover ^ meant to reply

sand rover
#

Okay, so the client understands the concept of Components?

wet kestrel
#

Yes.

sand rover
#

Ty

boreal orchid
#

that's what you use everywhere for any formatted text, like in tellraw or book contents component

wet kestrel
#

Adventure components and the actual ones in the server are not identical but it's the difference between public usable API and internal code

sand rover
#

I thought no matter how presented in code, at the network layer it all flies as characters prefixed with § signs LMAO

wet kestrel
#

There's a serializer internally to go to MC stuff to send off in packets

#

Nope, that ended with mc 1.6.4

serene hare
sweet hornet
#

Otherwise it may interlace with other messages send to the client at the same time

boreal orchid
#
ctx.source.sender.sendRichMessage("""
    <dark_gray><st>+----------+</st></dark_gray> $prefix <dark_gray><st>+----------+</st></dark_gray><br>
    <br>
       <gray>Author: <aqua>${Plugin.pluginMeta.authors()[0]}</aqua></gray><br>
    <br>
       <gray>Version: <aqua>v${Plugin.pluginMeta.version()}</aqua></gray><br>
    <br>
    <dark_gray><st>+----------+</st></dark_gray> $prefix <dark_gray><st>+----------+</st></dark_gray>
""".trimIndent())

looks funny

sweet hornet
#

You wouldn't need to .trimIndent() if you placed correctly your closing quotes

boreal orchid
sweet hornet
#

This wouldn't have occurred if they sent one single multi-line component per message

serene hare
sweet hornet
#

.append works for components

serene hare
#

yeah

boreal orchid
#

in a MM string you'd have to use <br>

serene hare
#

i could create a component for eachline

sweet hornet
#

(and doesn't insert a newline, unless you call a .appendNewline())

serene hare
#

btw there are no problems concatenating strings the "old" way with MM right?

#

like here

sweet hornet
#

wdym

serene hare
#

concatenating strings together using + or ${}

boreal orchid
#

there's nothing wrong with that, no

serene hare
#

aaand what if $prefix is a component? how could I render it in the string?

sweet hornet
#

As long as you don't use it to achieve something either:

  1. super complex
  2. already possible with MM
  3. or absolutely misleading for the user
    it should be fine
#

😄

boreal orchid
#
sendRichMessage("<prefix>", Placeholder.component("prefix", prefix))
#
ctx.source.sender.sendMessage(
    textOfChildren(
        text("+----------+", NamedTextColor.DARK_GRAY, TextDecoration.STRIKETHROUGH),
        space(),
        prefix, // will assume prefix has been turned into a Component too
        space(),
        text("+----------+", NamedTextColor.DARK_GRAY, TextDecoration.STRIKETHROUGH),
        newline(),
        newline(),
        text("   Author: ", NamedTextColor.GRAY),
        text(Plugin.pluginMeta.authors()[0], NamedTextColor.AQUA),
        newline(),
        newline(),
        text("   Version: ", NamedTextColor.GRAY),
        text("v${Plugin.pluginMeta.version()}", NamedTextColor.AQUA),
        newline(),
        newline(),
        text("+----------+", NamedTextColor.DARK_GRAY, TextDecoration.STRIKETHROUGH),
        space(),
        prefix,
        space(),
        text("+----------+", NamedTextColor.DARK_GRAY, TextDecoration.STRIKETHROUGH)
    )
)

I am often for using the "raw" adventure API when it comes to hardcoded components but this is hilarious tbh

sweet hornet
#

textOfChildren?

sweet hornet
#

Maybe you could've slightly simplified it using LinearComponents#linear tho?

boreal orchid
#

was that merged already

boreal orchid
#

tbh I don't see how it would change anything

obsidian nimbus
#

MiniMessage still cleaner

sweet hornet
#

I guess maybe statically importing NamedTextColors and TextDecorations would make it slightly less worse

boreal orchid
# obsidian nimbus MiniMessage still cleaner
ctx.source.sender.sendMessage(
    LinearComponents.linear(
        DARK_GRAY, STRIKETHROUGH, text("+----------+"), space(), prefix, DARK_GRAY, STRIKETHROUGH, space(), text("+----------+"),
        newline(), newline(),
        GRAY, text("   Author: "), AQUA, text(Plugin.pluginMeta.authors()[0]),
        newline(), newline(),
        GRAY, text("   Version: "), AQUA, text("v${Plugin.pluginMeta.version()}"),
        newline(), newline(),
        DARK_GRAY, STRIKETHROUGH, text("+----------+"), space(), prefix, DARK_GRAY, STRIKETHROUGH, space(), text("+----------+")
    )
)

not too bad actually

sweet hornet
sweet hornet
#

So unless there's some form of "resetting" like legacy, the components will be better that linear

small cloud
#

whats the right serializer for whatever format minecraft vanilla text strings have?

sweet hornet
#

None?

#

What are you trying to do?

small cloud
#

uuh generating a datapack jukebox_song.json and for the subtitle I needa component

#

I think?

quaint monolith
#

Oh so json

sweet hornet
#

You need JSON

small cloud
#

ooh

sweet hornet
#

(The GsonComponentSerializer)

small cloud
#

I thought I needed the weird minecraft fake json

#

my bad

sweet hornet
#

You mean SNBT?

quaint monolith
#

mojangson is for commands, although I guess it's called SNBT now?

small cloud
#

but I guess I was wrong

quaint monolith
#

Like typing in chat

#

For a json file you'd want real json

sweet hornet
#

There are places where components are given with SNBT, but in a file called "jukebox_song**.json**", I mean...

quaint monolith
#

Check the wiki to be sure I guess

serene hare
#

audience.getOrDefault(Identity.LOCALE, Plugin.translationManager.defaultLocale)
why getOrDefault can return null? it's called getOrDefault 😐

boreal orchid
#

if it comes down to that format you'll have to do something really annoying for it

wet kestrel
#

I miss calling it Mojangson

boreal orchid
quaint monolith
#

I don't even see anything in the jukebox song definition that would take a component

serene hare
quaint monolith
#

Oh the description

#

Anyway it's all JSON as far as I can tell

boreal orchid
#

it takes any value

quaint monolith
serene hare
boreal orchid
quaint monolith
#

I wonder if they could use @Contract on that to make it conditionally nullable depending on if whatever you passed to default was nullable

#

iirc paper's API does that in a few places

sweet hornet
quaint monolith
#

Oh so kotlin issue

boreal orchid
#

@Contract("_, null -> null; _, !null -> !null") so if the second argument isn't null then the return value shouldn't be null either

sweet hornet
#

Wait, that contract is wrong

boreal orchid
#

I imagine that Plugin.translationManager.defaultLocale somehow is being seen as nullable to Kotlin

sweet hornet
#

The first part of that contract is wrong

boreal orchid
sweet hornet
#

That contract says:
If the second argument is null, then this method always returns null

quaint monolith
#

Clanker says Kotlin doesn't understand @Contract but I can't find anything from a person saying either way

sweet hornet
#

(And the second part of the contract is correct, which means "if the second argument is not (= never) null, then this method never returns null)

boreal orchid
sweet hornet
#

Well, the first part of that contract isn't particularely useful

#

"If the second argument is null, then this method returns something"

#

Who would've guessed? x)

#

The only relevant part is the second one, _, !null -> !null

small cloud
#

hmm just doing it with GsonComponentSerializer#serializeToTree doesn't seem to work

Caused by: java.lang.IllegalStateException: Failed to parse either. First: Failed to parse either. First: Not a string: {"text":{"color":"gold","extra":[{"color":"yellow","text":"Song"}],"text":"Welcome "}}; Second: Not a json array: {"text":{"color":"gold","extra":[{"color":"yellow","text":"Song"}],"text":"Welcome "}}; Second: No matching codec found

😅

#

wait a second why is the text a json object

wet kestrel
small cloud
frozen tree
#

Any reason custom fonts/lang messages do not work in tags? Vanilla <font> or <lang> tag messages seem to work fine, but when using it from a custom plugin it doesn't format it.

Messages are being sent using the paper API on 1.21.3+ like Player.sendMessage(Component)

In different plugins(TAB) it seems to work fine.

(The image with the red text is what the <lang> tag should translate to, but in our plugin in the green message it doesn't work)

wet kestrel
#

Have you tested a minimal reproduction code with just that running, no other plugins, on a vanilla client?

frozen tree
#

I've asked the person who had issues with it to test it on a paper 1.20.4 test server, to see if this is a issue with the paper MM API, I will let you know if there is still a issue

wet kestrel
#

If it's paper-related you'd want to test it on 1.21.8 not 1.20.4

frozen tree
#

They are now using 1.21.7, which lets our plugin use the paper API added since 1.21, when the server version is below 1.21 it will use the MM BukkitAudiance

#

So 1.20.4 would rule that out

wet kestrel
#

Instead of MM do you mean platform-bukkit?

#

I still suggest doing the minimal reproduction on latest, maybe print some stuff to console to see what the parts look like as they come together. rgb_shrug

serene hare
#

should the fallback strings be hard-coded or have a fallback file (still have multiple translation files)?

sweet hornet
#

If you make fallback dynamically, why making it fallback?

serene hare
#

i would need the fallback in case the user deletes a translation key

sweet hornet
#

But if it’s dynamic, what would prevent the user from deleting that as well?

molten jasper
#

is boss bars with adventure natively in paper package or i have to implement antoher library to use components with boss bars

wicked torrent
#

native

molten jasper
#

so

#

how

#

it's this right

#

ah okay

#

got it

lime ermine
#

Hello, I've run into some kind of issue with new-line formatting. Instead of the newline appearing, this sort of symbol appears in place of that. I've also tried using <br> inside the PotionFormatter string but got the same result

#

I'm apppplying this onto an item

sterile rampart
#

lore doesn't handle newlines

lime ermine
#

oh i see, thanks, is there any work-around i could use?

sterile rampart
#

put them in your config as a list of components?

lime ermine
#

mhmm

sweet hornet
#

Is there documentation about the nbt module somewhere? I can't find it on https://docs.advntr.dev/

#

And second question, is it bundled in Paper or should I include it myself?

robust wharf
#

I don't think it's included in paper, we wouldn't want to expose an nbt api

#

You shouldn't need to use nbt generally

#

And I don't think we have docs for adventure nbt, other than the javadocs of course

sweet hornet
#

Ok thx

boreal orchid
#

isn't that module used just for stuff that takes nbt like hover events, dialogs and the like

sterile rampart
#

it's an impl of the nbt format

slate current
#

Is there no way to add one argument at a time in translation component builders? I can only see options for setting the entire list at once (which kinda defeats the point of a builder, at least for my use-case)

cloud vapor
#

sounds like a good PR opportunity

hardy estuary
#

I have tagsresolvers being passed to minimessage to deserialize and create the component.

An example of a tag is <item>.

In minecraft it is displayed correctly to clients, I am asking how can I serialize to String but resolving the tags?

I need a string and in the String I see <item> but I would like to see the actual value

sand drift
#

You would need to deserialise it to a component and then serialise it to a string

hardy estuary
#

Basically I am trying to add compatibility for discordsrv and I was modifying discord srv code.

He gets the Component from the AsyncChatEvent but he already does deserialization/serialization, maybe wrongly?

sand drift
#

Probably an order issue

#

Do you have it configured to use the modern paper events?

hardy estuary
#

ProcessChatMessage is a bit too long im confused lolol

#

yeah

sand drift
#

and, how are you applying the tags?

#

(really, the way they're doing that sucks, they should be using the renderer)

hardy estuary
sand drift
#

I mean, where are you running that code

#

are you modifying the message directly in the event? are you using a custom renderer?

hardy estuary
#

ah, I am doing it in my plugin, I have a renderUnaware.

and I also set it in the event, so plugin like discordsrv can get it formatted

#

event.message(myComponent)
event.render(myRender)

#

discordsrv btw doesnt need to render the event, he just need to grab the message to send to discord

sand drift
#

Well, that should work, as the component should have the parsed component in there

#

Well, no, because renderers can tweak messages

hardy estuary
#

don't know what to say, I will try to tell discordsrv dev

#

thanks for helping btw

amber quail
#

Since When does minimessage not use </bold> anymore?

sand drift
#

since forever, closing tags are optional

#

(at least, in some cases)

amber quail
#

Ah but its not in the code by default

vivid junco
#

It is possible to replace some text from the escape menu with something from Minimessage

sand drift
#

No, you can only modify that stuff using resource packs

#

(outside of like, an single entry you can optionally populate into there as part of the dialogue stuff in recent versions, but, probs not what you're asking)

vivid junco
sand drift
#

You don't

#

resource packs are zip files

amber quail
sand drift
#

You would need to look at the structure it produces

vivid junco
sand drift
#

It's probably losing the unset due to its prioritising the nesting of the color, I'd guess

sand drift
vivid junco
#

Replace the ReturnGame text in the lang file with <font:minecraft:esc>Return To Game</font> but nothing is applied

vivid junco
sand drift
#

MM is an adventure serialiser

#

you can't just slap MM strings into a resource pack, vanilla doesn't know what a resource pack is

#

I mean, doesn't know what MiniMessage is

vivid junco
#

Yeah, I think it's using the json format

#

But I don't know how

fiery oracle
#

you can attempt to abuse the client's rendering of legacy text

sterile rampart
#

you can't do fonts with that though

#

"the json format" is the component format, MM is just a layer we put on top of it

vivid junco
#

And from what I saw I can use json in the lang files

rare sage
#

no you can't, it's just format strings, but that message in particular takes no arguments so it's just a plain string anyway

rancid plank
boreal orchid
sand drift
#

Well, issue there is that chat plugins deal with the whole inseration of formatting which they don't want

#

ofc, that creates issues with plugins which deal with manipulating stuff in the renderer because they support audience aware operations

boreal orchid
#

The API supporting combining chat renderers would be nice for that. I remember there being use cases more than this one for that kind of thing

sand drift
#

Not sure what you mean

boreal orchid
#

Doing that with the current API is kind of annoying

sand drift
#

The issue is that it's just a glorified method that returns a component

#

idk how else you'd represent that sorta thing unless you started prescribing how stuff should be laid out in there

#

delegation is something that works, nothing says that you can't call the method, the annotation was added just solely because it's not a normal usecase for people to manually call the render method

#

but, ofc, that kinda falls apart if your goal is to just extract bits out, because there is no real formative layout there

boreal orchid
#

I’ll give a more clear use case of what I am talking about when I am home

sand drift
#

I mean, outside of delegation, idk how else you would design this in a useful manner unless you set requirements on how stuff is laid out

neon sphinx
#

shouldn't

final Player sender; //for this example player name is TestName
sender.sendRichMessage("<click:run_command:'/argument <sender>'>Test</click>",
Placeholder.component("sender", Component.text(sender.getName()))

when clicked execute /argument TestName?
because right now it executes /argument <sender>

tbh that was my first thought that its gonna do the first option

is it intentionally made so you can basically enter anything in there? or is that just a bug?

neon sphinx
#

still same thing

prisma mason
#

try Placeholder.parsed

neon sphinx
#

now

#

it works

prisma mason
#

👍

neon sphinx
#

ty

silk scarab
#

Does Object#equals properly compare components in the sense of checking if the same would be displayed?

#

If not, what would be a way to compare them?

sterile rampart
#

it's not a visual comparison, it's a data comparison

silk scarab
#

Okay, thats good enough for what i need haha, thanks :)

quaint monolith
#

The actual Object#equals is just comparing pointers

#

If you mean componentA.equals(componentB) they could look identical but not be equal because the tree is structured differently

lunar yew
#

Stupid question, but how do I play a sound for a Player if I already have a Sound object ready?

#

There was something about audiences in the docs, but that uses audiences and I'm not sure how to create that either. The docs used some sort of BukkitAudiences class which doesnt exist in my project

sweet hornet
#

Which platform are you using?

lunar yew
sweet hornet
#

So you are using Paper?

lunar yew
#

correct

sweet hornet
#

Then just use player.playSound(sound), if you have both a player and a sound as you stated in your question?

lunar yew
#

Man I'm such an idiot I tried to use play.playSound(location, sound, ...) not that

#

lmao

#

well thanks that's what I was looking for

sweet hornet
#

No problem, at least it was easy to solve 😅

lime ermine
#

Hello, is it no longer possible to substitute whole commands inside the <click:'run_command':'<THE_COMMAND> tag?
Because inside the tag, it doesn't get replaced however the second occurrence get's replaced.

 TypeConfirmToContinue:
   - ""
   - "<prefix> <gray>| <click:'run_command':'<command>'><hover:'show_text':'<red>Or just click this message to execute the command'><gradient:#ff5555:#9b94ff>Confirm the command - <yellow><command></yellow></gradient>"
   - ""
Mini.mm(s, "Commands.Misc.TypeConfirmToContinue", Placeholder.unparsed("command", "/syncher delete " + player + " confirm"));
sweet hornet
#

Placeholder.parsed(…)

lime ermine
serene hare
#

also, there's a way to add placeholders when building the MiniMessage instance?

obsidian nimbus
ember ginkgo
#

hi hi would anyone know why this click / hover event combo isn't working? i tried using the example above but im still struggling; (Paper

mission.ready_to_join.click.with_placeholder=<hover:"show_text":"{hover_message}"><click:"run_command":"{command}"><gold> ! </gold><yellow><underlined>[Click to Join]</underlined></yellow></click></hover>

    public void setReadyToJoin() {
        missionLifeCycleState = MissionLifeCycle.READY_TO_JOIN;

        // Send a message to all players
        List<Player> players = new ArrayList<>(Bukkit.getOnlinePlayers());

        Component hover = MessageController.INSTANCE.getMessage(
                "mission.ready_to_join.click.hover",
                Placeholder.parsed("command", "/mission join " + id.toString()));

        MessageController.INSTANCE.sendMessage(players, "mission.ready_to_join.click.with_placeholder",
                Placeholder.component("hover_message", hover),
                Placeholder.parsed("command", "/mission join " + id.toString()));
    }

*MessageController handles replacing "{}" with "<>"

*paper-1.21.7-32
*adventure :4.17

#

JK I JUST HAD TO UPDATE MY STUFF X)) catexplode

sweet hornet
ember ginkgo
#

just preference

boreal orchid
#

if you wanted to be fancy, you could probably make a MM instance which does the replacement on a pre-processor

serene hare
#

what's the advantage of using adventure's server-side localization instead of writing my custom implementation?
I'm trying to solve some problems using adventure but maybe I'm trying too hard and make my life simpler writing a custom implementation.

sweet hornet
#

The global translator is used automatically by Paper (and some other platforms as well could support it natively)

#

This means you send translatable components as if the translation happened client-side, but the server translates it right before sending it

serene hare
sweet hornet
#

Every translator has its own unique key itself, so this shouldn’t happen

serene hare
cloud vapor
#

e.g. myplugin.menu.title

sweet hornet
#

Also, aren’t keys namespaced specifically for this purpose, to avoid possible conflicts?

serene hare
cloud vapor
sweet hornet
#

Oh no translation keys are just basic strings, mb

cloud vapor
sweet hornet
#

Yeah just found that out

#

But this doesn’t mean you can’t do the same (add a namespace yourself)

serene hare
#

could I modify the translator to automatically prepend the plugin name to translations?

#

also, really important, I would need to translate items name/lore in my custom (read-only) gui

#

in that case I could render the component?

sweet hornet
#

Yes

serene hare
#

if I register the translations for a locale and then register again another translations for the same locale, do the translations gets overwrited?

serene hare
#

also I do not understand the difference between: MiniMessage.builder().editTags() and MiniMessage.builder().tags()

sweet hornet
#

The former keeps standard tags (and tags already registered on that builder instance), while the latter replaces them

#

Think "append" vs "set"

serene hare
#

oh ok so my intuition was right 🙂

upper tinselBOT
serene hare
#

<reset> doesn't seem to remove the italics in the lore

graceful kestrel
#

<!i>

vocal kite
#

How can I convert a String. (E.g. <red>test</red>) to a legacy string for example §ctest

cloud vapor
#

minimessage -> component -> legacy

vocal kite
#

LegacyComponentSerializer.legacySection().serialize(-)?

cloud vapor
#

yes

sweet hornet
#

Out of curiosity. Why?

vocal kite
#

and all gradient colors will be removed?

vocal kite
sweet hornet
#

Bedrock supports components??

vocal kite
#

no thats the problem

sweet hornet
#

Oh no ok I got it

boreal orchid
#

the library that geyser uses for the bedrock protocol also supports Adventure as of recently (commit ref 3a43b08) so it is just matter of Geyser updating their API

#

right now it seems that most things in bedrock still use legacy given their implementation of the component serializer, but that seems to be handled by them so you could technically use components freely as soon as geyser updates

sand drift
#

There is some questions over if the protocollib will keep the component stuff, but, there are alt legacy serialisers which support bedrocks "legacy+" format

serene hare
#

how do i remove all the styles of a component? i want to reset all the styles (like the default lore italic) before applying my component.
currently i do <!i> using MiniMessage in my component, but i would like to already to that in the code (so avoiding to use the mm tag every time).
myItemStack.displayName(myComponent)

upper tinselBOT
serene hare
#

i saw that but does Component.decorationIfAbsent() remove the original styles?
the method name does not suggest that...

sand drift
#

the issue isn't "removing"

#

you can't "remove" the style inherited from the component that the client wraps that in

#

You can override it with your own value, however

serene hare
#

and how would i use it on myItemStack.displayName(myComponent)?

sand drift
#

You would use it on myComponent

#

you would set the italic decoration to false to explictly disable that from the parent component

serene hare
#

but i dont have any arguments to pass to it

#

myItemStack.displayName(myComponent.decorationIfAbsent(...))?

sand drift
#

it takes arguments, I forget the specifics but you want to set the italic decoration to false

serene hare
boreal orchid
ruby lynx
#

Hello. When I updated geyser I had an issue because they started requiring kyori 4.24.0, i was on 4.16.0, i updated and now clickable text and hover text aren't working on my server. I'm on paper 1.20.1 with velocity 3.4.0

any ideas?

sweet hornet
#

Can’t you update to latest Paper 1.21.8? 1.20.1 is quite outdated

ruby lynx
#

so if i can fix it without doing so that'd be amazing

wet kestrel
#

I'd probably start by asking geyser how to mitigate that issue. Protocol shenanigans are shenanigans.

last horizon
#

this is not really an issue and more of an annoyance that is most likely just intellij being stupid again
using Component#text(String) inside a lambda yields a syntax error even though it compiles perfectly fine
i cant click on the method nor see its javadocs but looking for the method on the class itself i can find it
this only affects the string parameter method
reloading gradle works until i reopen the class
did anyone else ever encounter this or does anyone know how to fix this

dawn pewter
#

works perfectly fine for me

sand drift
#

probably just busted indexes or something stupid

dawn pewter
#

yeah

#

@last horizon can you try it like my example? Maybe it has something to do with the previous map call?

last horizon
last horizon
sand drift
#

god knows, aventure has 0 control over your IDE derping out

#

maybe plugins or a idea bug

last horizon
#

i wasnt expecting a magical solution because ij has more black magic against anything i throw at it

#

i reinstalled ij like a week ago but this has been going on for much longer already

rare sage
#

have you tried binary-searching the issue in your intellij plugins? or using the repair ide mechanism?

sweet hornet
#

And does it also happen if you specify the type explicitly in the previous map call (.<String>map(key -> ...))? If so, it would suggest it struggles to infer the type of that stream, and because there are multiple overloads for Component.text, it just gives up. Idk if it would help to solve the issue, but at least having a better understanding of how to reproduce it (without adventure), so maybe you could get support from IntelliJ

last horizon
last horizon
upper moth
#

how can i import adventure-platform-bukkit?

#

in to my gradle

wet kestrel
#

Isn't there an example on the docs?

prisma mason
#
serene hare
#

java.lang.IllegalArgumentException: Translation already exists: my.translation for en
there's a way to overwrite translations? i want to load custom user translations on top of the fallback translations

boreal orchid
serene hare
#

do i have any alternatives?

#

i'm using the MiniMessage translation store

boreal orchid
# serene hare do i have any alternatives?

I mean, it shouldn't be that hard. You just have to do something like this:

public record UserProvidedTranslator(
    TranslationStore<?> defaults,
    TranslationStore<?> user
) implements Translator {

  @Override
  public @NotNull Key name() {
    return Key.key("myplugin:user_provided");
  }

  @Override
  public @Nullable MessageFormat translate(@NotNull String key, @NotNull Locale locale) {
    if (user.canTranslate(key, locale)) {
      return user.translate(key, locale);
    }
    return defaults.translate(key, locale);
  }

  @Override
  public @NotNull TriState hasAnyTranslations() {
    return TriState.byBoolean(
      user.hasAnyTranslations().toBoolean() || defaults.hasAnyTranslations().toBoolean()
    );
  }
}
#

then you can add that translator as source of the GlobalTranslator

serene hare
#

so i create two minimessage translation stores, one for defaults and one for the custom translations

#

then i pass them to that class and add it to the global translator

boreal orchid
#

yeah, that should do it

serene hare
#

but eventually the minimessage translation stores would need a key, so i'll have a total of 3 keys right?

boreal orchid
#

wdym

serene hare
#

i'm creating the translation store like this:
MiniMessageTranslationStore.create(Key.key("myplugin:translation-store"))

#

if i do that 2 times for the defaults + custom translations i already have 2 keys

#

plus the one for the translator implementation that you made

boreal orchid
#

I don't think that key is used for anything tbh lol, just to identify the different translators if you happen to compose them or something I imagine

#

ah, it is used for the equals check

serene hare
boreal orchid
serene hare
#

so i could use an empty string for the minimessage ones

boreal orchid
serene hare
#

okok

boreal orchid
#

i.e. myplugin:user_translations, myplugin:default_translations

serene hare
#

and, beside the fact i'm using kotlin, should i feel bad to put the custom translator class inside my "translations" class?

#

i don't really want to create a separate file only for that

boreal orchid
#

I don't see anything wrong with that

#

just up to your code style

#

besides, the class would be fairly short in kotlin:

data class UserProvidedTranslator(
    val defaults: TranslationStore<*>,
    val user: TranslationStore<*>
) : Translator {

    override fun name(): Key = Key.key("myplugin:user_default_translations")

    override fun translate(key: String, locale: Locale): MessageFormat? =
        if (user.canTranslate(key, locale)) user.translate(key, locale)
        else defaults.translate(key, locale)

    override fun hasAnyTranslations(): TriState =
        TriState.byBoolean(user.hasAnyTranslations().toBoolean() || defaults.hasAnyTranslations().toBoolean())
}
serene hare
#

what's the hasAnyTranslations method for?

sweet hornet
#

i guess to skip having to search thru empty translators?

boreal orchid
#

You could probably just make it return TriState.TRUE given default translations should always exist but eh

serene hare
#

that's also true

#

and what about reloading translations?

#

i have to recreate all 3 stores?

boreal orchid
#

I imagine you’d have to remove the source from the global translator and then recreate them yes

#

You could theoretically make a TranslationStore that automatically reloads the existing ones without having to remove the source but eh

#

Let me see if I can whip out something simple for that once I get out of the bathroom

serene hare
#

oh lol

#

thx btw

#

and take you time 😛

dense veldt
#

so I guess in this case UserProvidedTranslator needs to have a unique key, but for the "inner" ones it doesn't really matter

boreal orchid
#

probably should put that in a paste

serene hare
#

so i will not use canTranslate?

#

ooh you could do like this:

override fun translate(key: String, locale: Locale): MessageFormat? {
    return this.customTranslations.translate(key, locale) ?: this.defaultTranslations.translate(key, locale)
}
boreal orchid
#

but I just realized this approach doesn't work

serene hare
#

why? I tried it and it seems to work

boreal orchid
serene hare
#

i came up with an another solution

boreal orchid
#

what did you end up doing

#

I was going to write something clever but figured it'd be easier to just have a reload method that does what I initially mentioned lol

serene hare
#

i have:

private fun initTranslator(): Translator {
    val customStore = this.createStore()
    val defaultStore = this.createStore()

    this.loadTranslations(customStore, defaultStore)

    val translator = CustomTranslator(customStore, defaultStore)
    GlobalTranslator.translator().addSource(translator)

    return translator
}

then:

var translator: Translator

init {
    this.translator = this.initTranslator()
}

then:

fun reload() {
    GlobalTranslator.translator().removeSource(this.translator)
    this.translator = this.initTranslator()
}
boreal orchid
#

yeah, that looks good to me

serene hare
#

to me too

boreal orchid
#

@serene hare I think you're the one person who has messed the most with the translator at this point, I'd write a forum post if I were you lmao

serene hare
#

bruh

boreal orchid
#

title: "tips for using adventure translation system"

serene hare
#

body: don't

fallow fable
#

I have an issue where all text on my custom items are italic, I know that is the default, but the only way I found to not let that it happend is by add .decoration(TextDecoration.ITALIC, false), but then I cant use italic in the text. How do I resolve this?

tawny bolt
#

use decorationIfAbsent instead

#

that way you can still set it to italic specifically

fallow fable
#

Like so: miniMessage.deserialize(loreLine).decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE);

#

Neither seems to work as I intent it to :/

#

Its either all italic or nothing

sand drift
#

That will set the italic decoration to false if it's not already on there

fallow fable
#

I try to show this lore:

   "<dark_gray><italic>{itemName}"
   "<gray>A mysterious artifact of uncommon quality."
  "<gray>It hums with latent power."
for (String loreLine : processedLore) {
                lore.add(miniMessage.deserialize(loreLine).decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE));
            }

This just make the entire lore normal text, not taking the <italic>into consideration

sand drift
#

generally, print out the json representation and see what it looks like

#

(and, considering that {} is not valid syntax for MM, I'm guessing you're running it through some code, so I'd guess, also check what that processedLore contains

fallow fable
#

the processed is just running .replace(), so at that point it is already correct text

#

It might work now, I have no idea what I did

#

I had an old config :I, but using .decorationIfAbsent was what fixed it, so thanks 🙂

prisma mason
#

also you can do <!italic> or <!i> to set italics to false

fallow fable
fallow fable
fallow fable
#

Yeah I am not a fan of that

prisma mason
#

why not?

fallow fable
#

Its not that user friendly if other people will configure it

prisma mason
#

hmm?

#

why would you think that? it's standard MM

tawny bolt
#

its a bit annoying for lore tbf with you having to add it for every line

fallow fable
#

I have never configured a plugin where I would have to add <!i> to make it not italic

#

I much rather just add <italic> where I want it to be italic

prisma mason
#

well I mean, then add the false flag programatically

rare sage
#

yes, that's what they're doing lol

tepid fable
#

Hi i'm getting this. can someone tell me what's that? it seems something related to mojang and adventure
i'm just trying to send a system_chat message with a url inside

rare sage
#

how are you sending the message? the url having single quotes there is incorrect ('https://...')

tepid fable
#

got it. i thought it was related to the error formatting not the actual string

narrow dove
#

since update from 1.21.4 -> 1.21.8, my parsing of a url with a <variable> in it now throws errors.
Caused by: java.net.URISyntaxException: Illegal character in query at index 101: https://www.planetminecraft.com/server/straight-up-survival-no-protection-smp-4081761/vote/?username=<username>

<username> is the issue.

I guess I have to pre-replace "<username>" in my string since minimessage now seems to take issue with parsing that placeholder in it's parsing logic due to increased URL verification?

rare sage
#

you need to use a Placeholder.parsed for that stuff iirc

narrow dove
#

oh cool thanks. Does that seem off that it was working in 1.21.4 using Placeholder.unparsed

fiery oracle
#

urls in click events are more strictly enforced since some recent version

robust wharf
#

(it's a Mojang change)

serene hare
#

how do i use MiniMessage's Format#date when using Component#translatable?

boreal orchid
#

like, a placeholder which has a date?

serene hare
serene hare
#

Formatter.date("date", LocalDateTime.now(ZoneId.systemDefault()
wanted to use that btw

#

what's different between Argument#tag and Argument#tagResolver?

boreal orchid
#

tag is a convenience method for tagResolver

serene hare
#

but the argument type (Tag vs TagResolver) is different

#

oh wait tag requires me to give a tag name

#

this should work

Argument.tagResolver(Formatter.date("timestamp", myDate.toInstant()))
boreal orchid
serene hare
spark relic
#

hello, i can get help here?

boreal orchid
boreal orchid
spark relic
prisma mason
#

if not do what Javier said, otherwise ask here

boreal orchid
serene hare
#

it should?

spark relic
prisma mason
spark relic
#

but i will say the problem if it is not then you say it i will delete it

serene hare
serene hare
prisma mason
#

the differnce is Placeholder.parsed runs before the main parser runs

#

since MM uses Java's DateFormatter you could just do

Placeholder.parsed("timestamp", DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss a").format(myDate))
#

can also change the MM string to

<white><hover:show_text:"<timestamp>"><relative-time></hover></white>.
serene hare
#

the problem is that i want to customize the date format with mm

prisma mason
#

?

boreal orchid
#

Placeholder#parsed uses a Tag#preProcessParsed while Formatter#date uses Tag#inserting. That being said, I don't think MM restricts nested tags to be only PreProcess ones?

prisma mason
boreal orchid
# prisma mason ?

they want to customize the date time format with the argument like they were doing

prisma mason
#

as I said, MM literally does exactly what I wrote

#

but this way you ensure the tag is pre processed

boreal orchid
prisma mason
#

why?

boreal orchid
#

localization? Lol

prisma mason
#

.....

#

you can localize with the date time formatter

boreal orchid
#

I believe they want to give the freedom to the user to customize the date time format however they want

prisma mason
#

I mean, they could also just make their own pre process resolver

#
public static TagResolver.@NotNull Single preProcessTime(@TagPattern final @NotNull String key, final @NotNull TemporalAccessor time) {
  return TagResolver.resolver(key, (argumentQueue, context) -> {
    final String format = argumentQueue.popOr("Format expected.").value();
    return Tag.preProcessParsed(DateTimeFormatter.ofPattern(format).format(time));
  });
}
#

this should work

#

@serene hare

prisma mason
serene hare
prisma mason
#

nope, this should work as is if I've done it correctly

#

it's possible it won't work

serene hare
#

i'm trying that

serene hare
prisma mason
#

thought so

serene hare
#
Argument.tagResolver(Utils.timeArgPreprocessor("timestamp", myDate.toInstant()))

fun timeArgPreprocessor(key: String, time: TemporalAccessor): TagResolver {
    return TagResolver.resolver(key) { argumentQueue, _ ->
        val format = argumentQueue.popOr("Format expected!").value()
        Tag.preProcessParsed(DateTimeFormatter.ofPattern(format).format(time))
    }
}
<white><hover:show_text:"<timestamp:'MM/dd/yyyy hh:mm:ss a'>"><relative-time></hover></white>
prisma mason
serene hare
#

i do not get any type of errors, the placeholder is just not parsed

prisma mason
serene hare
#

[14:23:54 INFO]: MM/dd/yyyy hh:mm:ss a

#

(i don't know why but the method gets called 6 times)

prisma mason
#

log the result of Tag.preProcessParsed(DateTimeFormatter.ofPattern(format).format(time))

serene hare
#
val test = Tag.preProcessParsed(DateTimeFormatter.ofPattern(format).format(time))
println(test.value())
#

like if the print was not called

prisma mason
#

what does DateTimeFormatter.ofPattern(format).format(time) return

#

it should work

serene hare
# prisma mason what does `DateTimeFormatter.ofPattern(format).format(time)` return

ok now it's really awkard

val format = argumentQueue.popOr("Format expected!").value()
println(format) // got output
println(DateTimeFormatter.ofPattern(format).format(time)) // no output (neither any "empty" lines)
val test = Tag.preProcessParsed(DateTimeFormatter.ofPattern(format).format(time))
println(test.value()) // no output (neither any "empty" lines)
prisma mason
#

debug that first

serene hare
prisma mason
#

yes

serene hare
sand drift
#

The temporal type you provided doesn't support getting the month of the year

serene hare
sand drift
#

Yea, and apparently an instant doesn't support that

rare sage
#

just pass a LocalDateTime

serene hare
#

so then I would need the timezone

#

there's a way to get the timezone of the player?

prisma mason
#

then use a ZonedDateTime

serene hare
#

oh, so that would be server defined and every user would see the same time?

prisma mason
#

correct

serene hare
#

that's not the greatest thing

prisma mason
#

just use UTC

sand drift
#

The client has 0 support for timestamps

#

and outside of going down the route of geoip, all the client has to guess anything is the locale of the player

prisma mason
#

I don't trust Locale as a Locale's country can have more than one timezone, namely USA and China

sand drift
#

Generally, people go down the route of just using the "server's time" as a grounding

prisma mason
#

I use UTC since most people know how to calculate their time from that

sand drift
#

i.e. many servers will bind themselves to UTC-5 for all of their servers event times

#

ofc, I've dealt with too many americans

serene hare
sand drift
#

Well, ideally the system time is the same as the "servers" time, but, that is overridable with JVM flags

#

(may want to consider providing a config option because hosts are a pain here)

sterile rampart
#

the hover event contents is parsed as a component so you can use unparsed tags there. The only reason you use parsed tags for click events is cuz their value is a string

rare sage
serene hare
sand drift
#

yes

serene hare
sand drift
#

an instant isn't tied to a timezone and so doesn't really have any real basis to exist

#

a ZonedDateTime has existence within our time concept of days and weeks

serene hare
#

what's different between LocalDateTime and ZonedDateTime?

sand drift
#

LDT is the more modern time API iirc

#

Nope

serene hare
#

oh okok

sand drift
#

LDT doesn't have any bounding to a timezone and is so somewhat "floaty"

#

ZonedDateTime is aware of timezones

serene hare
#

got it

crisp urchin
#

Not sure how to fix this? Its on spigot

prime sigil
# crisp urchin Not sure how to fix this? Its on spigot

Legacy formatting codes have been detected in a MiniMessage string - this is unsupported behaviour. Please refer to the Adventure documentation (https://docs.advntr.dev) for more information.

crisp urchin
prime sigil
#

Basically, you cannot mix legacy(&/§) format with MiniMessage(<>)

crisp urchin
#

As mentioned, I'm not sure where I would even change that as I didn't intentionally install it

fiery oracle
#

Is this in relation to a plugin you're developing?

crisp urchin
#

No, its Essentials X

fiery oracle
#

this channel is for developers to ask for help with the adventure API

#

for issues with a plugin, reach out to that plugin's support

crisp urchin
#

they sent me here dawg cause its your library

wet kestrel
#

Doesn't look like it to me.

crisp urchin
#

man whys the error spamming about yalls shit then

wet kestrel
serene hare
#

how do I check if a component is empty?

cloud vapor
#

isn't there an isEmpty method

#

or you can just .equals(Component.empty())

serene hare
sweet hornet
serene hare
#

i'm going crazy because customStore.registerAll(locale, file.toPath(), false) doesn't work. it worked 1h ago 😭

println(customStore.hasAnyTranslations()) // false
println(customStore.canTranslate("test", Locale.ENGLISH)) // false
println(customStore.translate(Component.translatable("test"), Locale.ENGLISH)) // null

and i do not get any errors

cloud vapor
#

I mean, it definitely works I can tell you that :')

serene hare
cloud vapor
#

How are you filling it up?

serene hare
#

i really can't explain to myself why it was working

hearty folio
#

Can you escape MiniMessage tags e.g. deserialize("\\<white>") or sth like that (i.e. render as literally Component.text("<white>")? The escape docs are a bit confusing (I think they’re talking about escaping \ in Java in general?)

robust wharf
#

\ works, yes

#

Depending on what you wanna do, you can use the util method provided on MiniMessage or you should use unparsed placeholders

hearty folio
#

Thank you, will try with \. Unparsed placeholders won't help me here though since I want to do escaping in my main string (which I'm fetching from config)

rare sage
#

then you should use the escaping method in the MiniMessage instance yeah

hearty folio
#

thank you

fervent agate
#

Hi, how can I add a default translation in case of the user language not being supported ?
Currently it doens't work and and it's just returns "itwillbreak.about_to_break"

public class Translations {

    public static void init() {
        TranslationStore<MessageFormat> store = TranslationStore.messageFormat(Key.key("itwillbreak:messages"));

        // Ajout des traductions7
        store.register("itwillbreak.about_to_break", Locale.FRENCH, new MessageFormat("Attention ! Votre {0} est sur le point de se casser !"));
        store.register("itwillbreak.about_to_break", Locale.ENGLISH, new MessageFormat("Warning ! Your {0} is about to break!"));
        Locale Spanish = new Locale.Builder().setLanguage("es").build();
        store.register("itwillbreak.about_to_break", Spanish, new MessageFormat("¡Cuidado! ¡Tu {0} está a punto de romperse!"));

        GlobalTranslator.translator().addSource(store);
    }
}

cloud vapor
#

what doesn't work?

#

you can set the default locale on the translation store

fervent agate
cloud vapor
#

did you set the default locale on the translation store?

fervent agate
#

No. I just use the default translation store, I don't create one

#

Oh my bad I create one

#

Sorry

#

How do I set the default locale for it then ?

cloud vapor
#

TranslationStore#defaultLocale(Locale)

fervent agate
#

It works tysm

serene hare
#

how can i debug the parsing and the registration of my translations from a .properties file when using TranslationStore#registerAll?

boreal orchid
serene hare
#

since yesterday my store does not register translations anymore

#

and i don't know why

boreal orchid
#

well, attach a debugger to your test server and see what is going on

#

or if you have the whole localization logic pretty isolated, you could make an unit test to make sure it isn't the issue, but that's only worth it if you are the type to do unit testing anyway

fiery oracle
#

what's your code

serene hare
#

so, this is the registering method:

this.localesFolder.walk().forEach { file ->
    if (!file.isFile) return@forEach
    val matches = filenameRegex.matchEntire(file.name) ?: return@forEach
    val localeTag = matches.groups[1]?.value

    var locale = DEFAULT_LOCALE
    if (localeTag != null)
        locale = Translator.parseLocale(localeTag) ?: return@forEach

    customStore.registerAll(locale, file.toPath(), 
}

the store is created with:

MiniMessageTranslationStore.create(Key.key(""), miniMessage) // yeah the empty key is intended

and this is the output after the registering method has completed:

println(customStore.hasAnyTranslations()) // false
println(customStore.canTranslate("test", Locale.ITALIAN)) // false
println(customStore.translate(Component.translatable("test"), Locale.ITALIAN)) // null
#

i use .properties files, and they're not empty

#

also when using another file and Locale.ENGLISH

boreal orchid
#

are you sure the fileNameRegex is being met

serene hare
#

yes i am

#
[20:23:13 INFO]: Loaded custom translations: EN, IT
[20:23:13 INFO]: FALSE
[20:23:13 INFO]: false
[20:23:13 INFO]: null
#

the really crazy thing is that it worked flawlessy until yesterday

#

but i did not any modifications of that part of code

boreal orchid
#

best to just use a debugger instead of print statements then

#

if you're using the run-task gradle plugin, it should be pretty simple to setup

serene hare
#

yes i am using run-task

boreal orchid
#

then you can just click the debug button on the run configuration generated by IntelliJ for the runServer task

serene hare
boreal orchid
#

you can just step in afterwards to check whether it is getting properly filled with the data

serene hare
boreal orchid
#

if you can't figure it out, you can either try to create a minimal reproducible example to reproduce the issue or post your thing on github and I'll check whether I can repro it as well

serene hare
fiery oracle
#

are you familiar with debuggers?

serene hare
#

it's not loading the translations

serene hare
#

i never went beyond breakpoints

boreal orchid
#

you have to step in in order for the code to keep running

serene hare
fiery oracle
#

the code on that line has not executed yet

serene hare
#

sorry, it was not clear, the loop already executed one time for the english locale

#

and no translation was loaded

#

then it was time of italian locale (i did it now) and still the same result

boreal orchid
#

can you check that the resource bundle isn't null?

serene hare
#

file.toPath() is a valid file that intellij let me open

boreal orchid
#

step into the registerAll method and check whether the ResourceBundle is getting built properly

#

you can go to the adventure class by Ctrl + clicking on the method then click the Intellij button that says "run up to this point" that will pop up on the left side of the line

serene hare
#

hmm

serene hare
#

already executed the method one time

#

if i ctrl-click on it i go to the method definition

#

but i don't see anywhere the "run up to this point" button

boreal orchid
#

you have to go to the impl

#

can't do much with the interface

#

Ctrl + Alt + B opens a popup for the impls or you can just click the green button on the gutter

serene hare
#

which one?

rare sage
#

just click "step into" on the debugger panel

serene hare
#

oh that was easy lol

boreal orchid
#

this was the button I was talking about btw

#

it was run to cursor lol

serene hare
#

the file content (cb) seems empty

#

but the files are not

boreal orchid
#

that is because the reader hasn't read anything yet, you have to let it run past that line

#

what you're seeing right now is just the initialized buffer

#

either step in to the past line or step into the PropertyResourceBundle constructor to see what is going on

#

though if the path is good, I don't see any reason why it would fail to load, it is JDK API

serene hare
#

from the try condition i got "redirected" on the catch

sand drift
#

readers are buffered, until it's read the temp char buffer will be empty

serene hare
sand drift
#

ignored

#

have you tried not ignoring it?

boreal orchid
#

that is adventure code

serene hare
#

i though that the debugger would let me see the exception

boreal orchid
#

it should, just step in one more time

sand drift
#

can you not copy that block of code into your own plugin for testing?

sand drift
#

if you're worried it's throwing an exception copy the code from that method into your own plugin and call it?

#

then you can print the exception

boreal orchid
#

inb4 it is about using the wrong path separator

serene hare
#

bruh i have to rewrite it cause it's java

boreal orchid
sand drift
#

JB literally supports transforming it as you paste it

serene hare
boreal orchid
#

I forget it does that, it is quite nice

boreal orchid
serene hare
#

yeah yeah, i did

#

but it did not convert the code for me

#

i have a culpript

java.nio.charset.MalformedInputException: Input length = 1
    at java.base/java.nio.charset.CoderResult.throwException(CoderResult.java:279) ~[?:?]
    at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:405) ~[?:?]
    at java.base/sun.nio.cs.StreamDecoder.lockedRead(StreamDecoder.java:217) ~[?:?]
    at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:171) ~[?:?]
    at java.base/java.io.InputStreamReader.read(InputStreamReader.java:188) ~[?:?]
    at java.base/java.io.BufferedReader.read1(BufferedReader.java:223) ~[?:?]
    at java.base/java.io.BufferedReader.implRead(BufferedReader.java:314) ~[?:?]
    at java.base/java.io.BufferedReader.read(BufferedReader.java:296) ~[?:?]
boreal orchid
#

why is input length 1

sand drift
#

generally encoding issues

serene hare
#

omg it's not utf8

#

but i can't change it

rare sage
#

you'd change the Charset used to load the file Reader

sand drift
#

Well, java only recentlyish added support for unicode property files

rare sage
#

or use an external file editor to change the file's encoding

serene hare
rare sage
#

idk

serene hare
#

there are just 2 lines

last horizon
#

@serene hare
in intellij you have to change the properties encoding separately

#

thats the most stupid option ever but it exists

sand drift
#

Semi makes sense when you remember that it was only in recent versions of java that properties files support that

#

ofc, people did offspec for a while

serene hare
boreal orchid
#

you can probably just use Adventure's UTF8ResourceControl to load it

rare sage
#

i mean, if the thing takes a Reader then the encoding is already taken care of by the Reader

serene hare
sand drift
#

fix the file encoding

boreal orchid
serene hare
#

yeah i think too

sand drift
#

otherwise you just make it a headache to deal with when you start actually using unicode

last horizon
serene hare
#

yeah sure

boreal orchid
#

I wonder why adventure itself doesn't use the UTF8ResourceBundleControl even though it suggests using it on its methods

boreal orchid
rare sage
#

yes but if you pass a Reader there is nothing to decode with a charset, it's already decoded

boreal orchid
#

? The reader doesn't decode anything until read is called somewhere

rare sage
#

yes, but it is the reader's job to decode with the given charset, not the Properties

sand drift
#

The buffered reader does if you ask it to

#

It's reading a char array, not a raw byte stream

rare sage
#

i mean, it does it, whether you ask it to or not, you can't skip it if that's all you have

#

the reader is the one decoding bytes with the charset and giving you chars

#

so if you give a Reader to a Properties, the properties object has nothing to decode, it's already decoded by the time the Properties consumes it

serene hare
#

thanks so much guys, it has finally loaded the translations

#

btw a little 🖕 to jetbrains

small cloud
#

I'm confused about translationstores, more specific the minimessagetranslationstore, if I try to translate with a store I added a json file via registerAll(locale.of("en_us"), path, false), it seems to return null?

#

oh wait, it doesn't take a json it takes a properties file

idle copper
#

After updating to 1.21.8, clickevents containing a callback are trying to execute an unknown command. Any solutions?

serene hare
#

How do I check if a TranslatableComponent is empty?

// The following doesn't work because the types are different
// TranslatableComponent vs Component
Component.translatable("key") == Component.empty()
serene hare
cloud vapor
#

but you can't know that until resolving it on both the server and the client

idle copper
serene hare
cloud vapor
#

yeah sure if you want

serene hare
#

do i need to use render?

cloud vapor
cloud vapor
serene hare
#

oh that was the missing step i forgot about

#

hmm

#

instead can i know if a key exists or not?

#

without rendering the component?

cloud vapor
#

you can just check canTranslate on the global translator, but bear in mind that won't check for client translations

serene hare
last horizon
cloud vapor
#

oh, ew, well, i think just gl you're on your own ig - can't exactly look into the source to see what might be broken haha

slate current
last horizon
#

yes its like 30 bucks or something to update

boreal orchid
#

and people pay for that

#

I should make myself a fork like that, dude is a genius

#

just claim 99% more performance

last horizon
#

while breaking 99% of compatibility

obsidian nimbus
sweet hornet
#

Why bother changing the brand?

#

I've seen companies selling access open-source services, and even worse i've seen people paying for them

summer comet
#

Hi guys, I know MiniMessage and Legacy colors don't go along very well but I would like to understand a little bit about what is going in behind it. Is it 100% safe calling ItemStack::getDisplayName, because we assume MiniMessage is already done with the formatting or not at all? I'm currently trying to integrate other plugins with mine, such as Nexo, that requires MiniMessage and I would like to know what could be the potential conflict when I'm trying to support both legacy colors and mini message, being the legacy colors the base.

I work based on legacy colors because most of our systems were designed like that and currently a whole revamp wouldnt be an option for now at least

sweet hornet
#

MiniMessage (similarly to legacy codes) is just an encoding

#

Once properly converted to component, the result is undistinguishable

summer comet
#

Got it, so I say in my case, the way to guarantee results it work with end results, such as ItemStack, BaseComponent, etc?

sterile star
#

The issue is converting back from component to legacy. Components have features which are not supported by legacy, resulting in a loss of data

sweet hornet
#

(However legacy codes cannot represent every component, unlike MiniMessage)

sterile star
#

^^

summer comet
#

Yeah i mean, legacy codes is mainly for colors

#

Is a simplification of the color system

#

format i would say

sweet hornet
#

Fonts, for example, would be lost

summer comet
#

But if I only work with the end-result ItemStack, that wouldnt be the case?

#

what if i did nexo item (encoded with MM i assume) > itemstack > setdisplayname(getdisplayname() + " §aHello")

sterile star
#

It would get lost, yes

sweet hornet
#

Your itemstack's name or lore could contains custom font, that would get lost in legacy

summer comet
#

So you're saying the way MiniMessage encodes is directly tied to the BaseComponent and the get/set displayname makes a more "basic" encoding that breaks these other components?

#

If I have to work with Spigot API, what would the best way to inject this kind of stuff (replacing placeholders mainly) without breaking the encoding work

sweet hornet
#

MM can encode every single component (it's nearly a 1:1 encoding) whereas legacy codes can only handle text with formatting (color & decorations), so if you want to preserve the component, you cannot rely on legacy encoding

cloud vapor
#

well the best way is to just use paper

#

outside of delving into nms there is literally no way to not lose stuff when using the legacy methods like getDisplayName

#

i mean, you could just hope and pray nobody ever uses anything like custom fonts, translatable components, sprite/head components, etc

summer comet
summer comet
#

I mean, the whole point to support Nexo etc is to indeed allow that lol

cloud vapor
#

your options are literally just use nms or the hope and pray method

robust wharf
#

Or don't use legacy, lol

cloud vapor
#

yep

summer comet
#

Thats not really an option for me at this moment

summer comet
robust wharf
#

Using legacy also isn't an option

#

You gonna have to die one death

summer comet
#

Does MiniMessage has a replace tool or something?

cloud vapor
#

it doesn't matter, the second you call getDisplayName you've already lost fonts, sprites, heads, translatable components, etc

summer comet
#

again, there are some borderline stuff i can do with MiniMessage, such as replacing placeholders, etc..

summer comet
#

Because currently I do have people using MiniMessage components and they most of the time display correctly

#

The problem is the setdisplayname/setlore indeed and placeholder replacement which indeed breaks things

cloud vapor
summer comet
#

So if i wanted to use MiniMessage, what options do i have when it comes to replacing placeholders / injecting new line without breaking anything?

cloud vapor
#

You can serialize to legacy using MiniMessage, but again you'll just lose everything apart from colour and styling

summer comet
#

Nono, i don't mean serializing to legacy, I mean replacing placeholders on an ItemStack that was generated with MiniMessage

cloud vapor
#

and atp you have only the item stack?

sweet hornet
#

Does spigot expose you components?

summer comet
# cloud vapor and atp you have only the item stack?

Not sure what you mean by at this point, I have other integrations with MiniMessage such as text messages (If there is no legacy color, minimessage is used <- but again, these are borderline components, not internal libraries or frameworks)

summer comet
cloud vapor
#

ig you could basecomponent[] -> json -> component -> minimessage (then replace your placeholders bearing in mind they will all be escape so you'll have to unescape and hope nobody was actually escaping stuff) -> component -> json -> basecomponent[]

#

adventure-platform might have a basecomponent serializer but idk

summer comet
#

So after an ItemStack is builded, there is no easy way to replace placeholders, thats what you're saying? kekw

cloud vapor
#

no

#

and it wouldnt be easy even if you were using paper lol - it's bad design to replace placeholders after you've finished creating the component

#

i suppose if you dont want to use minimessage you could just component.replaceText but then you have to deal with the regex and stuff

summer comet
#

Which means in any of the cases, I need to inject extra lore and how can i do that if is a bad design to replace placeholders after i'm finished creating the component lol

#

Nexo and other plugins provide me with the ItemStack, most of the plugins even don't give me an option to have the minimessage component, they might not even use it directly internally or expose them via the API

cloud vapor
#

ive already told you how you can do it if you want to do it the bad way

summer comet
#

Alright thanks

summer comet
cloud vapor
#

no clue

#

i dont know anything about the bungeechat api

cloud vapor
#

like i said we might have a serializer in adventure-platform but idk

summer comet
#

Founded for anyone else wondering adventure-text-serializer-bungeecord (snapshot builds)

#

So this actually converts from BaseComponent[] to Adventure Component, hopefully nothing breaks lol

sweet hornet
#

Assuming BaseComponent[] is correct, adventure’s Component are so nothing would break

stray patio
#

So i am trying to use the Triump-gui library in my paper plugin, but it gives an error as such:
Caused by: java.lang.UnsupportedOperationException
at ----1.0.8.jar/net.kyori.adventure.platform.bukkit.MinecraftComponentSerializer.<clinit>(MinecraftComponentSerializer.java:105) ~[----1.0.8.jar:?]

It seems to have issues with Components from Adventure, which triumph-gui shades aswel

#

Seems some others here have also encountered problems similar to this but I couldn't find a solution.
Does anyone here have an idea?

#

Oh I think its because its shading adventure-platform-bukkit or smth

rare sage
#

iirc you need to use some Paper specific item builder from it

stray patio
#

Thanks anyway :)

rare sage
#

omg that's me

stray patio
sand rover
#

Hi, How can I use tag resolvers to replace both <uuid> tags inside another tag (e.g. click_action)?

<white>UUID of <target> is <click:copy_to_clipboard:<uuid>><uuid></click>
serene hare
#

Is there something bad pre-rendering the TranslatableComponent on the server before sending them to the client?

sand drift
#

depends

#

But, I mean, it kinda doesn't matter outside of the vanilla clients languages, the data has to be populated and resolved from somewhere

serene hare
#

i use it to check if the translated message is empty and do things based on that

sweet hornet
idle copper
cloud vapor
#

got any more than a badly cropped screenshot?

#

click callbacks don't make commands like that so

sweet hornet
idle copper
cloud vapor
idle copper
#

The problem occurs for all client versions from 1.19.4 to 1.20.4 on a 1.21.8 server, and ViaVersion denies it's their problem.

cloud vapor
#

and paper 1.21.8 doesn't even use click callbacks anymore so nothing to do with paper either

sweet hornet
cloud vapor
#

vv_uuid with no prefix is not the paper command

sweet hornet
#

Oh I guess I got baited by how his screenshot was cropped, and I thought it was missing the beginning

idle copper
#

Yeah, it's /vv_uuid

cloud vapor
#

in fact the vv makes it seem like a viaversion thing but if they say it isn't them then ig so

idle copper
#

This is what we don't understand

cloud vapor
#

either way, not paper - check for other protocol hacks that may be malforming your click callbacks or custom click event packets

summer comet
#

Hi, so I'm not 100% into Paper API when it comes to ItemStack specifically, what kind of methods on Paper API simplifies the usage of adventure library? (Including adding new lines, appending certain component to a current line, etc..)

midnight spire
#

the major thing is being able to actually modify minecraft objects with adventure, otherwise you can use several Minecraft objects when building components too as they implement adventure interfaces

#

e.g. when creating an item hover

summer comet
midnight spire
#

no idea if I'm going to change the name lmao

#

I personally doubt OpenAI will live that long but ¯_(ツ)_/¯

midnight spire
#

as for the API: the docs.papermc.io pages have some information about paper-specific stuff

midnight spire
#

bubbles tend to burst violently

summer comet
#

Also how does Paper work internally? Does it save into Component (NMS) or internally it always preserves the adventure Component?

cloud vapor
#

depends really, i believe there's a wrapper nms component that holds an adventure one so serialization can be done directly from the adventure component

#

sometimes they're converted to nms components

summer comet
#

So if i just play around with the ItemStack#lore(), and void lore(List<Component>) and save content there nothing should break?

#

Meaning lore() -> directly to lore(List)

sweet hornet
summer comet
#

Alright, thanks man

robust wharf
#

You really shouldn't need to worry about any of that

#

The paper API will just work as you expect. Once you touch deprecated methods that have to do legacy conversions stuff falls apart obviously

summer comet
#

Yeah, for business reasons my project will have to stuck with Spigot support but it just makes sense to only support MiniMessage related stuff on Paper

#

From what i see internally, you're indeed still saving in Component (NMS) and then converting to Adventure but as you mentioned it should work as intended indeed

sweet hornet
summer comet
#

But I don't make those rules so fingerguns

#

Anyway, thanks yall

uneven silo
#

Hey, I'm currently looking at the localization stuff and I'm wondering if it is possible to crate something like a custom Locale resolver rather than using the clients locale?

I personally play Minecraft in English, but prefer the language of the server I'm playing on to be my native language.

So I'm wondering if it is possible to let custom code handle the locale resoling instead of taking the clients locale, to allow players to change their language on the server independet of the game language.

patent fable
#
private void initiateBossBar() {
    bossBar = BossBar.bossBar(
            Component.text("Wave 1"),
            0f,
            BossBar.Color.RED,
            BossBar.Overlay.PROGRESS
    );
    Audience audience = Audience.audience(game.getMap().getWorld().audiences());
    bossBar.addViewer(audience);
}``` anyone a clue why this bossbar doesn't show up (no errors)
sweet hornet
#

Did you tried audience.showBossBar(bossBar) instead?

patent fable
#

No I haven't

#

Nope nothing

sweet hornet
#

Could you check your audience (by sending a message for example) to make sure you actually have the expected player(s) inside?

patent fable
#

yes

#

give me a second

#

Do world audiences update automatically?

#

or do I have to recall java Audience audience = Audience.audience(game.getMap().getWorld().audiences()); every time?

sweet hornet
#

Idk, i guess it's up to the platform?

fiery oracle
#

world is already a forwarding audience

sweet hornet
#

In Paper, but which platform is he using?

fiery oracle
#

i mean they seem to already be calling ForwardingAudience#audiences

sand drift
#

audiences aren't event driven

#

i.e. even if the thing updates it's not going to "subscribe" to it and see any players being added or removed

fiery oracle
#

Audience#audience(Iterable) explicitly states that it does work if the underlying iterable it takes "updates"
if that is indeed a call to ForwardingAudience#audiences, whether or not that reflects changes depends on the implementation

#

(but if it is a forwarding audience, constructing another forwarding audience is redundant)

sand drift
#

I mean, it's basically a double wam

#

audiences() is using the getPlayers() method which returns a copy

#

But, being event driven doesn't mean that the underlying thing can't be updated, it can

#

the bossbar has no means of knowing that an audience was added/removed from an underlying forwarded audience

patent fable
#

I just update it manually rn and it works thanks for everyones help

young meteor
#

how do we remove italic by default for names, etc in adventure?

upper tinselBOT
mossy imp
#

wow

#

too fast

stark kiln
#

How do virtual components work? I've heard something like they could serialise the data to look in the same way it used to before deserialising, is that true? Does that mean that, for example, if I parse minimessage component <gradient:#123456:#654322>something</gradient> and replace "something" with different text using TextReplacementConfig, the new text will have gradient applied? Because with normal components it will be in single color afaik

cloud vapor
#

No that's not how it works

#

They're just components that hold data

boreal orchid
#

you couldn't use a text replacement config for it but you could technically replace a gradient tag's content if it is a virtual component (aka whether your context is set to emit virtuals, I believe it does by default?) by iterating through the component tree and emiting a new one if you find the gradient tag virtual component, but doing so would raise the question of why not just replace it before serializing the mm string

stark kiln
#

So there isn't a nice way to do that on Component?

#

Because in some cases where there is much to live-parse the parsing is less efficient

boreal orchid
cloud vapor
#

You're always gonna have worse performance using replaceText than starting from scratch with minimessage

stark kiln
#

Oh, somebody told me otherwise and it seemed pretty logical

#

And when I deserialize a minimessage string, what's the recommended way to replace a string, e.g. %itemname% with Component?

sweet hornet
#

Don't use %itemname% but <itemname> and use a dynamic replacement tag

boreal orchid
last horizon
#

the @Range annotation seems to be wrong
i did some testing and the pitch goes from 0 to 2
and the volume from 0 to 1

#

am i just being stupid or is the annotation just outdated?

sweet hornet
#

Volume can definitely go above 1, which doesn’t actually increase the volume, but rather the distance at which the sound can be heard

#

And pitch is between 0.5 and 2 in reality (values between 0 and 0.5 are allowed, but treated as 0.5)

last horizon
#

i see

sweet hornet
#

So yes, the range on the pitch is wrong, but on the volume it’s good

primal apex
#

I have never used MiniMessage before. Am I doing something wrong?

 private static final MiniMessage MINI_MESSAGE = MiniMessage.builder()
      .tags(TagResolver.standard()) 
      .tags(PlayerTag.playerTag())
      .build();

public static MiniMessage mm() {
    return MINI_MESSAGE;
}
MiniMessage mm = ZMiniMessage.mm();
sender.sendMessage(mm.deserialize("<white>Hi <player:" + sender.getName() + ">, how are you?"));

I only see the tags, not the colored message.

sterile star
primal apex
#

Thank you :)

#

The correct way to create gradients was <gradient:#fffffff:#ffffff>text</gradient> right? because it doesn't get parsed

runic onyx
#

too much f's

primal apex
#

Yeah i just wrote them here, i have correct hex colors in my code

prisma mason
#

send the actual mm text

runic onyx
primal apex
#

Whoops i had a problem in my parser, my bad

undone obsidian
#

hey, when creating a Sound.sound() it will automatically know if it is a sound event or a sound name?

cloud vapor
#

yep

undone obsidian
# cloud vapor yep

Is it even possible to play a set sound rather than a random one from a sound event without needing to brute force a seed for it

cloud vapor
#

nope

undone obsidian
sweet hornet
#

Isn't it fully client-side?

cloud vapor
#

I think the wiki has a seeds list?

undone obsidian
undone obsidian
undone obsidian
cloud vapor
#

i must be imagining bc i cant find it

undone obsidian
#

I don't think it's that hard to brute force them using smth like cupy

sweet hornet
undone obsidian
#

Like I found this in a spigot thread
Code (Java):
public Sound getSound(Random random) {
int i = this.getWeight();
if (!this.sounds.isEmpty() && i != 0) {
int j = random.nextInt(i);
Iterator var4 = this.sounds.iterator();

        SoundContainer soundContainer;
        do {
            if (!var4.hasNext()) {
                return SoundManager.MISSING_SOUND;
            }

            soundContainer = (SoundContainer)var4.next();
            j -= soundContainer.getWeight();
        } while(j >= 0);

        return (Sound)soundContainer.getSound(random);
    } else {
        return SoundManager.MISSING_SOUND;
    }
}

PositionedSoundInstance positionedSoundInstance = new PositionedSoundInstance(event, category, volume, pitch, Random.create(seed), x, y, z);

undone obsidian
sweet hornet
#

Interesting, I've never noticed that method before. Thx

undone obsidian
#

I think this is the correct one for 1.21.5 with seeds ( i tried a few and they match)

undone obsidian
#

But i dont think it will work for other versions as it matters how many sounds in a event exist

marsh oar
#

I heard there is pointer for permissions inside. How can I use it from Adventure or in general how works the point in adventure

cloud vapor
#

basic example would be

var hasPermission = audience.getOrDefault(PermissionChecker.POINTER, PermissionChecker.always(TriState.FALSE)).test("my.permission")
if (hasPermission) {
  ...
}
prisma mason
#

Is there any way I can get the ParsingException(s) from parsing an MM string?

robust wharf
#

Is strict mode still a thing?

#

Should be on the builder

prisma mason
#

nope still allows invalid tags e.g. <hover:show>

#

it does throw legacy formatting codes, but it does in non-strict as well

#

maybe I could just use TagResolver's resolve?

robust wharf
#

What is your goal?

prisma mason
#

oh I'm making the IJ plugin for MM and was making my own semantics checker but thought why not use MM's already existing exceptions

sweet hornet
#

But how would the plugin respond to custom tag resolvers? I mean, maybe on my MM instance I have redefined the hover tag so that <hover:show> is valid. Who knows?

prisma mason
#

that is what I'm going for, what MM would tell you is wrong instead of me redefining everything

#

as for custom resolvers, I haven't come that far

quaint monolith
#

Checking anything other than syntax would require compiling and running arbitrary pieces of plugins to get their MM customizations

fiery oracle
#

plus technically plugins could have their tags' formats vary dependent on info you'd only have during runtime, right?

quaint monolith
#

Yeah, you really can't do anything but validate basic syntax

#

You can't say "this tag only takes this attribute" or whatever since you don't know that either

#

You can assume the stock tags are actually the stock tags for the purposes of providing helpers for them (like showing the color for an RGB value) but you can't do any validation

boreal orchid
#

would be nice if there was a way to differentiate static vs dynamic resolvers

quaint monolith
#

Also I could have sworn someone already wrote this plugin

boreal orchid
#

One could do it naively by checking whether it is a WithoutArguments resolver but that wouldn’t cover resolvers with arguments which can be verified at compile time (i.e primitives) or just a tag resolver without argument that uses runtime information

quaint monolith
boreal orchid
#

Doesn’t seem like it was ever released on the jetbrains marketplace and the repository hasn’t had any commits in a year so I’d assume it is dead

quaint monolith
#

It was released but yeah it's dead, 2024.1

marsh oar
cloud vapor
marsh oar
#

How is then the permission Assignment working ?

boreal orchid
marsh oar
#

I want to use the Permission Checker for a Minestom implementation of LuckPerms and want to know how I can control it in the end.

#

I already saw that Velocity does that. The thing is, I can't change anything directly in Minestom, but have to build on my own code.

boreal orchid
marsh oar
#

Yes every use need to implement by it self

boreal orchid
#

Using the PermissionChecker object requires that the implementation expose it on its Pointers object, but I doubt Minestom interfaces with adventure at all to begin with

marsh oar
#

The interface is in use but developers can override the pointers in there implementation

boreal orchid
#

Nothing much you can do about that

#

If the developers don’t provide the pointer when creating new entities or whatever, there’s no (sane) way to inject it there forcefully

#

Bukkit does this by making every Entity a CommandSender which is Permissible by default

marsh oar
boreal orchid
#

So they’re just missing the permission part

marsh oar
#

Yes

boreal orchid
#

Well, PR it to Minestom and hope for the best lol

marsh oar
#

They removed its now on developers side to implement in there App it self

boreal orchid
#

Without the concept of permissions, only other choice is to have LP User wrap the entities in a similar fashion adventure platform wraps spigot entities as audiences

marsh oar
#

But maybe I found the solution

boreal orchid
#

Do share, I am curious as to how it’d even work Minestom being a platform mostly for forking off and all

marsh oar
#
public class TitanPlayer extends Player implements PermissionChecker {

    private final @NotNull Pointers pointers = TitanPlayer.super.pointers().toBuilder()
            .withDynamic(PermissionChecker.POINTER, this::getPermissionChecker)
            .build();

    private @NotNull PermissionChecker getPermissionChecker() {
        return this;
    }

    public TitanPlayer(PlayerConnection playerConnection, GameProfile gameProfile) {
        super(playerConnection, gameProfile);
    }

    @Override
    public Pointers pointers() {
        return super.pointers();
    }


    @Override
    public @NotNull TriState value(@NotNull String permission) {
        QueryOptions queryOptions = LuckPermsProvider.get().getContextManager().getQueryOptions(this);
        User user = LuckPermsProvider.get().getUserManager().getUser(this.getUuid());
        return CompatibilityUtil.convertTriState(user.getCachedData().getPermissionData(queryOptions).checkPermission(permission));
    }
}
#

Thats the soultion on Minestom side kekw

#

Or one possible way

#

This should be work but Minestom want only bit fat jar deployments. Means LuckPerms and everything else needs be shaded into the jar

#

@boreal orchid So far understandable ?

boreal orchid
marsh oar
#

I am not completely stupid kekw

marsh oar
summer comet
#

Hey guys, Does Component#appendNewline when passed into ItemStack#lore splits the into multiple lines?

runic onyx
#

No new lines do not work in lore, it is a list of components

summer comet
cloud vapor
#

do you need to do that? you can just get a list in your config file or w/e

#

it's much easier to start with a list

summer comet
#

Thats why it would be way easier to work with just a single Component or an object. Of course on my own wrapper I could already split it when someone calls appendNewLine ig but yeah just wanted to know if MiniMessage has something inbuilt for that as it would make everything much more simple!

cloud vapor
#

There is nothing in MiniMessage or adventure that provides tooling for splitting components as it is an incredibly complex problem that is much better solved with good design

boreal orchid
summer comet
#

I assume appendNewLine is just a basic text component with "\n"

#

I see there is a "children()" already that returns a list of components although not sure if i can use that

sweet hornet
#

You could try to get a working version, but I think you're overcomplicating the situation