#adventure-help
1 messages · Page 7 of 1
is there a way to sanatize or remove all minimessage parts of a string?
Im trying to have a configurable chat format, and i want the chat format part to be able to use minimessage, but not let player inject their own
or maybe a way to like replace a string in a component with another
if you're using a minimessage placeholder for the user-provided bit of the format, there's a placeholder for text that shouldn't be parsed
declaration: package: net.kyori.adventure.text.minimessage.tag.resolver, class: Placeholder
Seconding the use of Placeholder.unparsed, because that would more directly call them out when their message shows up with all the mm stuff in it 😆
is there a reason the adventure webui doesn't use the actual font minecraft uses? it has some notable differences and many missing characters as it uses an unofficial recreation
the minecraft website uses fonts by the foundry canada type, they are more accurate to the in-game font as far as i can tell, ideally it would be exactly as displayed in game though with all characters supported
in the client jar, assets/minecraft/textures/font has .pngs containing each glyph used in game
Because it's their property
The font we use is some free dupe
it's MIT actually https://github.com/Mojang/web-theme-bootstrap/tree/main/assets%2Ffonts
Contains the theme used on minecraft.net based on Boostrap 4 - Mojang/web-theme-bootstrap
and the fallback font is just unifont
or, atleast the repo is MIT except for the images
The mojang font is unlikely to be MIT and is covered under their brand guidelines, etc, iirc
Haven't seen those before, but if they are the same as the in-game fonts, feel free to submit a PR to change webui to use those but ensure you follow the license!
assets included in a repo and their licensing is often a weird area
idk if there is a general expectation that the license of the repo would apply to all assets, especially when brand guidelines exist, etc
it's got a SIL license in the folder
although yeah the ofl was added alongside the notosans fonts
From the Noto Sans PR
so probably not
no clarification so lets assume that they aren't just allowing everyone to use their fonts for free lmao https://github.com/Mojang/web-theme-bootstrap/issues/52
default license also states
All image assets of this project are copyrighted by Mojang Studios and may not be used outside this project without permission by Mojang Studios.
Just to share my personal opinion:
I don’t think this is worth messing with all those licensing questions when the current font is more than acceptable for the need of the current viewer, which is to preview the formatting of a MM string
I've bumped them a nod to improve the clarification, but, it's generally fairly clear from all of their documentation and such that those assets are probably not ours to take
question: is there any way to handle plurals in translatable components?
for example, let's say i have a string such as You have <count> coins.
the way i18next handles this is it adds suffixes to keys. in English, that'd be _one and _other, for example:
_one => You have {count} coin. // 1 coin
_other => You have {count} coins. // 2 coins
in Polish, there's _one, _few and _many, for example:
_one => Masz {count} monetę. // 1 coin
_few => Masz {count} monety. // 2 coins
_many => Masz {count} monet. // 5 coins
does Adventure support this? right now i'm just assuming the _many case for PL
No, that would be on the translator to deal with
and the default translators don't provide such a feature, at least afaik
MiniMessage has a choice format tag if you're using that
i see
idk if im using this correctly 😅
Component.translatable(
"commands.warnings.some.other",
Argument.string("player", target.name),
Argument.numeric("count", warnings.size),
Argument.tagResolver(Formatter.choice("choice", warnings.size))
)
Might need the single quotes? ' in the example and you have ".
Not sure though, just noticed that
oh true
yeah I think so, if choice is similar to booleanChoice you could also just pass them as multiple arguments
wait i have single quotes in my properties file tho
e.g. <choice:'choice1':'choice2':'choice3'>, not sure if this works tho
Hey, just a quick question: this should work correctly, replacing the <placeholder>?
MiniMessage MM = MiniMessage.miniMessage();
Component source = Component.text("<placeholder>");
String serialized = MM.serialize(source);
Component output = MM.deserialize(serialized, Placeholder.unparsed("placeholder", "something"); // -> something
I'm asking because it's some kind of magic and it doesn't work or I'm not aware about some stuff.
serialize will escape the <>
Hm yeah, it returns \<placeholder>
Сan I get around this without replacing escape chars? Or can I replace placeholders inside a component without serializing it?
I have a TranslationStore that I use to fetch a message in the specified language. Messages may contain placeholders that need to be replaced. I’m also using final components in the dialog created with the experimental Dialog API.
I tried using Component.translatable(…) when building the dialog, but they don’t resolve — what ends up on screen are the translation keys, not the actual strings.
So instead of that approach, I’m forced to obtain the component directly via TranslationStore#translate(TranslatableComponent, Locale) that returns Component.
declaration: package: net.kyori.adventure.translation, interface: Translator
I still don't know why you'd be having that issue - why aren't you using a MiniMessageTranslationStore?
Do you mean that they don’t resolve in dialogs? I’m actually using MiniMessageTranslationStore.
No I mean why are you doing this - why is your placeholder inside a component to begin with
Like you can just manually translate a component with your store, or even via the GlobalTranslator if you've registered it there
Ah, do you mean that I should call TranslationStore.translate(...) with Component.translatable(...), where I specify the argument resolvers?
translationStore.translate(Component.translatable("message.key", Argument.string("placeholder", "value")), Locale.ENGLISH);
Yep
Looks and works well, thank you
does Component.replaceText return a new object or just the mutated copy
in other words, should i do component = component.replaceText or just component.replaceText without the reassignment
components are immutable, so you'd need to reassign it (the first one)
sender.sendRichMessage("<yellow><click:run_command:/trade accept <player_name>>")```
can I use tagResolver to replace `<player_name>` with a string?
Yes, take a look at dynamic replacements: https://docs.advntr.dev/minimessage/dynamic-replacements.html
oh wait, this is inside of a run command, I don't think it works then
You need to quote the command as an argument of click (i.e. <click:run_command:'/trade accept <player_name>'>), and use the Placeholder#parsed tag resolver
I think click only passes along the string value and doesn't do any deserializing like hover
but just try and see I guess
Yes, but Placeholder#parsed tag resolvers are resolved first
I see, makes sense
If I'm using for example the MiniMessage translator for my plugin messages, are there any limitations to what tag resolvers I can use there + can I use translations inside translations there?
no limitations - nested translations should work fine too
Great! And thanks for the quick response!
🫡
the global translator still can't resolve named arguments, iirc?
nope, you can even throw entirely cusotm tags in it https://docs.advntr.dev/minimessage/translator.html#using-a-minimessage-translator
we love virtual components here
unless there's a change elsewhere that i've missed, virtual components (and thus, named arguments) do not get passed through the global translator:
https://github.com/KyoriPowered/adventure/blob/main/4/api/src/main/java/net/kyori/adventure/text/renderer/TranslatableComponentRenderer.java#L202
hm that if statement seems rather silly, why would we need to filter those out?
also this is why we have a github issues tracker, if you find issues let us know so we can fix them :p
first im ever hearing of custom arguments not working with a minimessage translator specifically in the global renderer
to be clear, I noted this: https://github.com/KyoriPowered/adventure/pull/1226#issuecomment-2851381860
This is an attempt at fixing #1157.
Currently, it renders translation arguments & children components twice when using MessageFormat translations - not exactly sure on the best approach for...
im kinda struggling to understand why filtering is even done there
that if statement is present because it'd otherwise just collapse the virtual component to an empty component in the renderer
I know you all do this on your free time and all, so no worries if you cant right now, but seeing as there's just been a couple of PR merges & a release - is there a chance you could take a look at my Adventure NBT PRs? would be really helpful if these could get merged/looked at
yeah they're on my list for 4.25
well no, they'd get caught by the virtaul check which just returns itself right?
look at the virtual check - it doesn't return
oh i see, that doesn't chain
see now im really trying to work out why we're even doing that
like you have to be very specific to leave virtual components lying about, why are we even getting in the way of them here
what exactly do you mean by that?
Hi, I am not sure if this belongs here or in the velocity chat.
I am sending a component to a player like this
source.sendMessage(LegacyComponentSerializer.builder()
.extractUrls()
.character('§')
.hexColors()
.build()
.deserialize("Discord: <https://discord.cloudnetservice.eu/>"));
once the 1.21.8 client receives it the client disconnects
Caused by: io.netty.handler.codec.DecoderException: Failed to decode: Illegal character in path at index 35: https://discord.cloudnetservice.eu/> {extra:[{click_event:{action:"open_url",url:"https://discord.cloudnetservice.eu/>"},text:"https://discord.cloudnetservice.eu/>"}],text:"Discord: <"}
I am using Velocity 3.4.0-SNAPSHOT (git-81deb1ff-b521) (please ping on response)
I saw a similar stack trace on my Paper dev server a few days ago, so this is not Velocity-specific I guess
that error is just from constructing a URI from https://discord.cloudnetservice.eu/>, because of that >
so i assume it's an issue with whatever regex is used for the #extractUrls
the regex is (?:(https?)://)?([-\w_.]+\.\w{2,})(/\S*)?
Feel free to open an issue, or even better a PR!
Although in this example idk why you don't just make the component manually
Is there anywhere i can see discussion or a wip pr for dialog support?
anything that exists is in these channels or on github
the consensus for now though is I think we're just letting dialogs mature for a version or two
let things stabilize before we try and build some sort of api in adventure
For now the advice is to use registry ?
Yes
I have a Placeholder.unparsed tag resolver that I am using on MiniMessage deserialize. It parses like normal in the chat, but it does not replace in my copy to clipboard. <click:copy_to_clipboard:'{{:<title>}}'>
Copy to clipboard is just text, so you need to use a pre parsed placeholder
what fonts are supported by minimessage?
i want to use small caps font: https://www.piliapp.com/cool-text/small-caps/
Fonts are client-side, so beside the few vanilla ones, if you want to use one, you must ship it into the resource pack you send to your players
okay
small caps is not a font
However, there are some Unicode characters that mimics the small caps, if you want to use them without a font and thus without a resource pack
its just different unicode characters that kinda look like the latin ones, but its horrible for accessibility and I just closed a PR for minimessage yesterday adding support for that since we dont want to promote bad accessibility
well the thing is, in my scoreboard there are placeholders, and they are using standard font for minecraft, and i want to replace it with small caps
Then my initial message applies
however, if you wanna screw over people with bad sight (they will not be able to read stuff since the announcer ignores these characters) you can copy the tag from here https://github.com/KyoriPowered/adventure/pull/1274
I think it's quite readable.
and pretty much 95% of czechoslovak servers use small caps
Not by screen readers or the narrator. You should instead find a font to use that emulates it
Will also be easier to use as you can simply just set the font
ill look on it
https://chevyray.itch.io/pixel-font-beaver is probably what you want
thanks sm
i installed it into resourcepack, how should i put it in scoreboard?
you'd want to change the font of the component on the scoreboard to that font
if you're using mini message use the font tag, otherwise something like Component#font(Key)
hii all! is there anyway to prevent the "parent" translatablecomponent to not pass its style to the args without changing the style of each arg?
no
I tried to modify the number while keeping the colors and formats. How can I do that?
private void modifyAttribute(List<Component> lore, Component component, String key, int i) {
Component newLore = component.replaceText(builder ->
builder.match(key + "[::] (\\d+)")
.replacement((matchResult, textBuilder) -> {
String colon = matchResult.group(0).substring(key.length(), key.length() + 1);
int num = Integer.parseInt(matchResult.group(1)) + blueprint.getUpgrades().getAttributeValue(key);
return Component.text(key + colon + " " + num);
})
);
lore.set(i, newLore);
}
I'm now using the code above, but obviously it can only replace texts when they are together without different colors or formats
Correct, that's just how it works
I'd suggest recreating the component from scratch, no reason to be doing replacements like this for such a simple problem
I know this is probably asked a ton, but when you have a component that contains legacy section characters inside the text field itself, whats the best way to handle it? My specific issue is that the components are straight from bookMeta.pages().
Right now its parsing out to this on our website.
The best way to handle it is don't do that lol
Nothing should be giving you that either, so you must have some cursed setup to get books like that
does paper default prevent a section character being placed in a book?
No but unless you're creating the books with legacy formatting in a component it should be gracefully handled
I'm not familiar with how they are even placing them there.
That'd be the place to start
books with legacy inside of components are gonna cause lots of problems
Would a PR adding support for reading a builder's current values be accepted? running into a scenario where I'd have to build the entire component pre-maturely just to read some values (unless I'm blind and there's already a way to do that)
There's already some features like that (e.g. text component builders let you both get and set the content), but for most values it doesn't seem to be supported - would be nice if it could just implement StyleGetter there or something like that
What's the xy?
Migrating some stuff from Bungee chat to Adventure (finally :D), and places that just had a Bungee chat component and added children and such along the way now use a builder, which means a lot of the existing logic we have is going to be very annoying to update currently
I mean, what sort of scenarios are you in where you need to do that?
A custom component parser from back when there weren't really any better options - it's got a lot of logic to support edge-case parsing shenanigans, so I'd much rather just update it as-is and work on moving to MiniMessage now that there's better options out there, rather than give it a big rewrite and then work on switching
I can link you specific places if you want, but uh, it's big and a little hard to read through
Yeah ig I'm just looking for specific code examples of what behaviour you're missing, bc I can't really see what we actually need to add here
snippets/examples are fine
Mostly just StyleGetter stuff,
var builder = Component.text();
builder.decoration(TextDecoration.BOLD, true)
// Someplace else
if (builder.decoration(TextDecoration.BOLD) == TextDecoration.State.TRUE) {
// Checking the builder's value
}
One actual example would be this
private static void copyDecoration(TextDecoration decoration, StyleGetter origin, StyleSetter<?> destination, boolean minimize) {
TextDecoration.State state = origin.decoration(decoration);
if (state == TextDecoration.State.NOT_SET) {
return;
}
if (minimize && state == TextDecoration.State.FALSE) {
return;
}
destination.decoration(decoration, state);
}
public static TextComponent.Builder copyFormatToNewText(TextComponent.Builder last, boolean minimize) {
TextComponent.Builder toRet = Component.text();
Component lastBuilt = last.build();
copyDecoration(TextDecoration.OBFUSCATED, lastBuilt, toRet, minimize);
copyDecoration(TextDecoration.BOLD, lastBuilt, toRet, minimize);
copyDecoration(TextDecoration.STRIKETHROUGH, lastBuilt, toRet, minimize);
copyDecoration(TextDecoration.UNDERLINED, lastBuilt, toRet, minimize);
copyDecoration(TextDecoration.ITALIC, lastBuilt, toRet, minimize);
toRet.color(lastBuilt.color());
return toRet;
}
in that example couldn't you use decorationIfAbsent or one of the style merge strategies?
Am I missing something ;-;? all of these look like they would require building the component first to read the values (either getting the states for decorationIfAbsent, or getting the style for merging)
The logic for setting the decorations can maybe be cleaned up with adventure's extra API, but you'd still need to get the styling/decorations off of TextComponent.Builder last somehow as far as I can see
Ah actually I see what you're trying to do, I think you can just ignore all that and compact the component at the end
Yes the builders should be able to return the style too, feel free to open an issue but it's unlikely to get done soon as I'm trying to avoid big new features before Adventure 5.0
I still need to copy over the values at the very least though - if the last component is bold I need to set that onto the new builder
I can try opening a PR, it doesn't look too hard to do - just some getters for the already existing fields as far as I can see
Yeah it's mainly annoying rebases im trying to avoid, but feel free to!
I assume I need to override the JD and specify @since 4.25.0, but should I just copy over the entire JD? Or is
/**
* {@inheritDoc}
* @since 4.25.0
*/
fine?
So something like:
I don't see why that wouldn't be fine 
That's basically exactly what @inheritDoc is meant for
Just asking because some methods there say like, Sets the color of this component (not sure why it says component and not component builder actually)
Just be careful, sometimes the IntelliJ preview does not show the exact result of the JavaDoc tool. Maybe try to generate the JD once, to ensure it works properly
Yeah that too. Just give it a quick poke and check manually if it matches what you expect
-# I did not mean git push, that was just a metaphorical expression, mb if that sounded incorrect lol
Or the #insertion JD says Gets the string to be inserted when this stylable is shift-clicked. - styleable there is probably fine? but maybe I should override the JD to say component instead?
well, a component is stylable, no?
Yeah, I'm just asking because ^ some methods override the JD to explicitly say component
StyleGetter#insetion - Gets the string to be inserted when this stylable is shift-clicked.
Component#insertion - Gets the string to be inserted when this component is shift-clicked.
Imo I don't think it's that big a deal, but just making sure since it's already being done ^
Just an external point of view, it is perfectly fine for me to leave styleable, it's like when you have Entity#getId and Cat#getId, you won't override the JD just to say Gets the ID of this cat, it is fine to say Gets the ID of this entity because a cat is an entity
I need to do validation for sounds provided from users in config, I am using kyori adventure sound. What happens if a provided sound Key (minecraft:....) doesn't exists? Will an exception be thrown?
no, the packet will be sent anyway, sounds can exist solely in the client without the server knowing
<@&748618676189528155>
Handled @sweet hornet 
can this crash the client?
no
oh, hm, it might disconnect it
anyway, adventure itself does not provide an interface to validate a sound existing on the server (and a server can't know what sounds the client has), you'd need to fetch it from the registry in whatever platform you're using or just hope for the best
I wanted to do that, but I dont really want to enforce it, in case somebody is adding sounds via resourcepack, so this would force them to not be able to use those sounds
I mean, if the client crashes every time it receive a sound it doesn't know about, it seems to me like a strange design choice
it no ops (on the client)
i mean on the client
I like your name btw
thanks for helping guys
How would you do <!i> in Legacy?
Why?
Why? As far as I remember lores and names will otherwise be italic'ed?
Why legacy?
Because my clients don't want MiniMessage
and I'm not being paid enough to argue and educate them
i enjoy minimessage it's easy to work with
(sry if i sounded a bit annoying)
There's no real way to replicate the <!i> in legacy. The "best" (least worse) you can do is §r, but it's violent. If you're dealing with it in the code side, you can just component.decorationIfAbsent(ITALIC, false), but mixing legacy and components is really really really discouraged as it will lead to unexpected behaviours
Applying #decorationIfAbsent(...) to the root component won't change the underlying component's style will it?
If you're parsing the legacy codes with the legacy component deserializer, at least you should have a valid component tree at the end, and applying decorationIfAbsent should work
&aHello &iWorld (i forgot what's the italic thing)
Got it
But if your bundling the legacy codes inside a text component, then you're screwed (and I can't help you any further)
Bad idea
The two syntaxes differ in paradigms
Legacy codes are "linear", while MM is a tree-structure
And, since components are a tree structure, no need to tell you which one is the easiest to work with...
Yep
One more question! How would you close <#RRGGBB> tag?
</>?
</color>?
or do i have to do </#RRGGBB>?
It depends on how you opened it
<#rrggbb> must be closed by </#rrggbb>; <c:#rrggbb> by </c>; and so on
You can have <#rrggbb>, <c:#rrggbb>, <color:#rrggbb> or <colour:#rrggbb> all leading to the same result, but each one needs to be closed accordingly
And I think by far <c:#rrggbb> is the best for RGB colors, since it can be closed with </c> without repeating the color
For sure!
I prefer defining <coolcolor> as a hex color so I can </coolcolor>
That's also a nice option for a predefined color palette, sure
I let users define
How can I make a minimessage tag resolver that converts a component into another?
For example an align:center that calls my Component centerAlign(Component) method
You should take a look at the Modifying tag interface
So something like this
Huh, I don't think casting is enough... Oh well maybe, since it's a functional interface... I guess you can try it out. However, there is a particular handling of this tag that will cause its children to get duplicated if you do it like this. I think in your case, you are already handling the children inside your .centerAlign method, so you should only call it at depth == 0, and return an empty component otherwise (to discard the children that would get processed as well)
The casting thing is an IDE autosuggestion
"casting" like that is a hint to the compiler for lambdas
& Serializable 
why cant tags have spaces
Because that's how the syntax is defined 
Makes it easier to parse them
And also, it would be kinda annoying if this would get parsed as one large tag: ```xml
As we all know, 25 < 16. This is not true for 25 > 45.
For this reason, MM defines that a tag name cannot have spaces, and if it has a space, it will be treated as a string literal instead so that my example parses correctly.
makes sense
we were moving skript's components to adventure while keeping support for legacy tags but <dark red> became an issue
< & > 
teach that to users
how can u use this, in where?
I'm guessing here, but probably reading it from some config and then adding Placeholder.styling tag resolvers to a mini message instance
Yep!
im trying to use tag resolver but i get this
something in your build process is fucked up
the fqcn is missing all its dots/slashes
its working on 1.17
not in 1.16
if it was my build i would know it
oh so thats the thing
ive been using MM on 1.16
this seems like something stupidly trivial that im missing but,
header should have hover+click while message should continue with its own hover+click
but still retaining the color/decroation from the previous component
i have no clue how to go about this
What's your current output vs expected?
hmm thats interesting because i do infact override it in a certain situation and it does not act as such
there is nothing more to comment without seeing the rest of the tree
give me a second sorry im getting that now lol
take for example https://webui.advntr.dev/?x=HP4mfCBWBR
yeah this is why im confused
chucks the item in just fine
but the hover is retained
can you show some more code
all the little snippets make it hard to see what's fully going on
and if you can't share more, a little MRE is fine too
yeah i can give this
the component serializer in question
String.formatted and Component.asString are extension funcs to use the normal minimessage de(serializer)
you might wanna try and make an MRE, lots of moving parts there
what does debugging tell you? where is the hover getting lost?
didnt really do debugging, assumed it was just me being stupid and missing something give me a sec
hmm it is possible it has something to do with MiniMessage#deserialize(String) not reading item hover events?
because thats the only thing i could see as an issue thus far
idk, is it? what does your debugging tell you
it tells me theres no issue if i take the components at face value and its in the serialization
does the issue persist if you use the json serializer instead?
(which is purely using minimessage deserialize and serialize)
so debugging is telling you that you are sending the correct component to the client?
if so, then make sure you're on a vanilla client, check mods, etc
nah im saying that when i use my action system, it serializes the component, using the minimessage serializer, thats where it breaks
i am about to test with json serializer
that should work fine, but i would never use minimessage for over-the-wire serialization
yeah im a bit dumbfounded as to why our serializer uses minimessage when we use json serializer elsewhere but i digress
conclusion:
minimessage serializer appears to be a bit borked in terms of item hover events
but my original question was actually more, how do i stop the hover/click events from applying to the appended component without clearing the events from the component itself
please do open an issue about that!
will do
just append them both to an empty parent so they're siblings
but then comes the predicament of i want to keep the color and decoration! 😭
You unfortunately can't have both the butter and the money of the butter (idk if that saying translates well in english 😅)
is there not a way i can copy specific styling and prepend it to a component
Of course you can, but it's similar to unsetting the hover/click events imo
It's up to you about what approach you prefer
ig
sounds like what you want to have is
parent component (color)
-> child header (click/hover)
-> child message (click/hover)
yes indeed, but the color comes from the header sadly
They'd need to extract the color/decoration part of the style anyway
using Component#color would return the last color right?
iirc it just returns the color of the style of that component
No hierarchical operation performed
yep
Hello, is there any way to turn a component back into minimessage format?
Hopefully this is the right place to ask
no
says this?
I could be wrong tbh
Lemme see if there's anything obvious
actually there is a method to serialize
MiniMessage#serialize
I've never used it, worth giving a shot
If you don't know an answer please don't answer so firmly 🙂
thing is, I've seen this type of question before and remember kezz answering that it's not possible, my memory might be bad tho
Very bad. It's always been both ways.
Why does using <reset> not work on item lore or display names? (they stay italic unless I explicitly use italic:false)
because reset is a broken concept
it does work
its just that a tree child cant unset style a parent sets, only override it
and since for lores vanilla sets italic as parent, reset doesnt know that it needs to unset it
but if you control the full component it works
use can use <!i> as a shortcut btw
yes I know but like I said, I just don't think there's many usecases for that
oh thx
I dont disagree, we only added it because people kept demanding it
and for chat it works exactly as those legacy users expect
ok fair
what is the most direct way to set a list of children in a component?
Pretty sure that there is a Component method to do that?
I need a direct way. This children method somehow takes 20% of the execution time of the entire huge program
There isn't a direct way because of ComponentLike, but it should be fairly fast unless you're doing something crazy
can't really comment on perf reports I can't see
how do I use the new custom click type added in 1.21.6?
I tried specifying both arguments with or without quotes respectively and it doesn't work no matter what
this requires some more context, is this about minimessage (sice you're talking about quotes)?
I don't think you can send a custom click event with mm
yeah it only implements actions that require a simple string/integer
well custom requires 2 strings according to the mc wiki
so it shouldn't be that hard to implement
wait does ClickEvent.callback use the custom click type?
well I'm on paper soooo
what's the best way to get the player object from an audience?
check instanceof and cast
Please share the spark or profiler data!! We're always looking for ways to improve adventure!
ComponentBuilder solves my problem. Is it possible to create a builder from a component? It's not convenient to do it manually
Please share your profiling data so we can actually make improvements to the software you're using and complaining about
Unfortunately I can't
Awesome
Is there a way to instruct MM to prefer a tag name alias over the regular name on serialization?
(I.e. use <!i> instead of <!italic>)
I don't think so no
Hmm, and what do you think of this?
Is it something that would make sense for you?
I can explain a little bit more what led me to this, if you want
Alternatively, do you think a simple find-and-replace technique on the serialized string would work?
I mean, we don't really support "find and replace" type manipulation, though, it can be effective
I know, that's why I originally not choose that, but if that's the only possible way to do it, I may try
one day™ we can expose the serialization api
then you just do a custom serializable resolver
What's the xy tho?
yeah this would be helpful
I’m working on an in-game item editor, without mods (with dialogs). And as you can guess, all the components use the MM format, so they are easily editable for the end-user. For item name and lore, obviously most of the time the italic is unwanted, so I have an option to auto-apply .decorationIfAbsent(ITALIC, FALSE). But when the user edits the same item, it then show the <!italic> in front of every line (and this is completely normal, of course), so just to make that a little less cluttered, I wanted to use the shorter version <!i> instead
While writing this, I realised maybe the most logic way to handle this situation in my case would be to detect if all the lore lines have the italic set to false, then completely unset it before serialisation and enable by default my toggle for auto-italic, so it will be added back after deserialisation
Yeah what you said right here would make the most sense. Just unset the style override so it doesn't serialize anything and keep it separate from the rest
The problem is then for detecting italic when sometimes, for existing items, the component looks like this:
{ "extra": [ { "text": "...", "italic": false }, { "text": "...", "italic": false } ] }
Technically, the root component does not disable italic, BUT italic is effectively disabled at each child level. Of course, then the component is not really optimized, but unfortunately, some item creation websites are pretty bad at this... (I actually have many examples in our "itembase" like this)
I don't think Component#compact handle this
It would require "factorizing" the style to optimize the component (by pulling up common style from all children), which sounds possible, but would require more work
couldn't you just... mmString.replaceAll("<!italic>","<!i>")
ah wait that'd break if it was escaped
Component#compact optimizes the style of the component as if it was the root component (parent style is set to null). But in some context, it is not the case, and it could optimize further if it knew the parent style (mainly, in item's lore, the parent style being italic & dark purple). But there's no way to specify it, even when it is supported in the code (nor we can call directly ComponentCompaction.compact since it's a package-private class)
sounds like a good PR opportunity
Does this method works if server is offline-mode or the server has plugins like AntiPopup/Freedomchat or similars which messes with chat?
Im asking to understand if it safe to include in a public plugin. Would use it as a feature to cancel messages after they are sent in chat, (for example it they contains swears etc)
declaration: package: net.kyori.adventure.audience, interface: Audience
deleting messages only exist for signed messages
I would store them from the AsyncChatEvent
plugins that cancel chat and send system messages instead will break it :P
last option, which I wanted to avoid, was storing in a cache the last 100 messages, when one is cancelled, sending again them in order
Heya! Is there a recommended maximum setting for the nesting limit in the component flattener?
Currently seeing an issue where excessively nested components are able to cause havoc, stumbled across that option, and am now curious what you'd recommend :)
Paper has it set at 30
you could probably go lower, you can also override the default if you want to affect all flatteners created
Bad idea
User experience wise and idea wise
You can't track ALL messages so the chat won't be the same
Also client side messages exist and packets that send chat messages but aren't technically chat messages exist too
Yeah I know, I want to avoid a packet listener 1 due to NMS or 2 to avoid packetevents for just 1 feature.
I will try to play and see if it works with popular plugins like antipopup or freedomchat
note that delete message does not actually delete the message on the client
you get a "<Message deleted>" text instead, its sadly is not completely gone
So if you want to replay chat or similar, the only way of truly clearing it is still spamming the client with empty messages
but thats a sort of /clearchat feature like
is there a better way to unescape tags in minimessage then .replace("/<", "<")?
even that won't work if someone is escaping the escape char
sounds like an xy problem
String formatStr = StringUtils.parseArgs(PlaceholderManager.parseString(player, format), name);
Component chatFormat = miniMessage.deserialize(formatStr);
formatStr is containing both legacy color and minimessage
I just though of a better approach that might work but this still could be useful for future
Mixing MiniMessage and legacy formatting is not supported https://docs.advntr.dev/faq.html#how-can-i-support-both-minimessage-and-legacy-code-formatting
Thanks! For our case we only create a flattener manually, so that should be fine to override once
What's the purpose of Style.Merge.Strategy.NEVER?
I mean, if we never merge, why calling merge in the first place? 😅
Why is there TextDecoration.State & TriState? Didn't they fill the same purpose? TriState has some really useful methods, but unfortunately I can't use them because I have TextDecoration.States
tristate was added later
could be a minor improvement for 5.0
im unsure how to go about recoloring all children (deep) from a given Component, ayone got any idea? im aware ComponentBuilder#mapChildrenDeep is a thing but unsure how to get to that or use it at all
You would need to turn the component into a builder to use that using the asBuilder method
then you call that method and it passes in all of the subcomponents and their subcomponents... into that function, you return the new component
If you just have a generic Component you first have to instanceof and cast to BuildableComponent<?, ?> (all components extend this so checking is kind of optional, but good practices and all), then you can call BuildableComponent#toBuilder
If you already have some sort of Component implementation (like TextComponent) you should already be able to call #toBuilder on that
okay so, my component is a TranslatableComponent apparently, and the hover event text i want to change color is an argument, is there any method like the mapChildrenDeep one to recolor arguments?
mapChildrenDeep iterates the component tree, arguments aren't really considered to be part of that
you would need to manually deal with the transltable component yourself
not really an adventure question but is there some way to allow color definition in resourcepack translatable?
you can color the translatable component itself and the arguments you pass to it but you can't do coloring for the entries in the resource pack
i guess you could try shoving legacy codes there to abuse the client's tendency to render them in most places
is there a way to "substring" a component?
and not lose the decorations
what's the XY here
I want to display colors in the action bar for a plugin I am working on.
The text is shown per-letter so currently I do a scheduler that for every time it subString the text.
I thought about using component.children() because I guess it would give me individual components that have the same style for each one
I want to get each object of the component
so for example:
"<red>Hello <yellow>World"
"<red>Hello " - this it an object with the color red
"<yellow>World" - this it an object with the color yellow
idk why you'd start with a completed component there, big design issue on your part
I can start with a string
but the thing is I need a splitted component and a plain string version of the splitted component
so I can apply style in a way
you solved your own design problem here
ik
how I get to that point tho
How can I cut the component to multiple ones
start with a list of strings and their associated style
I am starting with a string
thats is what I was asking - how can I split it from here
don't, start with a list of strings and style for each part
there has to be another way
sure, how I do that
I tried the iterable thing but I couldnt get out of it something
have you tried putting the arguments in
comp.iterator(ComponentIteratorType.BREADTH_FIRST, new HashSet<>());
... then you have the iterator so you can iterate though it
ik...
ill try again
Iterator<Component> iterator = comp.iterator(ComponentIteratorType.BREADTH_FIRST, new HashSet<>());
List<Component> components = new ArrayList<>();
iterator.forEachRemaining(components::add);
for (Component component1 : components) {
System.out.println(MiniMessage.miniMessage().serialize(component1));
}
well I don't usually use the Iterator directly...
but the logging seems weird?
The input : "<red>Hello</red><green>Hello"
[12:37:03 INFO]: [TalkShow] [STDOUT] <red>Hello</red><green>Hello // -> why is it logging the full msg?
[12:37:03 INFO]: [TalkShow] [STDOUT] <red>Hello
[12:37:03 INFO]: [TalkShow] [STDOUT] <green>Hello
"<b><gradient:#8E2DE2:#4A00E0>test </b>test" i cant stop bold text after setting a gradient? why?
you would have to close your gradient first
OR "<gradient:#8E2DE2:#4A00E0><b>test </b>test"
doesnt work still
show your entire string
"<gradient:#8E2DE2:#4A00E0><b>test</b>test"
Works on the web viewer at least
even if i close the gradient it still wont let me
maybe in code the styling is set to always bold
do you have access to the code?
Ah yeah if the parent is setting bold it'll just all be bold
<!b> should work in that case
use !b
it does thank you
Hi, does MiniMessage.miniMessage create a new instance every time? Or does it just return an already initialized instance?
it returns an existing one
Ok so calling it multiple times wont be a problem right?
even if it created a new one it likely wouldn't, but yeah
public static List<Component> buildHoverText(ItemStack item) {
List<Component> hoverText = new ArrayList<>();
ItemMeta meta = item.getItemMeta();
hoverText.add(item.displayName());
are these square brackets a side-effect of not serializing?
How should I be better handling this?
Try meta.displayName instead.
fuck right
(also this sounds like a paper question not an adventure one)
I still can't figure a way to do this.
Lets say I have a string (that can me deserialized) - "<red>Hello guys! <yellow>Get out."
I want to send the player this msg (in their action bar) like it is being written. to do so I use the scheduler.
What I need is a way to cut the component each time so I could achieve this effect ("H", "He" , ...., "Hello gu", .... "Hello guys! Get out").
My test version didn't support styling and just used the plain text and the substring method.
But now I want to have colors in it. Any ideas? 😔
There is no clean way to do that which isn't basically manually iterating over the component to rebuild a small subsect of it
yeah I guess.
but as you said - "it iterates all components. including the root component"
but it also doesnt split tags that haven't been closed - so it doesn't split to small sections
I guess its kinda my problem but I want a way around this
you would need to rebuild a new component from the old one
the fact that it iterates the root component is literally what you'd want here
.
umm
what if I just iterate these ones
This is really not that hard of a concept to understand
if you serialise the root component you'll get all of the children in there too
you would need to actually introspect the components you're dealing with
and build a new component from that, respecting the tree
This is generally a headache and why there is no magical util to do this; it's not massively complex but it is a pain
component.iterator(ComponentIteratorType.BREADTH_FIRST, new HashSet<>()).forEachRemaining(c -> {
if (c instanceof TextComponent textComp && !textComp.content().isEmpty()) {
Component a = Component.text(textComp.content(), textComp.color());
source.getSender().sendMessage(a);
}
});
well this works
for some reason
that looks like it'd break for any component that inherited styling from its parent
also it only preserves colors and not text decorations
🤷♂️
Sorry I just can't undersand the concept
<red>Hello <bold>guys!
~~```java
component.iterator(ComponentIteratorType.BREADTH_FIRST, new HashSet<>()).forEachRemaining(c -> {
if (c instanceof TextComponent textComp && !textComp.content().isEmpty()) {
Component a = Component.text(textComp.content()).style(c.style());
source.getSender().sendMessage(a);
}
});
this one seems to save the style~~
its really a headache for me that problem
LinkedList<Component> componentList = new LinkedList<>();
component.iterator(ComponentIteratorType.BREADTH_FIRST, new HashSet<>()).forEachRemaining(componentList::add);
Style currentStyle = Style.empty();
TextComponent.Builder builder = Component.text();
for (Component c : componentList) {
if (c instanceof TextComponent textComponent) {
currentStyle = currentStyle.merge(c.style());
builder.append(Component.text(textComponent.content()).style(currentStyle));
source.getSender().sendMessage(builder.build());
}
}
I guess this works
why a linked list?
the style merge logic you have there doesn't work properly
it assumes that a component has at most 1 child
you need to do something similar to what a ComponentFlattener does
i do have a gist lying around of where i had to do something similarish for some stupid idea i had
but a lot of that gist is filled with stuff to avoid adventure's style merging (because it used to be weirdly slow)
I thought it would change the inserting order
what?
well I don't know what ComponentFlattener does
Ahh I can't do this anymore

is there a reason you're doing this on the component instead of just the mm string
How can I do this on a mm string
At the end I need a colored substring
By splitting it into a list of singularly styled strings like I said right at the beginning
Of course this is difficult, you're solving a design problem with a code solution
private List<Component> loadTextFrames(Component component) {
List<Component> frames = new ArrayList<>();
List<Component> componentList = new ArrayList<>();
component.iterator(ComponentIteratorType.BREADTH_FIRST, new HashSet<>())
.forEachRemaining(componentList::add);
TextComponent.Builder cumulativeBuilder = Component.text();
for (Component section : componentList) {
TextComponent textComponent = (TextComponent) section;
String s = textComponent.content();
Style style = textComponent.style();
for (int index = 0; index < s.length(); index++) {
char c = s.charAt(index);
cumulativeBuilder.append(Component.text(c).style(style));
if (c != ' ') {
frames.add(cumulativeBuilder.build());
}
}
}
return frames;
}
yesterday I coded this, looks like it works
that won't work for this as you've been told
you'll lose the red
oh shoot
I can't understand your answer as well
how can I split it up then?
Find a Regex in the mm string?!
I wonder, you could probably use the deserializeToTree method to properly split the nodes
Hello, I have a problem. So I'm currently making a rank system in minecraft with a special symbol for every rank. So I make a Component with the Player's name and then append whatever rank they have to it. These Components are for example used to make item names. Now I'm trying to make a function where something happens to the player when I click on the item. This happens by getting the displayname, casting it to TextComponent, getting the content and removing the symbol and the space before it. However the .content() method seems to only return the symbol and not the name. Does anyone know what could be causing this?
components are tree structured. do not use them to store data, instead use PDC on item
what does tree structured mean?
It's like the DOM in browsers, just because it looks like a single line in your UI doesn't mean it's a single component, it's a nested pile of components, usually one per style change although you can get even more via append
You'd have to serialize the component to plain text to get a single line like you appear to be expecting but this is not a good strategy for storing information
Paper's PDC is a good alternative for storing stuff but really anything else that makes sense for your environment and the data you're storing
Could be as simple as a HashMap<UUID, MyData>
why does translatable("test.entry", Argument.tagResolver(Placeholder.parsed("value", String.valueOf(value))) works correctly, but translatable("test.entry", Argument.numeric("value", value)) does not? hover is parsed correctly, the value is substituted, but nothing is substituted into the click event. Message: <hover:show_text:'Click to delete <value>'> <click:run_command:'/test remove <value>'><value>.
that screen shows up because the command is not visible to the client
whether it is because you don't have permission or are otherwise excluding it, for that screen to not show the command needs to be visible to the client
the problem is that the command is not substituted as a <value> tag if you use Argument.numeric("value", value)
but hover works correctly)
I'd guess it's the matter of it being parsed?
i forget what is what, but, you have to use a specific type if you want to be able to inject into stuff before some stuff is processed
yes, i think so
It is, parsed means to slip it into the MM string, rather than it being processed as the contents of something later on
Hello
"UnsupportedOperationException: null"
Is it adventure, triumphteam or my error?
https://pastebin.com/7wULZq5H
Using server leaf-mc 1.21.8-79-ver/1.21.8@e396d8c
Using for build plugin java 21, paper-api 1.21.8-R0.1-SNAPSHOT
My code at BusinessesContainer at line 149:
private MiniMessage miniMessage;
public BusinessesContainer() {
this.miniMessage = MiniMessage.builder()
.tags(TagResolver.builder()
.resolver(StandardTags.color())
.resolver(StandardTags.newline())
.resolver(StandardTags.transition())
.resolver(StandardTags.translatable())
.resolver(StandardTags.keybind())
.resolver(StandardTags.decorations())
.resolver(StandardTags.font())
.resolver(StandardTags.gradient())
.resolver(StandardTags.rainbow())
.resolver(StandardTags.clickEvent())
.resolver(StandardTags.hoverEvent())
.resolver(StandardTags.pride())
.resolver(StandardTags.shadowColor())
).build();
}
...
ItemBuilder
149 line -> .name(parseMM("Information about <business_name>", Placeholder.parsed("business_name", configItem.name()))) //.name() returns String
...
private Component parseMM(String message, TagResolver... tags) {
this.miniMessage.deserialize(message, tags);
}
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.
I dont know why the cause would be adventure, thats basic deserializing and Placeholders, I see no issue there
You appear to be using adventure-platform-bukkit so should ask in #adventure-platform-mod-help
But, instead, why not just use adventure that's built into the api?
Did some digging, you apear to be running an outdated platform too.
I think the error is on the side of triumphteam-gui lib, I'll try to write to them
I'm using the paper api, not adventure
Thank you
Looks like you'd just need to bump version of it
Ye I found solution:
I need to use PaperItemBuilder instead of ItemBuilder
you can but it doesn't make it any easier nor I like the solution I ended up with lol
I hate it, but it works
could probably clean it up a little by making it more of an utility, I just didn't bother because I was testing with jshell
in the end, it'd probably have been better to just deal with the components instead of MM for this, so I was wrong about using the MM string being simpler
The main problem for me is that some classes are not documented clearly anywhere
I didn't even knew there was a ValueNode or TagNode class
They're not documented because they're not API 😛
eh I guess so 🤷♂️
well, kind of not API. It is supposed to be exposed to the API eventually but it seems like the whole tree-traversal part of MM is yet to be done (if it is ever going to be done, I doubt many people actually want to use it)
I hope they add a way to easily just cut a component someday
the idea is to just close all tags at the end
I'll give the component only way a go later and if I get something working I'll post it here as well
ik it would be difficult because its a tree
If you REALLY want to do it automatically, after all this time, you can linearize (or flatten or call that what you want) the component tree, then your existing code will probably work
That one
I think the tree linearization is the only part you’re missing (but I did not nor plan to look your code in depth, it’s up to you to test it)
currently that code breaks the styling
yeah ill see what I can do
I think someone also suggested to flat the component I just didn't really knew what it meant
Yeah obviously, as you don’t properly handle inheritance because you only use individual components
I can look at like like a pyramid of overriding
It’s really not that hard, and if you’re stuck, you can always find my fork with my brand doing that exact thing
Idk what your drawing is supposed to represent, but the styles are just inherited from parents to children, rather simple concept (considering you can access individual components’ style & children, and also merge styles)
the effect itself is nice, too bad the impl is annoying
Hi,
I think I'm missing something here:
Registry<org.bukkit.Sound> soundRegistry = RegistryAccess.registryAccess().getRegistry(RegistryKey.SOUND_EVENT);
NamespacedKey soundKey = soundRegistry.getKey(org.bukkit.Sound.MUSIC_DISC_11);
audience.playSound(Sound.sound(soundKey, Sound.Source.UI, 1.0f, 1.0f));
Is there a better less verbose way to do something like this without hardcoding the key string?
I like the org.bukkit.sound enum, but I can't use it inside Audience#playSound
because it uses net.kyori.adventure.sound.Sound
bukkit Sound implements adventure Sound.Type, which you can use to build an adventure Sound
Yes, but it seems that this method has since become deprecated, so I would like to avoid using it.
i'm not saying to use that method tho?
n.k.a.s.Sound.sound(o.b.Sound.WHATEVER, n.k.a.s.Sound.Source.WHEREVER, volume, pitch)
Hmm, I definitely haven't seen that method, Thanks !
I thought you were talking about the implementation of the Sound.Type interface in Bukkit Sound (key() )
Hey, i got a question about how to use minimessage properly. So i own a minecraft server with a custom codebase and pretty much use minimessage for every gui (itemnames & lores) and chat messages.
Everytime a message or lore is built i use the deserialize function. This oviously causes a huge dent in performance pushing the mspt to around 90 with just 100 players online.
can someone with a bit more experience teach me how to "pre-deserialize" the messages and reuse these components and replace the dynamic content (custom placeholders)?
Maybe there is a different way of doing it properly, thanks for any help in advance.
I guess you’d need to share the full spark report, but it seems you are at 20 TPS so… What is your real issue?
I'm always looking for ways to improve performance so please please please share the full spark and other profiling data you may have!!!
is it possible to somehow serialize kyori component to lang files so i can specify colors/etc... directly in resource pack's lang file? would be way easier than having to separate each arg/string that has different color/click event/...
What format do resource packs lang files use? JSON encoding?
If so, yeah sure you can use the GsonComponentSerializer
But I'm not sure they are components at all
resource pack translations doing support styling in values
iirc they just are plain strings
ya
Hello, is there a reference parser for MiniMessage-formatted text?
MiniMessage.miniMessage()?
If you mean is there a spec with the grammar defined or is there a simple implementation outside of any ecosystem no, afaik
is it possible to add my own component after each color in a component? I wanna try to implement vanilla-like shadows for scoreboard
since vanilla shadows are RGB divided by 4
I mean, sure,y ou can do basically anything, question is how easy is it
yes
if you wanted to modify the tree you'd basically need to walk over it
oh yea there is children() method
adventure contains all of the tools you'd need to do that at the very least
yeah its so hard
i just tried
i dont understand is shadow a text decoration or what
ShadowColor is part of the style of the component
ah wait
i got an idea
just gonna serialize minimessage back to text and insert <shadow> there
xd
And remember that components (including all of its composing parts: style, children...) and immutable, so if you want to add shadow color to each component that have a color defined, you'll have to create new components for the whole tree
I mean, if that would work you could literally just set that on the root component
(no idea how the shadow stuff works)
According to my understanding of your goal, imo it's far easier to work with components rather than the MM-encoded string of said components
same
It's pretty simple:
well write it for me if its that simple!
It works exactly the same way as color, but it also supports alpha channel
That's not how support here works 😅
I know
oh this probably wont support gradients and such
but i dont care
nevermind
hm, client/server version? and what platform
Client:1.21.7 Server:Paper 1.21.8-31
Maybe mod issue, I'll check tomorrow
I saw the ChatPatches mod add some custom click actions into the component
executor.sendMessage(Component.text("[确认]").color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(Component.text("点击确认"))).clickEvent(ClickEvent.callback(audience -> {
audience.sendMessage(Component.text("已为" + player.getName() + "解锁所有词条").color(NamedTextColor.GREEN));
})));
tried with paper 1.21.8-40 and vanilla client 1.21.8, this doesn't work
the code is in brig command
full code here
not typewriter, it's packetevents issue
You can reproduce it by only having packetevents?
yes
seems that pe only recognizes string payload
Payload is not a string payload, is CustomImpl{key=KeyImpl{namespace="paper", value="click_callback"}, nbt=BinaryTagHolderImpl{}}
So instead of ignoring the packet it destroys it?
probably
Why serializator can handle colors/styles without other symbols from text in MiniMessage (<red>, <red><bold>), but not in Legacy (&c, &c&l)?
I try to deserialize input text and then serialize it to string to save in config. I type text, that contains only colors or style (without any other text). MiniMessage serializes fine, but LegacyComponentSerializer returns '' (empty string) instead of &c, so I have to type some other symbol &c... and it saves as '&c...'
MM aims to preserve the tree
the legacy component serialiser from what I recall generally reasonbly behaves like the spigot one
(i.e. there is 0 consideration towards the formation of the tree, anything that isn't set is as part of the formatting stuff just generally overrides the stack, etc)
The neat thing about the legacy serializer is you don't have to worry about how it writes because it's such a lossy serializer it's not worth using as anything but a way to migrate pre-2014 text to something modern like minimessage
Fine, will save input directly in config instead of deserializing and serializing again
I tested because I wanted to double confirm that;
15:07:47 INFO]: [STDOUT] [net.minecraft.server.dedicated.DedicatedServer] [empty[siblings=[literal{Test}[style={color=aqua,!italic}]]]]
System.out.println(java.util.Arrays.toString(org.bukkit.craftbukkit.util.CraftChatMessage.fromString(org.bukkit.ChatColor.translateAlternateColorCodes('&', "&a&bTest"))));
It just looks like they're shading an old version of the Gson serializer (something before that commit https://github.com/KyoriPowered/adventure/commit/12aaa8cce985e842cac2b2d67f8d2839a9ddfac7), but the version specified on tag 2.9.4 seems to be 4.23, which should be good, so idk maybe something else weird is done then)
Oh yeah they're definitely doing something to that poor Gson serializer: https://github.com/retrooper/packetevents/blob/v2.9.4/settings.gradle.kts#L38
Should just use paper's when paper is present
It's so much easier to build a plugin that way imo
if you're already shading and relocating your own version, it'd be more sensible to use your own, for the sake of behavior being deterministic
of course, you run into issues like this where new features aren't adapted as fast, but that's a price you should be willing to pay if you patch/fork anything
In fact, they are not shading it. They completely replaced it with a modified version, but last commit is 1 year ago 🤦
https://github.com/retrooper/packetevents/blob/v2.9.4/patch/adventure-text-serializer-gson/src/main/java/net/kyori/adventure/text/serializer/gson/StyleSerializer.java
So, when they updated adventure, they forgot to update this weird "forked"/"overridden" version of the Gson serializer, which mean it is outdated
it looks like it was so they could support different versions of the game with just one serializer, looking at BackwardCompatUtil, I had assumed the adventure one would handle that kind of thing by itself tbh
There are options to control how the serializers behave iirc. But they would need one correctly-configured serializer per version, I guess
tho they could make a single serializer delegating to the correct one if they really need to, but I don't really know what/why they are doing anyway. I was just intrigued by how that issue could've happened
If doing per-mc-version releases (which is getting increasingly necessary with changes happening in mc), it's not a risk imo
And packetevents is something that needs updates for each version that adventure would update (and plenty adventure wouldn't update for)
I take back what I said actually, given there's no good way to handle this kind of situation
either you permit delegation in your serializer so that new features are properly handled and maybe open a door to unforeseen issues, or you just use your own versions like they do and just fail completely at handling new features
It's a glorious mess isn't it
the former choice would eventually be the sensible one given how fast the ecosystem moves
When using MiniMessage, it seems that I can't put an argument as the key in a lang tag, so <lang:<key_arg>> doesn't work. Does this work as intended?
you'd need to use a Placeholder.parsed for that kinda stuff
Okay, another question:
I created a method that can deep clean styling from a component and I want to turn that into a minimessage tag, but I don't know which one to use. I tried Modifying but that duplicates my component because of how it works internally, doesn't seem to be made for what I'm trying to do.
Return an empty component when depth is not 0 (or 1, I don’t remember which one is root)
this has got to be the dumbest thing I've ever seen btw
like quite intensely stupid both in a) the fact it exists and b) the way it was implemented
the fact that they could achieve the exact same things they are forking for with api is just sad
What chars are allowed for a tag name? The pygments suggests any char goes (except ofcourse [>:'"])
declaration: package: net.kyori.adventure.text.minimessage.tag, annotation type: TagPattern
alr thanks ❤️
how do i send message to all players on server using Audiences?
Depends on the server software. What's yours?
Paper, for instance, has methods on Server.
yeah paper
im using audiences first time i already have some class that im using for general context player messages however now i want to send message to all players on arena that the match is cancelled
if you have one arena per server of world then it's easy, since those both implement audience
so i coudl do this by doing for player : players player.sendMessage(ServerMessage.error(playerData.getPlayerLanguage, "info.match.players.failedtoconnect"))) smth like this
yeah its one arena per server
however this seems like bad design
so i'd love to do this using audiences as i believe this is the right way?
well now i realised its actually not the case in my case because im getting playerLanguage for each player and by audiences i would send the same message to everyone
if you're referencing specific per-player data in the component I don't think audiences will work here
It seems you’re using some kind of i18n, but not adventure’s one. Any reason for this? Because with built-in localisation system, you could get the best of both worlds: using the server as audience and player-specific localised messages
With something alongs the lines of:
Bukkit.getServer().sendMessage(Component.translatable("my.message.key"));
because some people are playing minecraft in diffrent language then the language they use
and they might prefer play minecraft in english and mini game in their own language because some of the information is complex
So, the locale is fixed on the server?
the locale that i use for server messages is server based yeah
its stored in player's settings
so they can play minecraft in chinese and server in french or whatever
So you could just configure the adventure translation system to do server-side translation based on the configured language, I guess
That's something im doing to some extent im just dynamically injecting player's language into adventure translation system
public static Component translated(Locale locale, String key, Component... args) {
return GlobalTranslator.translator().translate(Component.translatable(key, args), locale);
}
return Component messageComponent = translated(locale, messageKey, args);
}```
and im injecting the player's locale on the run
Ok, but if you wire things correctly, I think you shouldn't need to send different components to individual players
Because if you correctly configure server-side translation on Paper, it is done when the actual component is being sent to the player
So you just have to send the same translatable component to everyone (which can be achieved easily through the fact that Server implements Audience to forward messages to all online players)
Ahhh yeah i get it now
yeah i was using it wrong i believe
right right and then i should be able to for example send GlobalTranslator.translator().translate(Component.translatable(key, args), playerdata.locale);
right?
my bad but i didnt understand it quite well when i started doing this
well that changes a lot
Yeah that was really helpfull that will actually work but it needs much changes in code at this point but ig that's the way to go
I actually don't have much experience myself with that localisation system, but this documentation page should provide you with most of the info: https://docs.advntr.dev/localization.html
Yeah i mean i understand it to the part where audiences don't make their appearence
as far I understand it, shouldn't you be able to just send the translatable component, and Paper should render it under the hood?
yeah that's kind of to what conclusion we came there the way i was using it before is i rendered it before using it later in my code
i was using this function
public static Component translated(Locale locale, String key, Component... args) {
return GlobalTranslator.translator().translate(Component.translatable(key, args), locale);
}
``` which already translated it
however i still see some flaws because here let's say we have this translatable component and audience
audience.sendMessage(Translatable , locale)
however players from audience have diffrent locales right
Audiences really aren't a complex concept at all. An audience is just "something that may be able to handle messages/titles/actionbar/...". The most simple audience being a player. And then, there's the useful concept of "forwarding audiences", which are audiences that simply forward everything they receive to some others. A team is a good example, it forwards to every players part of that team. A world forwards to all players in that world. The server to all online players... You can define your own audiences to simplify the handling of "a list of targets" for instance.
And another nice concept of audiences is that they silently ignore any request they couldn't handle. For example, the console is an audience, it can receive messages, but not titles. If it do receive one, it will just ignore it, so that a forwarding audience forwarding both to a player, and the console, if you send it a message, both will receive it, and if you send a title, the player will receive it and the console ignore it
There is no special relation between audiences and translatable components, the audience just provides a standard interface with methods you can call with components (which can be translatable ones) if you want
yeah yeah so that's where this complexity comes in because if you want translated message to come out for players you just send translatable component and players locale but if there is a group of players with diffrent locales?
Translatable components doesn't comes with locale
but translating it needs a locale?
A translatable component is locale-independent, it only contains a translation key and arguments (and possibly a fallback string in case the key is unknown, but in a correctly configured environment, this isn't needed)
Technically speaking, you could just send the component to the player as-is. Minecraft will process it, however it will likely don't know how to translate it, causing the raw translation key to appear
(Unless the translation key is one of the existing Minecraft message, or the client has a resource pack with a language file containing a message for this key)
This would be client-side translation
But in your case, you want server-side translation
And Paper & Adventure allow this to be done fairly easily, with the GlobalTranslator
On one hand, you configure the translator so it knows how to resolve translatable components (= turn them into text components, using the player's locale (and you may be able to override the way the locale is selected, but I'm unsure about that), and the messages associated to their translation key, for each locale)
yeah so im doing it at this point for singular components right
And on the other hand, you just send raw translatable components to audiences, and Paper will automatically call the translator on them for each player that will receive that component
yeah but translator won't know what to translate it for each player because it doesnt have this knowledge
he has knowledge on how to translate the translatables but he needs to know what to translate it to or else he will just change it to default
Hence why you need to provide him that knowledge by configuring it as explained in the doc I linked you above
There is also this page which I think explains the same thing, but maybe it could help too: https://docs.papermc.io/paper/dev/component-api/i18n/
hmm yeah ill work on it
or the translatable component has a fallback format :)
redirecting this question here.
instead of Locale.ROOT should i use Locale.US for fallbacks?
use whatever locale you want for the default
looking at SoundStop, is there a way to stop all sounds except a specific sound?
No
couldnt you just iterate thru all sound
yeah i was hoping to not have to do that but i'll give that a try
wdym?
maybe i was not clear: i have a locale file (written in english) that i want to use as a fallback if the client's current language isn't supported by my plugin.
e.g.
-
show fallback text (english) if the user locale is german and i do not have a german specific language file
-
show fallback text only for the keys that are not in the matched locale file (the plugin has a german locale file but it's missing a key that exists in the fallback file)
is there a way to Clear/stop a title and/or action bar?
couldn't you send an empty one?
Audience#resetTitle
1 can be done by setting defaultLocale on the translation store
2 can be done by setting the fallback on the translatable component
thanks, so:
myStore.defaultLocale(Locale.US)or whatever locale i want to use as default- how does that work? I see that
Component#translatableaccepts only a simple string as fallback and not a component
yes fallbacks can only be strings
i lose all the fancy formatting then
what you could do in your case is:
- override contains to always return true
- override translate to call super and if null return a custom message
bear in mind that will break every single other plugin and translatable component if you register that store to the global translator
but idk why you'd want to do that in the first place, standard practice for translatable messages is to just return the key if anything is missing
oh, then I'll follow the standard pratice. i didn't know that
based on that, how bad is to let the user delete the keys (or set them to an empty value) to disable them (so prevent the plugin to show them)?
if (key is not null or value is not "")
player.sendMessage(Component.translatable(...))
I don't think that's what he wanted in the first place, he said he wanted to use the fallback locale when either the client's locale is unknown or the language file for that locale is incomplete (only some messages have been translated)
Not a fallback message for every unknown key
that's not what they asked in their follow up message
I think it's just a language barrier, it was weirdly worded 😅
yeah this would be fine ig
sorry for the confusion (@sweet hornet got it almost right):
use the fallback locale when either the client's locale is unknown or the language file for that locale is incomplete (only some messages have been translated) OR ENTIRELY MISSING
in that case just set the default locale for the store
only that?
yes
well that's easy, should I do it before adding the store to the globaltranslator?
doesn't matter when really
surely before showing text to players i'd imagine
yes
what are the allowed chars for non string arguments? anything?
for example hover's show_text and such
either i am sleep deprived or your question does not make any sense
allowed chars where for what kind of non-string arguments?
<hover:show_text:'<red>test'>TEST
Here '<red>test' is a string arg, while show_text is a "non-string" arg
I'm having trouble understanding the source code, but from what I understood anything goes untill it reaches : if it's not in a URL
sure
You need to quote arguments if they contains <, :, > or . Maybe others, but those ones are the most obvious ones (space)
spaces i believe are allowed
Ah?
yeah they are
Ok mb, it's only in the tag name where they aren't then ig
alright thanks
TextReplacementConfig replacement = TextReplacementConfig.builder()
.matchLiteral("%frequency%").replacement(String.valueOf(settings.getFrequency()))
.matchLiteral("%radius%").replacement(String.valueOf(settings.getRadius()))
.build();
I assume this isn't ok because I added the second literal match and now nothing is replaced. What should I do instead of this?
You should use a framework/library that has built in placeholder support e.g. MiniMessage
TextReplacementConfig only replaces one thing at a time, you're replacing the frequency literal with the radius literal matching there
I'm actually using minimessage already
Then why aren't you using its placeholder system?
Yeah
i had no idea it existed withinin mm until now
well there ya go :p
Do placeholders have to be <some> with < >
Yeah, all tags are formatted like this
So how should I go about replacing placeholders in an ItemStack displayName()
Why are you doing it on the component? Aren't you starting with a MiniMessage string?
I'm not actually I was wrong I have an ItemStack and I need to replace placeholders in its name component
why are there placeholders in the component name of the item stack?
who/what put them there?
I have an ItemStack in my configuration file for users to edit
and you can have placeholders in the display name which will contain dynamic information about the item so it needs replacing
But why don't you parse the components when reading the item stack from the config?
i use a config library which just gives me an itemstack
thats out of my control
im not going to switch library at the moment as it's too much work
would this really make a difference? either way i'm replacing text inside of a component just at a different time, the part im having difficulty with is replacing text inside of a component
string != component
Well, yea, because your input would be the raw string from the config in that case, rather than having to run around a roundabout and have to potentially deal with messing to parse out something or losing data in the process
you should either a) make your config library let you use minimessage or b) plain text serialize the item name and recreate it as a component using MiniMessage
not sure i mentioned strings anywhere? by text i mean text components
all of the plain text formats bar MM will discard any rich formatting, and MM will escape any tag inside of the content of a tag
ok so serialize the name and use mm to recreate a component and replace its placeholders
a) make your config library let you use minimessage
just out of curiosity, how would a change to the config library work? if i save an ItemStack in the config then will the library still not return me an ItemStack? Where about does MM come into play here and where does everything get replaced? The replacements happen when a user runs a command e.g/specialcommand <frequency> <radius>so it needs to replace it here not when reading from the config initially right?
not having a raw itemstack pulled from the config would give you many dozen potential code options depending on the route you wanted to go down
ok so dont store item stacks and store mm strings instead
yep, you'll find that much easier to deal with
"too much" is meaningless
how can i reload/register again the translations in a TranslationStore?
If you're using the global translator, you can unregister the store from its key and then register a new one
so I only need to unregister the store?
NamedTextColor#nearestTo(TextColor)
what if i'm not using the global translator? i do store#registerAll at the start of my plugin
You can just swap the store you're using
or call unregister
or just register everything again (im p sure they replace)
Wdym? Recreating the instance of the store?
yeah like just make a new one
and register the translations again
this also could be a good option instead of recreating + registering
oh ok
also, what's the need of the key when creating a TrnaslationStore?
TranslationStore.messageFormat(Key.key("namespace:value"));
well if you are adding it to the global translator it needs to be identified
and if I'm not?
in which cases i would have to refer to the store with its key?
idk debugging?
even if you're not you still have to pass one in
and it doesn't hurt anyone, so like
yeah yeah, just for my knowledge
does adventure support on legacy ? (1.8 - 1.21)
the adventure api is version agnostic for the most part, then each implementing platform chooses what versions it supports
does the console have a locale?
and how i can get the locale() from an audience object?
Using pointer iirc

ok i figured it out what pointers are, but if I have this.audience.get(Identity.LOCALE), what happens if multiple players are included in the audience?
where are you getting this audience from?
command sender, and occasionally casting player to Audience to have a standard thing where I don't have directly access to an audience object
forwarding audiences (generally) don't expose any pointers
so if I use regular audiences I will not have problems?
i mean, what exactly are you doing?
then you want to unwrap any forwarding audiences and iterate them yourself
or use the translation api
wdym?
what in particular? i'm already using the translation api
?
if you're using the global translator, you don't need to render the components yourself
i'm not using the global translator, i use an unregistered translationstore
Is there a way to nest a <selector> inside a show_text hover?
I have this:
"<hover:show_text:'<selector:@a[team=Hider]>'>" + " <aqua>" + hiderTeam.getSize() + " <gray>players remaining." + "</hover>"
but in game it just puts the selector value as the hover text
I would bet that it is just a syntax error that im missing but cant seem to get it to work with trial and error
selectors must be resolved manually unless you use it in a spot where that happens automatically
which I forget what they are if any exist
each platform may provide API for it
PaperComponents in Paper
got it working, thanks
Which is a class common to both CommandSender and Player?
I would like to make a method that sends a custom message and didn't wanted to make a different for each type
.. Audience?
But Audience can be also multiple targets?
Like 2 players in a single Audience object? Or that's the ForwardingAudience
that would fall under forwarding audience, yes
So Audience refers to a single target
i mean, ForwardingAudience extends Audience to make it easier to, well, forward all the method calls to the forwarded audiences
And I could get the locale of that target with audience.get(Identity.LOCALE)?
and which of the forwarded audiences would it get the pointer for?
I don't want to use forwardingaudience
then don't use it
I'm using a translation store without registering it to the global translator
So I'm handling all of the translations manually, and creating an helper class to do so
you'd need to explode forwarding audiences to their individual audiences
The problem is that I want to make a method like "MyHelper#sendMessage" that can take both a CommandSender and a Player
And then get the locale of the player/commandsender (or use default locale if sender is console as it doesn't have a locale)
take an audience, and explode forwarding audiences recursively to send the message to the individual audiences
But only the Player object has locale() method
okay
So like iterating through the audiences and "if Audience == player" use its locale else send message using default locale
no need to check for player, just check that the pointer value is not empty
getOrDefault(Identity.LOCALE, defaultLocale)
but you need to explode forwarding audiences and recursively call the method
CommandSender
(to answer strictly to your question)
So in my "sendMessage" function, i Will need to iterate through the audience targets and check for the locale with the method you wrote
That's a solution, but just to be sure: If you simply want to send messages to either CommandSender or Player, you just need to write your function for CommandSender, since Player extends it
feels like you just wanna look at forEachAudience
that will give you a consumer for each individual audience member in any forwarding audience
or just one call for any single audiences
but CommandSender does not have a locale() method, i would have to check if CommandSender is instance of Player and then cast
Yeah yeah, I was just replying
Then I can use this to iterate over the audiences
And use the pointer to get the locale, if any
And then use my translator and send the message
That's it
how do i turn off formatting in specific selection of text?
i have chat message formatting like this
Text: '<hover:show_text:''<i><lgray>Message was sent at: <white>%localtime_time_hh:MM:ss%</white></lgray></i>''>%ezcolors_color%%message%</hover>'
but if players include < in their chat message
it gets ruined
for example i just wrote "<" in chat here
And why not use MM tag system for placeholders?
Use proper MiniMessage placeholders and not whatever % system you have there
Those can be parsed and unparsed (what you want)
That is a really glaring bug/exploit in that plugin then and should be reported
why?
what other things can players do with it?
Send click events for example
With open url stuff
Anyone could just type <click:run_command:/op kezz101>here's my normal chat message heheeh
Or suggesting commands
what minimessage placeholder should i try???
there's no placeholder that'll fix this, you need to get the plugin to use placeholders properly
if, e.g. %message% was instead a component placeholder no minimessage tags would get parsed in it at all
Basically the code needs to be fixed that you can define the message via <message> and not %message%
if you direct them here we'll be happy to help them switch over
start reading from here
known issue. see #960839051093630986 message
also harmless btw, it still doesn't allow players to insert tags in their messages
Hello, I'm using ClickEvent to run a command, how can I disable the confirmation to run the command?
You can't, basically
It's client-side on modern Minecraft
However, iirc it only shows that confirmation for commands that are either unrecognized (by the client), or privileged (requiring OP in vanilla)
i'm doing [inv] in chat, and when I click to [inv] I run a command, other server has this function and they don't ask to confirm the run
So maybe you can make a command that is not perceived by the client as priviliged, while still maintaining the server-side checks to ensure only authorized users can run it
But I don't know the details about how to do that, neither if it would work
my command has no permission
Can you show the confirmation screen plz?
Can you translate the text in english? 😅
Mostly the second line
Is it refering to a privileged command, or an unknown one?
"non riconosciuto o invalido" seems to means "unrecognized or invalid", right?
If that is the case, then your problem is that the client doesn't know about this command (i.e., if you type it in chat, it'll be shown as unknown, in red)
another plugin was blocking the command. Thank you for the help
ctx.source.sender.sendMessage("&8&m+----------+&r $prefix &8&m+----------+")
ctx.source.sender.sendMessage("")
ctx.source.sender.sendMessage(" &7Author: &b" + Plugin.pluginMeta.authors[0])
ctx.source.sender.sendMessage("")
ctx.source.sender.sendMessage(" &7Version: &bv" + Plugin.pluginMeta.version)
ctx.source.sender.sendMessage("")
ctx.source.sender.sendMessage("&8&m+----------+&r $prefix &8&m+----------+")
What would be the best way to replicate that using MiniMessage?
ctx.source.sender.sendRichMessage("<dark_gray><st>+----------+</st></dark_gray> $prefix <dark_gray><st>+----------+");
ctx.source.sender.sendRichMessage("");
ctx.source.sender.sendRichMessage(" <gray>Author: <aqua>" + Plugin.pluginMeta.authors().get(0));
ctx.source.sender.sendRichMessage("");
ctx.source.sender.sendRichMessage(" <gray>Version: <aqua>v" + Plugin.pluginMeta.version());
ctx.source.sender.sendRichMessage("");
ctx.source.sender.sendRichMessage("<dark_gray><st>+----------+</st></dark_gray> $prefix <dark_gray><st>+----------+");
should i use MM dynamic replacements?