#adventure-help
1 messages · Page 8 of 1
Depends on what you're doing with the component
if you feel like it, when it is hardcoded strings like these I personally don't see the point
yeah that's not really a message that a user could change
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
Okay, so the client understands the concept of Components?
Yes.
Ty
that's what you use everywhere for any formatted text, like in tellraw or book contents component
Adventure components and the actual ones in the server are not identical but it's the difference between public usable API and internal code
I thought no matter how presented in code, at the network layer it all flies as characters prefixed with § signs LMAO
There's a serializer internally to go to MC stuff to send off in packets
Nope, that ended with mc 1.6.4
any advantages creating a "big" component and send it all at once instead of multiple sendMessage...?
less packet headers I guess
If you're executing that code async, with a single component you're certain it will be shown grouped
Otherwise it may interlace with other messages send to the client at the same time
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
You wouldn't need to .trimIndent() if you placed correctly your closing quotes
I just do it out of use, but yeah
(Example I saw few days ago while playing on a server I'm sure some will recognize, where individual lines of 2 messages were interlaced)
This wouldn't have occurred if they sent one single multi-line component per message
lol, i will use .append for each line
.append works for components
yeah
in a MM string you'd have to use <br>
i could create a component for eachline
(and doesn't insert a newline, unless you call a .appendNewline())
this seems more smart
btw there are no problems concatenating strings the "old" way with MM right?
like here
wdym
concatenating strings together using + or ${}
there's nothing wrong with that, no
aaand what if $prefix is a component? how could I render it in the string?
As long as you don't use it to achieve something either:
- super complex
- already possible with MM
- or absolutely misleading for the user
it should be fine
😄
if prefix is a component then you'd have to use dynamic replacements
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
textOfChildren?
bruh
Ah, idk why I imagined something more complex lol
Maybe you could've slightly simplified it using LinearComponents#linear tho?
was that merged already
tbh I don't see how it would change anything
MiniMessage still cleaner
Not much, that would still be a mess lmao
I guess maybe statically importing NamedTextColors and TextDecorations would make it slightly less worse
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
No I don't think it'll work, your style for the header & footer propagates
welp, that's sad
So unless there's some form of "resetting" like legacy, the components will be better that linear
whats the right serializer for whatever format minecraft vanilla text strings have?
uuh generating a datapack jukebox_song.json and for the subtitle I needa component
I think?
Oh so json
You need JSON
ooh
(The GsonComponentSerializer)
You mean SNBT?
mojangson is for commands, although I guess it's called SNBT now?
but I guess I was wrong
There are places where components are given with SNBT, but in a file called "jukebox_song**.json**", I mean...
Check the wiki to be sure I guess
audience.getOrDefault(Identity.LOCALE, Plugin.translationManager.defaultLocale)
why getOrDefault can return null? it's called getOrDefault 😐
if it comes down to that format you'll have to do something really annoying for it
I miss calling it Mojangson
because the default can be null ig
I don't even see anything in the jukebox song definition that would take a component
but it's a constant
kotlin's !! and i'm done
tbf with you, I also believe it is quite dumb for getOrDefault to have a nullable default but alas
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
It makes sense because it is correctly annotated (and thus documented). It's Kotlin's fault for not seeing it
it does have a Contract
Oh so kotlin issue
@Contract("_, null -> null; _, !null -> !null") so if the second argument isn't null then the return value shouldn't be null either
Wait, that contract is wrong
I imagine that Plugin.translationManager.defaultLocale somehow is being seen as nullable to Kotlin
The first part of that contract is wrong
Is it? If the first value is null then it returns null no? Or am I reading that contract wrong
That contract says:
If the second argument is null, then this method always returns null
Clanker says Kotlin doesn't understand @Contract but I can't find anything from a person saying either way
(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)
Pointered::getOrDefault here's the javadoc for it if you're curious
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
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
must be a weird caching problem with my runPaper...
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)
Have you tested a minimal reproduction code with just that running, no other plugins, on a vanilla client?
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
If it's paper-related you'd want to test it on 1.21.8 not 1.20.4
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
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. 
should the fallback strings be hard-coded or have a fallback file (still have multiple translation files)?
If you make fallback dynamically, why making it fallback?
wdym?
i would need the fallback in case the user deletes a translation key
But if it’s dynamic, what would prevent the user from deleting that as well?
is boss bars with adventure natively in paper package or i have to implement antoher library to use components with boss bars
native
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
lore doesn't handle newlines
oh i see, thanks, is there any work-around i could use?
put them in your config as a list of components?
mhmm
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?
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
Ok thx
isn't that module used just for stuff that takes nbt like hover events, dialogs and the like
it's an impl of the nbt format
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)
sounds like a good PR opportunity
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
You would need to deserialise it to a component and then serialise it to a string
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?
and, how are you applying the tags?
(really, the way they're doing that sucks, they should be using the renderer)
Minimessage.deserialize(String, TagResolver.Builder().build())
I mean, where are you running that code
are you modifying the message directly in the event? are you using a custom renderer?
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
Well, that should work, as the component should have the parsed component in there
Well, no, because renderers can tweak messages
Since When does minimessage not use </bold> anymore?
Ah but its not in the code by default
It is possible to replace some text from the escape menu with something from Minimessage
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)
Yes I know it's with resourcepack, but how do I apply mini message?
But how come when I do:
<#00ff00><b>VIP</b><yellow>+<#00ff00>
It will still make the + bold?
Do I need to use some other code for this to add support for the closing tag?
You would need to look at the structure it produces
I've seen that there are people who can do it.
It's probably losing the unset due to its prioritising the nesting of the color, I'd guess
Seen people do what exactly?
Replace the ReturnGame text in the lang file with <font:minecraft:esc>Return To Game</font> but nothing is applied
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
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
And from what I saw I can use json in the lang files
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
(yes it indeed does. ChatRenderer gives the entire chat line (including the player's name) instead of just the message, which we don't want. ChatRenderer#render is also marked OverrideOnly further discouraging it's use)
if you wanted to be fancy, you could use a custom chat renderer that only returns the message on render, and make each channel an Audience that you'd use as viewer, then just call render on it with the channel list
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
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
Not sure what you mean
A way for one to not override the current chat renderer but add upon it
Doing that with the current API is kind of annoying
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
I’ll give a more clear use case of what I am talking about when I am home
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
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?
use Placeholder.unparsed
try Placeholder.parsed
👍
ty
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?
it's not a visual comparison, it's a data comparison
Okay, thats good enough for what i need haha, thanks :)
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
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
Which platform are you using?
The default one included in paperapi
So you are using Paper?
correct
Then just use player.playSound(sound), if you have both a player and a sound as you stated in your question?
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
No problem, at least it was easy to solve 😅
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"));
Placeholder.parsed(…)
That worked! Can't believe I haven't tested that one 😭 thanks!
also, there's a way to add placeholders when building the MiniMessage instance?
yes, using tags() method
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)) 
Why not using directly <> instead of replacing {}?
just preference
if you wanted to be fancy, you could probably make a MM instance which does the replacement on a pre-processor
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.
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
Currently I'm not adding my translator to the global translator to avoid having possible key conflicts with other plugins
Every translator has its own unique key itself, so this shouldn’t happen
we (me and others) had a bit of a convo about that #paper-dev message
that's a bit silly, just prefix every key with your plugin name if you really care
e.g. myplugin.menu.title
Also, aren’t keys namespaced specifically for this purpose, to avoid possible conflicts?
should I do that? or there's a better way?
translation keys are just strings
Oh no translation keys are just basic strings, mb
yeah if you want
Yeah just found that out
But this doesn’t mean you can’t do the same (add a namespace yourself)
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?
Yes
if I register the translations for a locale and then register again another translations for the same locale, do the translations gets overwrited?
also I do not understand the difference between: MiniMessage.builder().editTags() and MiniMessage.builder().tags()
The former keeps standard tags (and tags already registered on that builder instance), while the latter replaces them
Think "append" vs "set"
oh ok so my intuition was right 🙂
how does that work with minimessage?
<reset> doesn't seem to remove the italics in the lore
<!i>
How can I convert a String. (E.g. <red>test</red>) to a legacy string for example §ctest
minimessage -> component -> legacy
LegacyComponentSerializer.legacySection().serialize(-)?
yes
Out of curiosity. Why?
and all gradient colors will be removed?
It's requred to support bedrock forms.
Bedrock supports components??
no thats the problem
Oh no ok I got it
bedrock does support components, see the Text Component Format wiki
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
There is some questions over if the protocollib will keep the component stuff, but, there are alt legacy serialisers which support bedrocks "legacy+" format
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)
i saw that but does Component.decorationIfAbsent() remove the original styles?
the method name does not suggest that...
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
and how would i use it on myItemStack.displayName(myComponent)?
You would use it on myComponent
you would set the italic decoration to false to explictly disable that from the parent component
but i dont have any arguments to pass to it
myItemStack.displayName(myComponent.decorationIfAbsent(...))?
it takes arguments, I forget the specifics but you want to set the italic decoration to false
declaration: package: net.kyori.adventure.text.format, enum: TextDecoration
ok now I got it, I was struggling to understand the method arguments
displayName().decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE) for anyone else reading
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?
Can’t you update to latest Paper 1.21.8? 1.20.1 is quite outdated
that is like the last option updating for me with my system would break so much stuff
so if i can fix it without doing so that'd be amazing
I'd probably start by asking geyser how to mitigate that issue. Protocol shenanigans are shenanigans.
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
works perfectly fine for me
probably just busted indexes or something stupid
yeah
@last horizon can you try it like my example? Maybe it has something to do with the previous map call?
sometimes it works sometimes it doesnt
the code compiles and runs
the map call is irrelevant
it just cant find Component#text(String)
but only inside lambdas
but like in every project?
god knows, aventure has 0 control over your IDE derping out
maybe plugins or a idea bug
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
have you tried binary-searching the issue in your intellij plugins? or using the repair ide mechanism?
this is beyond #adventure-help tbh
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
also happens on a clean ide install without plugins
just tried it but now i cant reproduce it at all anymore 😄
i love how random ij is
Isn't there an example on the docs?
yes, there is https://docs.advntr.dev/platform/bukkit.html
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
you can't outright override them, no. You could use a custom Translator which takes from the default if UserTranslatorStore#canTranslate returns TriState.FALSE
😭
do i have any alternatives?
i'm using the MiniMessage translation store
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
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
yeah, that should do it
but eventually the minimessage translation stores would need a key, so i'll have a total of 3 keys right?
wdym
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
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
and is that used somewhere? or just useful during debugging?
the key is more for you to identify them, adventure doesn't use them for anything internally
so i could use an empty string for the minimessage ones
there's no reason to do that really. Just call them something apropriate
okok
i.e. myplugin:user_translations, myplugin:default_translations
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
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())
}
yeah, was already "translating" to kotlin lol
what's the hasAnyTranslations method for?
i guess to skip having to search thru empty translators?
You could probably just make it return TriState.TRUE given default translations should always exist but eh
that's also true
and what about reloading translations?
i have to recreate all 3 stores?
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
it's used in the global translator to identify them in the hash set
so I guess in this case UserProvidedTranslator needs to have a unique key, but for the "inner" ones it doesn't really matter
probably should put that in a paste
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)
}
yeah, but using canTranslate is probably better
but I just realized this approach doesn't work
why? I tried it and it seems to work
I mean the reload part, adventure doesn't expose the translations map
i came up with an another solution
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
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()
}
yeah, that looks good to me
to me too
@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
bruh
title: "tips for using adventure translation system"
body: don't
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?
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
That will set the italic decoration to false if it's not already on there
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
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
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 🙂
why not use MM's dynamic replacement?
also you can do <!italic> or <!i> to set italics to false
Yeah you are right, I might change it later
Would I then have to add the infront of each row in the lore?
Yeah I am not a fan of that
why not?
Its not that user friendly if other people will configure it
its a bit annoying for lore tbf with you having to add it for every line
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
well I mean, then add the false flag programatically
yes, that's what they're doing lol
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
how are you sending the message? the url having single quotes there is incorrect ('https://...')
got it. i thought it was related to the error formatting not the actual string
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?
you need to use a Placeholder.parsed for that stuff iirc
oh cool thanks. Does that seem off that it was working in 1.21.4 using Placeholder.unparsed
urls in click events are more strictly enforced since some recent version
(it's a Mojang change)
how do i use MiniMessage's Format#date when using Component#translatable?
what do you mean
like, a placeholder which has a date?
wait wait i'm figuring that out right now, maybe using Argument#tagResolver
yeah, that should work
Formatter.date("date", LocalDateTime.now(ZoneId.systemDefault()
wanted to use that btw
what's different between Argument#tag and Argument#tagResolver?
tag is a convenience method for tagResolver
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()))
TagResolvers as it name implies, resolves Tags. Tag is an object which holds the logic for a given tag
<white><hover:show_text:"<timestamp:'MM/dd/yyyy hh:mm:ss a'>"><relative-time></hover></white>.
did i wrote that correctly? becase the hover placeholder doesn't render
hello, i can get help here?
if it is about Adventure, yes. If it is about Paper then you can use #paper-help or #paper-dev for plugin development
no i need about plugin
then try your luck in #paper-help
thank you so much
hold on, @spark relic are you trying to write a MiniMessage string in a config or somewhere?
if not do what Javier said, otherwise ask here
Honestly not sure, does MM even support quoting like that?
it should?
I don't know if it's a mimimessage because I just learned how to do it recently.
pretty sure it does
but i will say the problem if it is not then you say it i will delete it
use Placeholder.parsed
where?
i'm using this rn
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>.
the problem is that i want to customize the date format with mm
?
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?
it won't parse them because it considers them arguments not part of the string to parse
they want to customize the date time format with the argument like they were doing
they can?
as I said, MM literally does exactly what I wrote
but this way you ensure the tag is pre processed
they mean that they want to customize the date time format inside of the MM string, not on the code
why?
localization? Lol
I believe they want to give the freedom to the user to customize the date time format however they want
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
what does that?
I combined parsed and Formatter.date
do I need to change anything in my MM string?
i'm trying that
aand it does not seem to work
thought so
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>
where does it seem to error out?
i do not get any type of errors, the placeholder is just not parsed
can you log the format argument?
[14:23:54 INFO]: MM/dd/yyyy hh:mm:ss a
(i don't know why but the method gets called 6 times)
log the result of Tag.preProcessParsed(DateTimeFormatter.ofPattern(format).format(time))
hmm i'm not getting any output
val test = Tag.preProcessParsed(DateTimeFormatter.ofPattern(format).format(time))
println(test.value())
like if the print was not called
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)
it seems your formatter is failing
debug that first
you mean the datetimeformatter?
yes
got this:
java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: MonthOfYear
The temporal type you provided doesn't support getting the month of the year
I provided an instant (from a Date) object
Yea, and apparently an instant doesn't support that
just pass a LocalDateTime
then use a ZonedDateTime
no
oh, so that would be server defined and every user would see the same time?
correct
that's not the greatest thing
just use UTC
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
I don't trust Locale as a Locale's country can have more than one timezone, namely USA and China
Generally, people go down the route of just using the "server's time" as a grounding
I use UTC since most people know how to calculate their time from that
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
so using the system default wouldn't be too much of a problem?
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)
this is wrong
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
and what tz would an Instant use?
an option for the timezone?
yes
i don't understand what you mean
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
what's different between LocalDateTime and ZonedDateTime?
oh okok
LDT doesn't have any bounding to a timezone and is so somewhat "floaty"
ZonedDateTime is aware of timezones
got it
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
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.
Where do I uninstall it? I'm not sure how I got it to begin with.
Basically, you cannot mix legacy(&/§) format with MiniMessage(<>)
As mentioned, I'm not sure where I would even change that as I didn't intentionally install it
Is this in relation to a plugin you're developing?
No, its Essentials X
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
they sent me here dawg cause its your library
they sent me here
Doesn't look like it to me.
man whys the error spamming about yalls shit then
Because EssX is using our stuff, because it would be silly to reinvent it. Follow up in the EssX support channel for additional help with EssX.
how do I check if a component is empty?
doesn't seems to
You can even use == because the same Component.empty() instance is returned every time
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
I mean, it definitely works I can tell you that :')
so why i'm getting that output? like if the translations don't exists?
How are you filling it up?
with this: customStore.registerAll(locale, file.toPath(), false)
i really can't explain to myself why it was working
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?)
\ works, yes
Depending on what you wanna do, you can use the util method provided on MiniMessage or you should use unparsed placeholders
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)
then you should use the escaping method in the MiniMessage instance yeah
thank you
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);
}
}
How can I do this ?
For now if the client's locale is not French English or Spanish it just returns itwillbreak.about_to_break instead of English
did you set the default locale on the translation store?
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 ?
TranslationStore#defaultLocale(Locale)
It works tysm
how can i debug the parsing and the registration of my translations from a .properties file when using TranslationStore#registerAll?
what do you mean by debugging
since yesterday my store does not register translations anymore
and i don't know why
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
what's your code
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
are you sure the fileNameRegex is being met
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
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
yes i am using run-task
then you can just click the debug button on the run configuration generated by IntelliJ for the runServer task
and add breakpoints on the registerAll call?
sure, or wherever might make sense
you can just step in afterwards to check whether it is getting properly filled with the data
well i don't really know since i don't also know what's the problem here
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
are you familiar with debuggers?
it's not loading the translations
no i'm not, didn't you see the println? lol
i never went beyond breakpoints
you have to step in in order for the code to keep running
yes and i'm doing that
the code on that line has not executed yet
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
can you check that the resource bundle isn't null?
file.toPath() is a valid file that intellij let me open
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
hmm
so, i'm again here
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
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
which one?
just click "step into" on the debugger panel
oh that was easy lol
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
from the try condition i got "redirected" on the catch
readers are buffered, until it's read the temp char buffer will be empty
but i can't see anywhere if there's an exception
that is adventure code
i though that the debugger would let me see the exception
it should, just step in one more time
can you not copy that block of code into your own plugin for testing?
wdym?
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
inb4 it is about using the wrong path separator
bruh i have to rewrite it cause it's java
Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8).use { reader ->
customStore.registerAll(locale, PropertyResourceBundle(reader), false);
}
or something along these lines
JB literally supports transforming it as you paste it
really? never happened before
I forget it does that, it is quite nice
it does as long as you copy-paste code from within the IDE
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) ~[?:?]
why is input length 1
generally encoding issues
you'd change the Charset used to load the file Reader
Well, java only recentlyish added support for unicode property files
or use an external file editor to change the file's encoding
intellij won't change it back then?
idk
so maybe would it be easier to create my register method that creates loads the resource bundle using the ISO encoding?
there are just 2 lines
@serene hare
in intellij you have to change the properties encoding separately
thats the most stupid option ever but it exists
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
so maybe would it be easier to create my register method that creates loads the resource bundle using the ISO encoding?
or just changing the encoding LOL
you can probably just use Adventure's UTF8ResourceControl to load it
i mean, if the thing takes a Reader then the encoding is already taken care of by the Reader
what's the best option of the 3 then?
fix the file encoding
just change the encoding and be happy
yeah i think too
otherwise you just make it a headache to deal with when you start actually using unicode
btw thats only how intellij encodes the file when saving
how you handle it in code is a different story
yeah sure
I wonder why adventure itself doesn't use the UTF8ResourceBundleControl even though it suggests using it on its methods
apparently it is the JDK being funny about it
yes but if you pass a Reader there is nothing to decode with a charset, it's already decoded
? The reader doesn't decode anything until read is called somewhere
yes, but it is the reader's job to decode with the given charset, not the Properties
The buffered reader does if you ask it to
It's reading a char array, not a raw byte stream
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
thanks so much guys, it has finally loaded the translations
btw a little 🖕 to jetbrains
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
After updating to 1.21.8, clickevents containing a callback are trying to execute an unknown command. Any solutions?
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()
what platform?
what do you mean by "empty"?
no/blank text
but you can't know that until resolving it on both the server and the client
UniverseSpigot
can't i resolve it on the server before and check for the value?
yeah sure if you want
do i need to use render?
never heard of that before, you'll have to be more specific
yes
oh that was the missing step i forgot about
hmm
instead can i know if a key exists or not?
without rendering the component?
you can just check canTranslate on the global translator, but bear in mind that won't check for client translations
got it, i don't care about client translations because i'm checking for server ones
think of it as yatopia but as a paid subscription and obviously closed source
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
I think they make you re-buy on every major release or something?
yes its like 30 bucks or something to update
and people pay for that
I should make myself a fork like that, dude is a genius
just claim 99% more performance
while breaking 99% of compatibility
Bro that aint even necessary you just change change the server brand and sell paper builds to people
Why bother changing the brand?
I've seen companies selling access open-source services, and even worse i've seen people paying for them
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
MiniMessage (similarly to legacy codes) is just an encoding
Once properly converted to component, the result is undistinguishable
Got it, so I say in my case, the way to guarantee results it work with end results, such as ItemStack, BaseComponent, etc?
The issue is converting back from component to legacy. Components have features which are not supported by legacy, resulting in a loss of data
(However legacy codes cannot represent every component, unlike MiniMessage)
^^
Yeah i mean, legacy codes is mainly for colors
Is a simplification of the color system
format i would say
Fonts, for example, would be lost
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")
It would get lost, yes
Your itemstack's name or lore could contains custom font, that would get lost in legacy
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
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
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
Yeah I mean, I'm asking what alternatives do i have, even if with MiniMessage to avoid this and that doesn't require major changes such as:
- Use Paper (even if is good, not really an option on my case)
- 100% rely on MiniMessage (would force me to revamp several components which is not what i intend to do)
I mean, the whole point to support Nexo etc is to indeed allow that lol
your options are literally just use nms or the hope and pray method
Or don't use legacy, lol
yep
I just told why I can't rely on 100% MiniMessage 
Thats not really an option for me at this moment
Hope and pray method sounds tempting but I'm gonna pass on that one lol
Does MiniMessage has a replace tool or something?
it doesn't matter, the second you call getDisplayName you've already lost fonts, sprites, heads, translatable components, etc
again, there are some borderline stuff i can do with MiniMessage, such as replacing placeholders, etc..
They are mainly to be displayed. I assume they get "displayable" tho?
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
no, they are just pure legacy text that strips out everything apart from colour and styling
So if i wanted to use MiniMessage, what options do i have when it comes to replacing placeholders / injecting new line without breaking anything?
You can serialize to legacy using MiniMessage, but again you'll just lose everything apart from colour and styling
Nono, i don't mean serializing to legacy, I mean replacing placeholders on an ItemStack that was generated with MiniMessage
and atp you have only the item stack?
Does spigot expose you components?
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)
I assume BaseComponent[]? Why
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
So after an ItemStack is builded, there is no easy way to replace placeholders, thats what you're saying? 
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
Okay, explaining what I'm doing so it makes it more easy.
I have a crate preview menu.
On the displayed item it will usually appear:
Display name: (Gets the display name of the item)
Lore:
- (actual lore of the item)
- ""
- Percetnage: %cool_placeholder%
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
ive already told you how you can do it if you want to do it the bad way
Alright thanks
Hey, quick question about this, how can i convert from basecomponent to json exactly? Can't seem to find anything related to that
like i said we might have a serializer in adventure-platform but idk
Founded for anyone else wondering adventure-text-serializer-bungeecord (snapshot builds)
So this actually converts from BaseComponent[] to Adventure Component, hopefully nothing breaks lol
Assuming BaseComponent[] is correct, adventure’s Component are so nothing would break
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
iirc you need to use some Paper specific item builder from it
Yeah the second I post to find help, I find a github issue which specifies the issue lmao https://github.com/TriumphTeam/triumph-gui/issues/150
Thanks anyway :)
omg that's me

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>
Is there something bad pre-rendering the TranslatableComponent on the server before sending them to the client?
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
i use it to check if the translated message is empty and do things based on that
The "copy to clipboard" can only contains raw text, so you need to use Tag.parsed (and maybe quote the argument as well)
thanks!
I tried also with Paper, same problem
got any more than a badly cropped screenshot?
click callbacks don't make commands like that so
But they used to, I think he's just on an outdated version
Tried right now with Paper 1.21.8 Build #60
no they didn't, they were paper:callback <uuid>
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.
and paper 1.21.8 doesn't even use click callbacks anymore so nothing to do with paper either
Yes, that's the command
vv_uuid with no prefix is not the paper command
Oh I guess I got baited by how his screenshot was cropped, and I thought it was missing the beginning
Yeah, it's /vv_uuid
in fact the vv makes it seem like a viaversion thing but if they say it isn't them then ig so
This is what we don't understand
either way, not paper - check for other protocol hacks that may be malforming your click callbacks or custom click event packets
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..)
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
First question, are you going to change your name from GPT-6 to 7 when GPT-6 actually releases? 🤓 Secondly, as I'm a newbie on this and you prob know better than me on this, is there any place I can find more about Paper API specific methods, when it comes to ItemStack?
no idea if I'm going to change the name lmao
I personally doubt OpenAI will live that long but ¯_(ツ)_/¯
declaration: package: org.bukkit.inventory, class: ItemStack
as for the API: the docs.papermc.io pages have some information about paper-specific stuff
lol what?
thx man
bubbles tend to burst violently
Also how does Paper work internally? Does it save into Component (NMS) or internally it always preserves the adventure Component?
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
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)
I guess if you really want to know what Paper is doing, you can just look at the source code: https://github.com/PaperMC/Paper/blob/main/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
Alright, thanks man
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
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
At least it is a good reason for your customers to switch to Paper ¯_(ツ)_/¯
Yeah lol, I mean personally I don't see why would people stay on Spigot you know
But I don't make those rules so 
Anyway, thanks yall
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.
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)
Did you tried audience.showBossBar(bossBar) instead?
Could you check your audience (by sending a message for example) to make sure you actually have the expected player(s) inside?
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?
Idk, i guess it's up to the platform?
world is already a forwarding audience
In Paper, but which platform is he using?
i mean they seem to already be calling ForwardingAudience#audiences
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
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)
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
I just update it manually rn and it works thanks for everyones help
how do we remove italic by default for names, etc in adventure?
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
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
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
are you having performance issues when using MiniMessage?
yeah this is not true lol
You're always gonna have worse performance using replaceText than starting from scratch with minimessage
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?
Don't use %itemname% but <itemname> and use a dynamic replacement tag
here's an example of the above MiniMessage.miniMessage().deserialize("<item_name>", Placeholder.component("item_name", item.effectiveName()))
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?
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)
i see
So yes, the range on the pitch is wrong, but on the volume it’s good
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.
The .tags call resets the tags fully. You'd want to do ```
.tags(TagResolver.resolver(
TagResolver.standard(),
PlayerTag.playerTag()
))
Thank you :)
The correct way to create gradients was <gradient:#fffffff:#ffffff>text</gradient> right? because it doesn't get parsed
too much f's
Yeah i just wrote them here, i have correct hex colors in my code
send the actual mm text
https://docs.advntr.dev/minimessage/format.html#gradient - it is the right way yeah
Whoops i had a problem in my parser, my bad
hey, when creating a Sound.sound() it will automatically know if it is a sound event or a sound name?
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
nope
But would it be possible to brute force the seeds to make it possible
Isn't it fully client-side?
I think the wiki has a seeds list?
No you can provide a seed
Really, where?
I couldn't find one
i must be imagining bc i cant find it
I don't think it's that hard to brute force them using smth like cupy
Where?
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);
Sound.sound().seed(728) ....
Interesting, I've never noticed that method before. Thx
I think this is the correct one for 1.21.5 with seeds ( i tried a few and they match)
music.json by @undone obsidian: https://pastes.dev/cPubOhf5Ew
But i dont think it will work for other versions as it matters how many sounds in a event exist
I heard there is pointer for permissions inside. How can I use it from Adventure or in general how works the point in adventure
basic example would be
var hasPermission = audience.getOrDefault(PermissionChecker.POINTER, PermissionChecker.always(TriState.FALSE)).test("my.permission")
if (hasPermission) {
...
}
Is there any way I can get the ParsingException(s) from parsing an MM string?
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?
What is your goal?
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
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?
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
Checking anything other than syntax would require compiling and running arbitrary pieces of plugins to get their MM customizations
plus technically plugins could have their tags' formats vary dependent on info you'd only have during runtime, right?
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
would be nice if there was a way to differentiate static vs dynamic resolvers
Also I could have sworn someone already wrote this plugin
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
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
It was released but yeah it's dead, 2024.1
How can I register a Pointer in a Audience Object ?
You can't
How is then the permission Assignment working ?
Wdym?
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.
I don’t think Minestom has anything permission related, does it?
Yes every use need to implement by it self
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
The interface is in use but developers can override the pointers in there implementation
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
Every player and console sender is CommandSender in Minestom and uses the Audience
So they’re just missing the permission part
Yes
Well, PR it to Minestom and hope for the best lol
They removed its now on developers side to implement in there App it self
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
But maybe I found the solution
Do share, I am curious as to how it’d even work Minestom being a platform mostly for forking off and all
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 
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
And here the minestom impl: https://github.com/TheMeinerLP/LuckPerms/tree/feature/minestom/minestom
@boreal orchid So far understandable ?
Yeah, I just thought you were trying to impl the pointer without making a custom Player impl which would’ve been harder lol
I am not completely stupid 
You're the master of stupidity, after all.
Hey guys, Does Component#appendNewline when passed into ItemStack#lore splits the into multiple lines?
No new lines do not work in lore, it is a list of components
Is there any way to convert from Component (that contains appendNewline) into a List<Component>?
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
Well, the problem is that this will not be just used as a basic operation such as "from config to ItemStack". I have a wrapper for cross compability, my own framework for several things such as translations, ingame editor etc..
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!
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
As long as you don’t mind style not being carried over, you can just split it yourself
I mean, I'm talking about basic appendNewLine, not components that contain \n inside.
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
You could try to get a working version, but I think you're overcomplicating the situation
