#adventure-help
1 messages Β· Page 1 of 1 (latest)
see #announcements
hiiiii
whats this?
wow
Fifth
Wow
hi
same, havent heared of adventure yet. checking it out rn
Allows for stuff line MiniMessage
hiya all
hi:)
ahhh okk, dev stuff
Kinda but kinda not
Dibs
hell yeah
yo
yoooo, welcome new official papermc devs :D
Hello!
Xd
π
party time?
hello
Isn't Kezz a Mcc dev?
20+ messages here and all off-topic 
this merger is really cool, Adventure is a great thing
Is this the adventure with the components and shit? Or am I brain dead
Oh hell yeah
Bingo
But things like the ansi serializer and compatibility with other platforms will keep existing right?
Considering #adventure-platform-mod-help exists, probably so
hey!
Adventure is a library for server-controllable user interface elements in Minecraft: Java Edition.
Mainly plugin developers
yo, this is sick
Oh damn no thx skript my beloved
lol really not many people know what that is?
Looks like it π
is there any images or smt abut adventure?
It's a developer thing, there is nothing to screenshot
A ton of folks here are admins, not developers, which means Adventure won't affect them as much
i mean do you count my terrible handwritten design drawings?
yea but what does it do
like "built with Adventure:"
(Though I expect help with Minimessage as an admin will be directed here now)
like, server admin side MiniMessage is the most visible thing yeah
Okay, that makes sense.
It's how developers do formatted chat and items and such
But it already was in Paper, wasn't it?
Like putting colors and clickable links and such
Adventure is mainly a text component library. Makes it easier to create cool text components for chat, and other places.
Yes Paper has used it since 1.17
yeah, it's mostly an administrative change lol
Yes, but just as a library. Now the project is under the PaperMC umbrella, similar to Velocity. Velocity also was originally an independent project before Paper adopted it
pretty cool
what does "user-interface project" even mean
announcements were looking dry anyway
Minecraft text
The ways you interact with users are inventory and text, adventure is the text parts π
Guys, Adventure is (in my experience of using it) a library that allows developers to make text components, work with sound events, bossbars and everything else more conveniently, there's nothing to screenshot and show, you have to try it.
this channel opened 10 mins ago damn?
Oh yeah, and bossbars and sounds and such
it may never come, as folia is mainly for large servers with high end hardware and teams of developer in first place...
so i guess its not like a full merger?
can we get a minimessage channel
adventure still exists as a project and supports non-Paper things so not a full merger
whoop 
t
guys, do you think using components like this is more convenient than the standard library?
I'm not sure why, but on the line where gradient is, I can't replace it. Is this a bug?
Code: https://pastes.dev/KjNAaoxrbe
because gradient splits your component in many different small components
Use Minimessage placeholders, don't replace it after the fact (that's breaking because each letter is split up into a differently-colored compoinents)
no, since thats one component
Static color
"Text" color1
Gradient
"T" color 1, "e" color2, "x" color3, "t" color 4
Use placeholders or do the replacement before you deserialize it
I dont get what adventure is for and what it is used for
Adventure is (in my experience of using it) a library that allows developers to make text components, send messages, work with sounds, bossbars, tab list, chat etc. more conveniently, there's nothing to screenshot and show, you have to try it yourself in your plugins.
So just an easier way to display ui components
Dope
Adventure is a library for server-controllable user interface elements in Minecraft: Java Edition.
kinda
It's been in paper since 1.17 so there is nothing new if you're making plugins
It's just some organizational changes
1.16? Somewhere around there
Never touched it lol, I used to use Spigot until I realized paper is just better.
Mostly never made plug-ins except some security plug-ins to link with my backend
ClickCallback is updating itemstack to air ? In the image I had clicked on the message which displayed that I was wearing the helmet, then i took the helmet off, but the callback shouldnt update ?
Can you share your code?
The callback code will always be called when you click, it doesn't store any state
contentToUpdate is outside the callback area, so it shouldnt be touched besides running through the loop
Mmh, those arrays might be a live view and you need to clone them, can't check implementation of those two get methods rn, am on mobile
Well, you can try cloning it
But that's the only way I can explain the behavior you are seeing rn
When will adventure fully gets implemented in velocity? Atleast the sound part
Is there an issue explaining what is missing?.
If so, people can start working on it π
Sound can be done in newer versions, but, for older versions that will never happen
This is generally just the joys of a 10 mile todo list
so uh wahts adventure
It's the way plugin devs send messages or set the lore of items and stuff
Let's go
what's this
Adventure is a library that provides cross platform API for text, sound, boss bars, action bars, etc, etc
If you've used Component or MiniMessage anywhere, that's adventure!
Is there a plugin using Adventure yet?
Component.text() is from adventure
Plenty of plugins yeah
Ohhhh, that's cool!
so, all plugins that do not use legacy chat 
yep 
One question about this merge, does this mean the JavaDocs will also get merged or will they stay separated?
Adventure is still independent of Paper the server software so yes the javadocs will remain separated
I'm not sure what our plans are in terms of moving over to the paper docs, but nothing for a while as it's low prio regardless
i think they mean whether the javadocs will be hosted on jd.papermc.io
/adventure or something
they will certainly not be merged with the paper api jd
Uh sometime ago some paper team guy told me that adventure is implemented except sounds and books
thats what I meant actually
now that I think of it, I realise why its stupid
Hey, forgive me if this is obvious, but does Kyori have any way to test effective equality, rather than data-structure equality? The easiest example being an item's display name set via meta.setDisplayName("Hello") vs meta.displayName(Component.text("Hello")), though my question isn't just limited to that.
Like, let's say for whatever reason that someone did:
final Component lhs = Component.text("").append(
Component.text("").append(
Component.text("Hello")
)
);
final Component rhs = LegacyComponentSerializer.legacySection().deserialize("Β§rHello");
Is there a strategy somewhere of how to test whether these 'compile' to an identical chat message?
Hello does anyone know if the Adventure is the same as the Minimessage format?
How do I get it on my server?
It's built into Paper already, has been for years
it's included since like 1.16.3
Plugins support it (or don't, if they're outdated or making... interesting... choices)
Cuz I watched a video by 'KassaiSora' on yt ABT using the Minimessage format, and he also said about installing Carbonchat, but when I use the <colour> tag in my paper 1.20.1 server, it comes out as plain text π¦
Yeah, CarbonChat supports minimessage. Talk to them for further help on that.
Also, you really need to upgrade your server. It's full of exploits
I don't even know what Carbonchat does, I just installed it
It's a chat plugin. Read its docs.
Does essentialsXChat support it
But some of the plugins I use haven't been updated yet
Those plugins are surely dead at this point, if they're not updated past autumn 2023.
It's time to move on. It was time to move on a year ago. A full year ago, you would have already been past the point where you should have been on 1.20.4, abandoning dead plugins.
B-But they're no alternatives
I just think mojang updates are just too frequent but don't add/remove/change alot
The updates have been pretty spread out. Dead plugins are just dead. If you want to continue this chat, let's take it to #general , as this channel isn't meant for explaining to people why they shouldn't run exploitable software.
1.21.4
??? π
Okk
the very latest, previous versions have known, widespread dupe and crash exploits
Ok can someone still explain to me why MN format isn't working
Please
Does it support EssentialsXChat?
MiniMessage format works fine. Your issue is with a plugin. I already told you to look to that plugin for help.
Carbon 100% supports adventure. I don't know about EssX, but you could ask them.
What do you think is the best message formatting plugin
I like Carbon
Idk how to configure it, the data folder is empty
Okay.
If you ignore the suggestion of reading their documentation and looking to their support system, I don't know what else to tell you.
Sorry
Too excited
Also..
Does the MM support GeyserMC?
Do the hex codes work or they get replaced with default colours?
MM is just a component serialiser
Past that, it's up to how your platform deals with the component
That really depends on your use case. I can't really think of a reason to compare components tbh, you could compare contents by using the plain text serializer, but this feels like an XY question
Baaaasically, it's about plugins using display names and lore as custom item identifiers. I have no real control over this nor can I realistically attempt to refactor it all.
I don't understand π
U mean if they support hex codes at all?
So I guessed weird and this is the wrong approach, pdc should be used instead
Adventure doesn't provide a way to do what you want since normally there isn't a need to and it's actually quite complex
You will have to use some form of serializer or just do stuff properly
MM just gives you a component, how geysermc handles that component is generally up to geyser
given that afaik, bedrock doesn't support RGB, they'll likely just downscale it
π²
Just like your other questions about plugins Paper doesn't make, Turbo, this is a question for Geyser.
Oh ok aight
But whyyyy
That's up to Mojang, buddy.
So I cant get any other colour from the ones in the colour kit in essentials?
Nobody said that.
If EssX supports hex, you can do hex in Java. Which Paper is.
Further EssX support belongs with EssX. Which is something I've told you before.
I'm worried by how much you keep ignoring what I say. π¦
They're a protocol translation layer, they'll only support what the protocol supports
So they support hex?
.
You need to read all replies you get to your questions.
no, bedrock does not support hex, bedrock players will not see the full rgb spectrum, java players will
You can use hex inside of a component, but, bedrock will not support showing the RGB, they'll likely downscale it to the closest color it can
Why?!!! π€―
mojang choices
Because Mojang didn't implement RGB support there
it's a limitation on the bedrock side of things
So it's kinda limited right?...
bedrock is
It's only limited for bedrock players. You can still use hex for java players.
So I'm only limited to this on bedrock?:
Which has been stated already, repeatedly.
Ok
It hurts
We support Paper, which is for Java edition.
And I can't use MM!
(67b897ab6ed5010734cf1b87) // @sour silo (@drjoehn / 656146295555358736) has been warned by @wet kestrel (71627708521512960)
Reason: Be polite. There is no reason to attack other users.
Bro π
You can use MiniMessage with Paper plugins. As we have said, repeatedly.
If you continue to ignore our replies and keep repeating yourself, you will be timed out because this is getting too cyclical.
B-but
I sowy
Oh one more thing
I've been looking to modify death messages, is there a plugin that allows you to modify the death messages for each damage/type?. So basically let's say I wanna modify the death messages caused by PvP, in the config or smthg, I can give lists of messages(with the victim+killer placeholders included obv) and the plugin with choose anyone from that category at random to display in game, and so on and so forth for other damage/death type
Pleasee
Yeeaaaah, I agree. Honestly, and this is well outside the scope of Adventure, but it would be awesome if we could register custom materials, but also be able to add item visuals at network-time. Setting a custom-item flag on a PDC is great, but then what if you want some explanatory lore? But then what if later you realise the lore has a typo? If the lore was added at only at network-time, it's never actually on the item, then you can just change the network-time lore without needing to do any kind of DataFixer or similar.
You wouldnt set a flag, you would set a custom item type string as pdc
Oh yeah, that's what I meant
You can also typo-fix the lore on the item by detecting it with the PDC
Just wanted to drop in and say, it's cool Adventure finally merged into Paper!
adventure has been in paper for years
Merged into PaperMC the organisation :p
o_O
π
Where is Sound.Source.RECORD used? Is this used for a music disc? Or is Source.MUSIC used for a music disc?
record is the jukebox slider and music is the music slider in the sound options
Looking at the minimessage docs, there doesn't seem to be an option to define a Fallback?
Would be beneficial to have as translatable components do have a fallback key to set: https://minecraft.wiki/w/Text_component_format#Translated_Text
The lack of support for named arguments strikes again
No clue how such a tag would look like
Maybe use the lack of named args as an advantage?
Like f.e. <lang:commands.drop.success.single:'1':'Stone':fallback='You droped something...'>
Tho, maybe a dedicated tag with the first arg being the fallback would be a bit better to not break existing setups
Or alternatively have an arg prefixed with a specific character to identify as fallback.
And another question.... Can I access translatables from non-mc namespaces (i.e. from resource packs)?
in MM? yea, they are not rendered out
Your reply is a bit confusing... Is it supported or not?
Well "access" is a weird word
you are just specifying the key of a translatable component
you can put whatever you want there
it is only actually "converted" on the client
I wasn't sure, given the file would be in a namespace that isn't Minecraft and I don't know how it would be identified
I don't want to add named args
I am semi certain the lang stuff isn't namespaced
I'd much rather <translatable_with_fallback:fallback:args>
Yeah languages aren't namespaced, they're just keys
I think translatable would be enough.
Just the diff towards lang would need to be made clear.
We already have translatable as an alias for lang
oh, rip
Oh, we don't - but either way that's confusing
Fallback is a pretty niche part of an already niche minimessage tag, I don't want to introduce more confusion. If you need such a tag, PRs would be welcome - but let's keep it clear
(and if you don't wanna PR, an issue would be appreciated too)
Weeeell, yes, but these are legacy items: putting the custom-item-type string on the PDC would have to come after detecting an item with the lore, or otherwise it's effectively voiding any and all existing custom items of that type. It also doesn't play nicely with item.isSimilar, which is how these custom items are handled in code. As I said before, I have little to no control over this.
Unfortunately beyond incredibly lossy serializers (e.g. plain text) or insanely complicated methods (e.g. idk, pixel comparison of rendering or smth) there are no good solutions for "effective" comparison because it doesn't make much sense
Fair
There are some bad solutions, you could try compacting both components and just hoping they end up the same
But yes, identifiers in PDC are what you (or whoever's code you're inheriting) should've done from the get go
Another question though: does Kyori have, for want of a better word, component regexes? The XY of this is waypoints in chat messages (eg: [name:Some waypoint, x:5, y:0, z:125]), where a mod can find and replace that specific segment of the chat message with a clickable.
Oh, this code comes from before PDCs :P
This code goes back to serialising custom data as section codes in the 0th line of lore xD
Well, yes, regexes exist :') See Component#replaxeText
That was never a good solution
Agreed
can recommend a full on DFU abuse during the next version upgrade of your server
but tbf to them, it was the only solution at the time... trying to access item nbt was such a pita
Yeah literally, don't keep shooting yourself in the foot - take your network offline for a few hours and migrate your data
Hacks upon hacks upon hacks upon hacks is not a good foundation
:]
We literally have a plugin called SimpleAdminHacks that's basically like 40 minuature plugins
But yeah, I did contemplate trying to use the DFU, but I couldn't really figure it out, and I don't want to contaminate the item-data updates. So rn I'm PR'ing a way to use inventory open and player login events to find outdated items and update them on demand.
Or that, tho that is a bit uff given it is a continuous thing sitting around
You don't have to use DFU, but the concept of migrations is universally better than layers of hacks in your codebase
Is there a way to use DFU, which uses a separate versioning system?
Yea, back in the day when I did it, I just had a plugin iterate chunks on the server and load them
no
Given we don't control those IDs, we/you basically have to hijack
Migrations also aren't "check a thing every time a player joins" - idk if it would be a good thing for paper to support hacks like that
Exposing DFU is just, not really a vibe 
I'd rather not have plugins fuck up stuff, traceability is ass
We currently have a custom item type, well, kind of, where every(?) single item has a "compacted" counterpart. And this is denoted by whether the item has "Compacted Item" in its last line of lore. Attempting to update this would be such a monumental pita and require so much testing. And then migrating all existing items into the new data structure...
a PITA sure, but what's your alternative?
Continue trucking along with everything still mostly working? :P
Then you no longer need us haha
Hello! What is the way to parse this sign into components (I assume 4 per side)
{back_text:{color:"black",has_glowing_text:0b,messages:['""','""','""','""']},front_text:{color:"black",has_glowing_text:0b,messages:['{"extra":["Test Sign"],"text":""}','{"extra":["Hello!"],"text":""}','""','""']},is_waxed:0b}
Well, the messages looks like JSON so you can use the JsonComponentSerializer
doubt is_waxed:0b is json
It's snbt
oh yeah it is SNBT, the json serializer wouldn't work right?
is there no way to parse these to components
is there anyway to like substring components?
Where do you even get this snbt?
maybe there would be a better way to get the info
TextComponent.content().substring()?
That's just going to work for the singular content of a text component.
This feels like an XY problem. What's your actual desire?
sign text change packet
I don't have access to the actual block
The JSON serialised would work for the messages - not the rest of the nbt
To have a segment of the component..
Actually I resolved the issue using a custom method by serializing the component as minimessage, escaping minimessage tags and then with some math to substring the content with the colours
serializing the component as minimessage, escaping minimessage tags and then
I think plain text serializer would have been easier for this
It wouldn't take colours
nvm, yeah, for a moment thought for some reason that escaping means removing
Can you please share this method?
Why? What would you even need a substring for?.
If you share why you need it, we can point you to a better solution
@misty marten ^
For things like a typewriter animation.
I will send It asap
i feel like you just want a substr of the actual content, not of the components
The best solution for this would be to use a custom flattener that can create a list of components, adding to the list after every new character
Flatteners accept style and content independently, which would allow you to slowly reconstruct the component tree char by char
how to capitalize or toUpperCase toLowerCase a placeholder?
ex: Hello <player>
how to uppercase <player> result
Placeholder.parsed(βplayerβ, player.getName().toUppercase()?
or whatever kind of placeholder you use
what?
nevermind
There are a few questions I feel like can/should be answered in a future faq about the move:
- Will this have an impact on the domain used for documentation, javadocs, etc? Like will it eventually be moved under the papermc.io domain or remain separate?
- Will this have an effect on the dependencies, like group id, repository URL, or similar?
repository url as in github or maven
Any changes made, I imagine, would be made with the same sort of warning we have given for other things. Velocity's old domain still works, and redirects to the new paper site for example, and the groupId remains the same. Not an official statement, just noting previous project absorptions.
github repo's will be moved over, maven stuff will likely stay on central/sona
Is this where I ask why it's light_purple and not pink 
i mean, that's just what it's called
ask mojang why they gave it that name if you disagree
they are pretty much a 1-to-1 copy of this from the 80's https://en.wikipedia.org/wiki/Color_Graphics_Adapter#Color_palette which had 8 colors and then 8 light variants of each (as to why they switched "magenta" to "purple" and brown to gold, who knows lol)
blame miku
Hello, quick question, I think I already know the answer but I just want to know if someone already tried something, or had thought to share about an eventual implementation I could try.
Is there any way to compute a word-wrap operation on a component?
Having https://github.com/KyoriPowered/adventure/issues/499 would make it possible, but sounds pretty difficult to implement. Especially because we do not know the exact value and are thus unable to split some components (translatable being the obvious example).
The obvious use-case is to take a somewhat long component and split it into a list of smaller components, so it can be put in an item's lore without having an overflowing tooltip.
Ultimately, I agree Minecraft itself is able to do it client-side (cough Text Displays cough cough Chat cough) and should provide a way to do so for item's lore as well but... In the meantime it would be cool to find a way to do it! π
There is no API for it - you should be allowing your users to configure lists of components so they can wrap themselves
It's something that would be nice to have, but it would require a lot of work, won't be fully accurate due to clientside font changes, and also has better alternatives (e.g. allowing users to define lists instead of doing the wrapping yourself)
I'd like to, but unfortunately, this is kind of not really an appealing option for me... Just to give a little more insights about my use-case:
First, I am my own and only user, as this is a "simple" plugin for my server. The plugin deals with quest scrolls (you have an item generated by the plugin which gives you a quest to do).
Quests have objectives, like "Break 15 Diamond Ore in the mine", "Kill 50 Zombie, Skeleton, Spider or Creeper in the arena"...
Those objectives are defined through the config file of the plugin, by specifying the type (break blocks, kill entities...), the amount, and which blocks/entities/... count. Currently, the description of the quest (in the item's lore) is automatically generated by the plugin (using translatable components for blocks/entities), which is perfectly fine, except it overflows when given a long list of options. Having to manually write the description for each single quest would be very very time consuming (and a bit counter-productive because if we modify a quest, and forget to edit the description, it would break). And I also cannot really generate the description with line breaks, because with smaller list it would not be really good:
Break 15
Diamond Ore
in the mine
I could make some predefined templates depending on the number of options, but it would also not be ideal. And considering we have a lot of handy methods likeComponent#joinfor example, I thought this would also fit the API well
It wouldn't fit in the API directly as it requires vanilla generated data (the width of every character) but I could see us adding support for automated wrapping of some sort if the user would supply that data
Unfortunately there is no such plans for this as it's quite considerably difficult as I mentioned above
And I don't care about the exact accuracy of the wrap, I just need it to wrap somewhere near the nth character, even if it's approximately
Wrapping with newlines is less complicated (you can mapChildrenDeep and character count, inserting a newline when needed) but in your case you need full splitting which is a lot more complicated
Yeah I understand this perfectly fine, I just share my use-case so maybe it adds a tiny tiny tiny weight about this feature is "wanted by users" π Anyway thanks for the reply, and as a last question, is there a method to flatten a components tree? Something in the lines of Component#compact but like Component#flatten?
Oh
For example (using JSON representation because it's easier to write here), turn:
{
"text": "A",
"color": "red",
"extra": [
{
"text": "B",
"italic": true,
"extra": [ { "text": "C", "color": "green" } ]
},
{ "text": "D", "color": "blue" }
]
}
Into:
{
"text": "",
"extra": [
{ "text": "A", "color": "red" },
{ "text": "B", "color": "red", "italic": true },
{ "text": "C", "color": "green", "italic": true },
{ "text": "D", "color": "blue" }
]
}
(Or basically just the list of components in extra, because the idea is to have a flat result, so no root content/style)
I don't believe we have any API to produce components like that, although I'm not against such a thing being added as I can see the use cases
Your best bet would be a custom flattener impl yes
Ok I'd have a look at it thanks
How does one use gradients without minimessage?
There is no API for it in adventure so you'd have to code it yourself
However, just use MiniMessage and save yourself the hassle :p
There is a WIP PR that was never finished (https://github.com/KyoriPowered/adventure/pull/1063), but the basic idea of it is quite nice (a generic gradient api with a list of positioned stops). I wouldn't want it to be overly complicated (I don't want us to introduce a full set of interfaces for alternative colour spaces as the original PR suggested was the end goal) but I'm happy for it to remain relatively generic to allow consumers to edit it as needed
how to make minimessage with "\"(new line) to List<Componenet>?
You should just allow your users to supply a list
it's much more user friendly and you won't have to mess around with splitting text up
Instead of starting with newline chars, start with a list.
kezz is pointing out that this is coming from a design error.
From what I remember there is something that automatically converts minimessages using \n.
There is not
If you want a list of components, you should start with a list of minimessage strings
hmm... okay
Is there a reason ComponentLike isn't ComponentBuilderApplicable? I mean, it sounds completely possible to add this to ComponentLike to make it extends ComponentBuilderApplicable:
default void componentBuilderApply(final @NotNull ComponentBuilder<?, ?> component) {
component.append(this.asComponent());
}
Am I missing something? It would be handy to use ComponentLikes inside LinearComponents#linear
Especially given that LinearComponents#linear checks instanceof ComponentLike itself, despite not accepting this type
Sounds like a fine addition yea
Do you want me to make a PR or is it something to be handled by your team?
any method for directly list of minimessage(string) to list of component?
All you need is a for loop or streams, we don't have API for that in particular no
oh okay
I have this algorithm I was working on, not really optimized but it works in the cases i tested https://pastes.dev/B5qOKpBQmm (let me know if you find any bugs)
not so well tested lol but wanted to drop it in case it helps
Iβll definitely have a look at it, thanks!
Hey, so I've been playing with the solution to this question β¬οΈ and I've hit a snag and I'm unsure how to go ahead without going full lexer.
It seems like the replaceText code is only testing the regex against individual components, meaning that a component like "[", "name: Some waypoint", ",", "x:5", ",", "y:0", ",", "z:125", "]" would fail because none of the individual parts would match the regex, even though, if they were combined, they would. Then I found .compact(), which fixes the problem if used prior to the regex text.
However, the snag is that, if any of the parts are styled, such as the x, y, z values being coloured red, green, and blue respectively, then .compact() doesn't include it (as expected), and thus the regex doesn't match. I'm not entirely sure where to go from here that isn't backtracking entirely and implementing what would amount to a pet-language lexer for waypoints xD
What is the context of these replacements? Why can they have different styling to begin with?
This is in context to a client, but I figured the context is vague enough and isn't really specific enough to a particular platform implementation. The idea is to replace any embedded waypoint (eg: [name:Some waypoint, x:5, y:0, z:125]) with an identical version of itself that, when clicked, executes a local command for my map mod. However, there are occasions where the server sends styled embedded waypoints, such as the axis values coloured to their axis colours. I could PR to change this for the particular server I play on, but I'd rather have the mod be resilient to what servers provide it than attempt to simplify server outputs to satisfy the mod.
Hmmm, idea
Since I'm replacing the embedded waypoint with an exact content-copy of itself, I could run the regex on a plain-text serialised component, and then add the click event to the components at the specific index. Though I'd need to split the component beforehand and join it afterwards.
Is there a component-equivalent to a String's .split("")?
Yeaa unfortunately whatever solution you're going to end up with is likely implementing cross-component replacement haha. Please do PR if you get around to it!
Okay, I've got something largely working but I've hit another snag: components that, in their literal content, contain legacy formatting codes. This does not work well with character splitting because it splits it into, for example, ["Β§", "a"], so then the chat message just has a random "a", rather than green text. Does Kyori have a "recursively serialise" function somewhere?
those are invalid components
those components are flawed and incorrectly constructed to begin with
I agree, but it seems that some servers still send them :P
But if them being invalid means there's no function, fair enough
that is a bug in their software
It's odd that it's invalid though, since the Minecraft chat still works with it
Mojang deprecated the legacy format 10 years ago
using legacy colors inside of components is an artifact of them not stripping that stuff
it would make 0 sense for adventure to add specialcasing for an archiac and deprecated format of which there is no means of defining a sane and consistent behavior for
mojang will remove the rendering of section symbols as style
Oke, since I've somehow summoned three separate maintainers :P is there a NMS function for this, so I can then pass the fully-resolved component to Kyori? Since this code is meddling with the user's chat, I'd rather not remove styling that would be there, even if that styling is deprecated.
what?
if you mean the legacy color code stuff, no
that literally means nothing to anything but the legacy block of rendering code in the client
Maybe you can try recomputing the component if you find an Β§ inside using the LegacyComponentSerializer
There is no method, either supported, unsupported, or in NMS for turning a component containing legacy text into a proper component
thank you
The best you can do is run it through the legacy serializer and hope you don't mind it being lossy
name: "<reset><gray>Close</gray>"
For some reason it always addes the italic event even
ConfigurationSection itemsSection = plugin.getGuiManager().getGuiConfig().getConfigurationSection("gui.items");
if (itemsSection != null) {
for (String key : itemsSection.getKeys(false)) {
ConfigurationSection itemSection = itemsSection.getConfigurationSection(key);
if (itemSection != null) {
Material material = Material.valueOf(itemSection.getString("material", "STONE"));
String name = itemSection.getString("name", "");
List<String> lore = itemSection.getStringList("lore").stream()
.map(line -> "<reset>" + line)
.collect(Collectors.toList());
String type = itemSection.getString("type", "dummy");
List<Integer> slots = Arrays.stream(itemSection.getString("slot").split(","))
.map(Integer::parseInt)
.collect(Collectors.toList());
GuiItem guiItem = ItemBuilder.from(material)
.name(miniMessage.deserialize("<reset>" + name))
.lore(lore.stream().map(miniMessage::deserialize).toList())
.asGuiItem(event -> handleItemClick(event, type));
for (int slot : slots) {
gui.setItem(slot, guiItem);
}
}
}
}
gui.open(player);
}
I even tried adding the <reset> in the code hardcoded
<reset> simply closes all open tags in the MiniMessage string
<!i> is probably what you're looking for, or better, Component#decorateIfAbsent
Ah cool thanks alot!
Hey, anyone know if it's possible to use a transition with a numeric PAPI placeholder? (in-game w/ existing mini-message supported plugins)
Probably? Depends how the plugin handles papi placeholders in minimeseage
If the plugin supports MiniPlaceholders, the placeholderapi expansion is compatible for use in other MiniMessage tags
I wanna send a message to all players with a certain permission, and I feel like using audiences is the proper way. How can I get an audience of all online players who have said certain permission?
I mean there is https://jd.advntr.dev/api/4.19.0/net/kyori/adventure/audience/Audience.html#filterAudience(java.util.function.Predicate), but the audience it provides is just a snapshot of matching audiences from when you call the method.
Why not just loop over all online players & check the permission before sending the message?
yeah I'll probably just do that
I thought that might be considered clunky but I guess that's inevitably what's gonna need to happen in the background anyway
cant you make your own Audience?
I'd quite like the API to have a dynamically filtering audience tbh
well pencil kicked me for posting javadoc links so find 'em if you want, but either implement your own forwarding audience like leah mentioned, or use guava's filtering iterable (Iterables#filter) thing w/ Audience#audience
And if you make a nice generic solution, I think you can open a PR because according to this issue this is wanted: https://github.com/KyoriPowered/adventure/issues/471
This is somewhat regarding the discussion above
In AsyncChatEvent event, event.viewers() returns Set<Audience> and I noticed there is the console and every online CraftPlayer in the set java event.viewers().forEach(a -> plugin.getLogger().info("Audience: " + a));
However i'm not sure how to hide chat messages from specific players?
event.viewers().remove((CraftPlayer) player2)?
this does not feel right to me, is there a proper way?
You can just remove the normal bukkit player, no need to cast. Remember that CraftPlayer is just the implementation of the Player
Fair enough, thank you
Is Audience useful in the scenario for making "chat rooms"? (players are divided into groups/rooms and can only see each other's message if they are in the same group)
I can't imagine not making spaghetti code inside the chat event otherwise
(or I fully misunderstood what Audience is used for π¦)
You can definitely take advantages of audiences to simplify your code yes!
An audience is "something you can send things to". You can have a single audience per room, with the appropriate players inside, and when a player sends a chat message, you set the viewers to the room he's in
What makes audiences useful is that a single audience can be forwarding to multiple players/console/admins...
So you just have a single receiver in your code, yet it represents everyone that should receive the messages
And the audience adapts to the receiver's abilities: You can show a title to an audience forwarding to players and console, and only the players will see it, because there's no way to show a title in the console
declaration: package: net.kyori.adventure.audience, interface: ForwardingAudience
But the console's implementation of audience will handle this filtering for you, no need to worry about that yourself
(that's part of the contract of Audience - if an audience doesn't support a method, it will silently do nothing)
I wrote this code first time when implementing chat rooms π ```java
@EventHandler
public void onPlayerChat(AsyncChatEvent event) {
Set<Audience> viewers0 = event.viewers();
Set<Audience> viewers = new HashSet<>();
ChatRoom channel = plugin.getChannel(event.getPlayer());
viewers0.forEach(audience -> {
if (audience instanceof Player receiver) {
// both can be null and it is ok
if (channel == plugin.getChannel(receiver))
viewers.add(audience);
} else {
viewers.add(audience);
}
});
viewers0.clear();
viewers0.addAll(viewers);
}If i'm not mistaken, there could be a single `Audience` object representing my chat room (something else will handle adding and removing players from it), and the above method would just become something likejava
event.viewers().clear(); // actually, clear only players, not the console and etc
event.viewers().addAll(plugin.getChannel().getAudience());``` Is this right?
Side note about this code: You might be interested about the Collection#removeIf(Predicate) method
declaration: module: java.base, package: java.util, interface: Collection
If i'm not mistaken, there could be a single Audience object representing my chat room
Yup! Depending on how you've implemented chat rooms, you could even make your existing chat room object implementForwardingAudience, so that the chat room object itself is an audience (i.e. no need for another field)
It might be easier to just have a single Audience field instead of having to implement all the methods imo (composition instead of inheritance)
ForwardingAudience implements all of the normal Audience methods by default. There's only one abstract method, which takes a collection of Audiences that stuff should be forwarded to.
Oh yes, I forgot about this!
I see a static factory function Audience.audience which i can just call with a list of players
I'm assuming this is bad (that's why i crossed it out) because it creates a new audience every time this is called, but if I keep a single ForwardingAudience is it possible to add and remove audiences from it on the run? Or does it take it directly from this java public class ChatRoom { private final List<Player> members; public ForwardingAudience getAudience() { return Audiences.audience(members) } }List every time it requires?
(The entire point of that interface is specifically to make stuff like this easy to implement)
Yes this sounds like what I need, yay
Which method to override though? there is a lot of sendMessage overloads
Use IJ's "implement" keybind (Ctrl+i) instead of override (Ctrl+o), it should prompt only the unimplemented abstract method
(Quick check, the one you're looking for is Iterable<? extends Audience> audiences())
Javadocs are your friend:
Creates an audience that forwards to many other audiences.
The underlying Iterable is not copied, therefore any changes made will be reflected in Audience.
-# src
declaration: package: net.kyori.adventure.audience, interface: Audience
oh wait it makes more sense now
I thought i'd have to override sendMessage and put all the broadcasting logic in there and it worried me that I'd have to do the same for the rest, sendTitles for example
it showed all methods unfortunately
Wierd.
It's okay, thank you for taking your time writing all these things out β¨
Actually it's subtle in the new UI, but in the normal UI you can see it's the only abstract method that requires implementing
it's just a slightly different icon here too xD
Yeah, but I feel this is more contrasted with the vertical bars than the "dashed" style of the new UI
Or I'm just more used to it, maybe x)
Anyway, it's not obvious, but now you know
Doesn't the UI also just autoselect all the methods you don't already have that you have to implement?
Weirdly, no, I just tried and using the "Implement methods" quick fix just showed me this dialog
But I thought the same before, hence why I checked
hello
Does anyone know how I can add custom tags so that they can be used on the server?
Or if there is a base project that shows this. If you basically took the .jar and put it in the plugins folder, you would already have the tags as an addition
Looking at this section, I have no idea how to register the tag so that it can be recognized globally
i mean that would be kind of be a nightmare for compatibility if any plugin could just set shove its own tags as default?
i guess you could technically provide your own minimessage service provider, but like, your platform would already have one specified and I don't think you can have two judging by the repo https://github.com/KyoriPowered/adventure/blob/main/4/api/src/main/java/net/kyori/adventure/util/Services.java#L69
why do you need your tags to be "global"?
In my maven project I have the paper dependency, adventure is already implemented together as mentioned in the paper documentation, I wanted to know how to create my own Parser Directives
The "global" would be the possibility for you to use the tags you created in any other plugin that supports minimessage
You can create a package full of parsers, in addition to those standard ones in the Adventure documentation
I just don't know how to implement this, because I'm still a noob at creating plugins XD. But I have the ability to understand complex code
https://github.com/KyoriPowered/adventure/issues/696 would allow global registration
For situations where users may want to have multiple sources contribute to a TagResolver, it may make sense to have identify tags by Key rather than just a plain value. This would have a default na...
You could try MiniPlaceholders and register the placeholders you want, it will work with all compatible plugins
@prime sigil The problem with using miniplaceholders is that it only works for String interpolation, creating a parser directly through TagResolver, allows the modification of strings between closing or opening tags
An example in the Minimessage documentation is the use of <clear>, a custom tag just for example
It would even be possible to create a swearword filter system, where such words would be replaced in red. Anyway, lots of ideas.
"PaperAdventure.registerParser("key", value -> {})
Something along those lines
@sterile rampart thx for info, From what I understand, it would be a contribution to the project itself. But what most people would like is for it to be possible on their own servers to have their own tags.
I don't know if I misunderstood, but I saw an issue where a guy tried to create a custom tag <list to format spacing in lists
I don't have the issue link to send you at the moment, as I was trying to understand what was being discussed there.
how can i remove the shadow from a component?
declaration: package: net.kyori.adventure.text.format, interface: ShadowColor
perfect thx
π€¨
I think it is obvious that I have never used Modifying, but that would be an interesting idea
@prime sigil That's exactly what I wanted to get to, thank you for your help. However, my intention is not to do a filter project, something else
Now that I saw that the creator of the expansions was you HAHA
π
fun resolveTags(string: String, tags: TagResolver): String { // Resolve tags and then un-resolve LOL
return miniMessage.serialize(miniMessage.deserialize(string, tags))
}```
This can't possible be the best way to do this D:
Essentially, the API I'm using wants a list of strings because it has it's own MiniMessage thing going on. Now, I have a list of tags which are bundled in that TagResolver which I want to resolve before passing on the string list. However I can only see this as a valid method of doing it?
Unless I missed something on the JDocs
should ask that api to add a way to pass your own tagreaolvers to it
That would be ideal, but is there a method in Adventure ( I can't find one ) which would tags.replace(string) or something
without parsing to a component D:
One last question, is there any way to force the expansion to work in any plugin? But this would have to override the minimessage class I believe
As seen in its documentation, there must be plugins compatible with the miniplaceholder plugin, it would be interesting if the miniplaceholder.jar did something like that, injecting/modifying the main minimessage class. This would allow plugins to not need the miniplaceholder hook
For example, I use a plugin called Socialismus, it supports Minimessage, but I wanted to use my expansions on it too. For this I depend on the author adding support for the miniplaceholder hook...
The way your plugin is built is perfect, but I believe that what I said would be the final touch to complete the implementation.
The problem with that is that it would create unwanted situations and possible exploits.
For example, you would not want a player to access all the data contained in your server without restriction, so you would not parse the player's input with the MiniPlaceholders placeholders. But by adding the MiniPlaceholders TagResolvers globally, you would be making every plugin that uses MiniMessage.miniMessage() able to access that data, including chat plugins.
A very common example of this is using PlaceholderAPI, you will never see a chat plugin that allows player input to be modified by PlaceholderAPI as it can display sensitive information such as IPs
I take that reaction as a no 
Heck even just the default tag resolvers you wouldn't want to let user input have access to
Anything handling user input would have a custom MiniMessage instance so even if you could inject into the default one that wouldn't help
You might be surprised to know that practically all plugins use simply this
But selectors and NBT...
I'd consider any plugin passing user input to the default instance to have an exploit
Well, unless it limits user input to admins or whatever via permissions
i mean tbh those kinds of plugins don't do resolution on the components so it ends up not mattering lol
fwiw it is a long term goal to have a global mutable tag registry, but there's just a lot of hurdles in the way of that first
one thing I was thinking about was making context able to check permissions and giving all tags some sort of permission that can be set
Canβt wait to buy a rank for 10β¬ just so I can change my chat styling and add a click event to give me permissions to every message I sendβ¦
Hi all, this might be a long-shot, but given a Component that is comprised of many bits of formatting / colors / etc., is there a way I could split this component into multiple Components whilst retaining the formatting across lines? Context here is having a long MiniMessage formatted string that needs to be applied as lore on an ItemStack, but without splitting it the ItemStack's lore would get super long. I'm also fine with any other way to represent a MiniMessage format / Component that indicates line breaks of some sort.
One naive approach I could think off is to convert the Component to a plain text string and stripping out any MiniMessage tags, then wrap the string, then somehow trying to piece back together the MiniMessage tags, but this feels like an absolute nightmare.
Hm, I see indeed an issue open for something like this (#499). I might give it a think and a look in the source code of Components (as I am not at all familiar with this), but can't promise anything.
Thanks for the response nonetheless!
Hello!
What's the best way to define dynamic tags* in a MiniMessage instance?
*By "dynamic tags" I mean to have the ability to add / remove some later, at runtime. Note that unlike most other, I do not want to modify tags globally, simply have my local MiniMessage instance to which I can decide to add or remove tag resolvers based on whatever rule I want.
I am currently considering 2 options:
private @NotNull MiniMessage miniMessage = MiniMessage.miniMessage();
public void addTag(@TagPattern @NotNull String tagName, @NotNull BiFunction<ArgumentQueue, Context, Tag> tagHandler) {
this.miniMessage = MiniMessage.builder().tags(this.miniMessage.tags()).editTags(tags -> tags.tag(tagName, tagHandler)).build();
}
Or having some kind of "default tag handler" if it is possible, that will call a handler whenever it encounter a tag it doesn't know about, and I can resolve it myself from, say, a Map<String, BiFunction<ArgumentQueue, Context, Tag>> that I could dynamically populate in my addTag(...) method.
I don't really know what's the best option here, because since the MiniMessage instance is unmodifiable, I feel like solution #1 is "cheating" and solution #2 would be better, but in the same time I don't even know if solution #2 is possible (is it possible to handle all unknown tags with a single handler?)
you can provide tag resolvers in deserialize method
Oh yes I know about that, that's true it is a third solution I didn't mentioned, but isn't it better to have them registered in the instance so that it simplify using it?
you can't dynamically register tag resolvers, so that's the best solution actually
And also what's the performance difference between registered tag resolvers and dynamically added one, if any?
I don't think there would be any difference, registered or not tag resolvers work exactly the same
Interesting, I wonder then why they made the MiniMessage instance immutable
most likely design choice, not sure tho
personally I think it's better to provide a serializer with static options, than with dynamic
Oh I just found how to do my solution #2: I just need to write a custom TagResolver implementation
Component to String?
for what purpose?
component to normal text
Stripping out all formatting, colors, hovers, etc?
There's a plain text serializer for that purpose. For curiosity, what do you need it for?
I dont even know how to explain this
trust me
Just trying to watch out for the 'wrong' uses of it, like when we see people use it to compare item names to then do things with that.
ye ok let me think
I have a string with placeholders in the config (ymal).
I currently use String.contains() to check for the pattern and as I am writing this down I remembered the time I used the component placeholder methods and that I could use that insteadβΉοΈ
...
Are you trying to replace placeholders into a component? Just use minimessage.
ye just remembered about that
TagResolver, right?
usually simpler to use the Placeholder class
works like magic thx
how do I strip all styling, hover events, etc. from a component?
The plain serializer does it, but can you clarify why you want it? Lots of folks do it for bad-coding-design reasons that bite them later.
it's just a niche thing I'm using to parse commands from signs, which means I already put it through a json serializer
(like, if you want to clear styling while preserving translatables and such you'll want to convert the component to a builder and mapChildrenDeep to set the style to an empty style on each element)
putting it through another serializer is probably bad but idk, maybe adventure is that performant
I don't care about preserving translatables
parsing commands from signs seems not super practical tbh cuz of length limits, but plain serializer is probably what you want
if its not displayed you could use PDC/storing custom nbt
funky, there are custom payloads though
you mean like the custom payload packet built into the server, that plugins can interact with?
it's restricted to a byte array up to your control so i think you could manage to put something nice there :p
Hey. Im trying to seperate a part of a component.
When you kill someone you are given a Component deathMessage
And sometimes it contains the info about the weapon that was used (look image)
for this part of the message its possible to hover and see more information
How do i seperate this part from the whole message? and is it possible?
seperate it, why?
Like, you could always walk the tree and look for the translatable component and grab the args from it, pretty sure that would work
if i want to reconstruct the message with the used item elsewhere or formatted seperately from the rest of the message
tree?
are you on paper?
Like, paper just exposes that as the ItemStack#displayName() or something
otherwise, there should be an nms method for that
i am on paper
otherwise, yea, components are 'just' a tree structure
How do i get rid of the color of the weapon?
deathMessage = deathMessage.color(NamedTextColor.GRAY);
for (Player player : Bukkit.getOnlinePlayers()) {
player.sendMessage(deathMessage);
}
result
I'd suggest looking into the component manipulation APIs provided by adventure
It's pretty hard to explain what to do loosely if you're not really familiar with how components work
alrigh thanks
MiniMessage
.builder()
.editTags { builder ->
builder.tag("party_prefix") { args, ctx ->
Tag.preProcessParsed("<pink>PARTY <dark_gray>βΊβΊ <#49b6ff>")
}
}
.build()
Will the party_prefix be able to be closed?
So like this <party_prefix>Test</party_prefix>
I believe so? Just, ofc, it's not going to magically know what to do with any contents
I just want to make aliases for colors for example, so i can change it globally so for example <text_color> will redirect to <gray> and it would be nice if they are able to be closed, i think ill just try and see
No, pre process tags just insert the literal content, they are not closable iirc
You'd want to use an inserting tag, e.g. Placeholder.component
Oh, yea, I derped on that front, ^
builder.tag("text_color") { args, ctx ->
Tag.styling(
NamedTextColor.GRAY
)
}
But this would work?
Yes that would be closeable
And Tag.inserting is also closable?
ty
So I started the adventure-web-ui on a server as a daemon, now I literally cannot kill/stop/anything it. Force killing the pid just respawns it instantly, there is no GradleDaemon running in ps, and I have restarted the box. What in the holy hell is keeping it going?
What is adventure favor against legacy system?
because idk it just seems complicated and I dont see why I should switch
@shrewd nest Could you explain why its outdated? and what adventure does better since your reactions aren't really helpful
legacy is nothing more than a collection of hacks and it hasnt been relevant for as long as some people in this discord have been alive
why "hacks"? I want to know what adventure does
with adventure you can easily use hex colors hover and click messages and much more
Adventure supports all the features of minecraft's component system while legacy does not, think of stuff like hover text, smooth gradients, clickable stuff
But they are possible?
ah okay thanks a lot!
legacy Β§xΒ§FΒ§FΒ§0Β§0Β§0Β§0HΒ§xΒ§FΒ§FΒ§5Β§FΒ§0Β§0eΒ§xΒ§FΒ§FΒ§BΒ§FΒ§0Β§0lΒ§xΒ§DΒ§FΒ§FΒ§FΒ§0Β§0lΒ§xΒ§7Β§FΒ§FΒ§FΒ§0Β§0o Β§xΒ§0Β§0Β§FΒ§FΒ§3Β§FmΒ§xΒ§0Β§0Β§FΒ§FΒ§9Β§Fy Β§xΒ§0Β§0Β§9Β§FΒ§FΒ§FfΒ§xΒ§0Β§0Β§3Β§FΒ§FΒ§FrΒ§xΒ§1Β§FΒ§0Β§0Β§FΒ§FiΒ§xΒ§7Β§FΒ§0Β§0Β§FΒ§FeΒ§xΒ§DΒ§FΒ§0Β§0Β§FΒ§FnΒ§xΒ§FΒ§FΒ§0Β§0Β§BΒ§FdΒ§xΒ§FΒ§FΒ§0Β§0Β§5Β§Fs
minimessage <rainbow>Hello my friends
that took me WAY too long
no idea why i did that manually
damn i forgot the spaces and everything was uppercase
ah okay
The legacy way also just isn't how text has worked in Minecraft for over a decade
wdym?
Behind the scenes Spigot/Paper has been converting that to components for you
oo so they have been working as components?
This project didn't make up components, that's all Mojang, since 1.7.1
This project just lets you actually use them instead of just converting the limited functionality the legacy system had to keep it working with components
is the legacy planned to be removed any time soon? since its deperecated
the client can still render some of it in some parts, and probably not any time soon
since that would break a huge amount of plugins
wdym can still render some of it
Some Day β’οΈ
the motd for example will probably never drop support for it since you can ping any server version with the latest client version
hypixel for example actually sends the motd as legacy
also I am unsure if its my issue but when seeing hex colors it varies on diffrent clients like I see #FFFF00 as yellow but on vanilla mc its black
Did you intentionally put an invalid hex code there?
its yellow but I miss typed it
my guess is because it saves a little bit of bandwidth and they dont (want to?) have version specific motds
fixed it
i know that liquid bounce messes with the rendering of components and colors but i doubt that it shows yellow as black
probably something like viafabric or viaversion (on the server)
both clients are same version one is lunar client and one is vanilla mc
and there is no via
because #FFFF00 is translated to Β§x...Β§0 which in turn means black
FFFF00 is yellow
i know but neither bukkit nor the client know that
yeah but I dont understand how 2 clients have 2 diffrence colors
Hold on
i daubt thats client related in this case
Do you mean <c:#ffff00>Hi, component API, or legacy jank?
and which client version
What would be the best way to leftstrip from a component?
the best way is to trim it before it's a component! failing that, see replaceText - match characters, replace whitespace with blank strings and end as soon as you hit a non whitespace char
I recently ported Grim's command system from ACF to Paper and made the entire project cross platform and was looking to improve command/text translations.
I was gonna do my own thing for translating text until I saw adventure had support for server-side translation, but I don't really get how it works and I'd like to make sure it can replace my original plan:
My idea was to do the following:
- Intercept Client Options packet
- Decode to find client language and set a
grimPlayer.languagefield for each player (which defaults to server language)
Create a method grimPlayer.translate(key, "fallback-text")
The idea would be
- we would read from a file defining translations for the key in the player's native language
- if that key doesn't exist we would fall back to that key in the server's default language
- and if neither exist we fallback to the hardcoded text.
I would like to however minimize custom code and would prefer to use common library code to achieve these goals.
How do I achieve equivalent behavior in adventure? With the proper fallback order and hardcoded default text? Is getting the player's language supported on all platforms and not just Bukkit? My packet based approach would work on any platform but how does adventure get a player's language on Fabric and Velocity?
(And yes all my text uses components already)
basically you register your translations to the GlobalTranslator
https://jd.advntr.dev/api/latest/net/kyori/adventure/translation/GlobalTranslator.html
as the javadoc states, you either use
TranslationRegistry, which you create usingTranslationRegistry#createand usesMessageFormatfor the translation strings
or- implement
Translatorand decide your own translation logic (where to source translation from, how those translations are converted into a component, etc.)
TranslationRegistrylets you set a default locale, and withTranslatoryour implementation could decide to fallback to another locale if you want
and adventure gets the locale the same way you do - the client sends their locale setting to the server, and the adventure implementation sources the locale from the platform
if you implement Translator, then the locale is provided when the global translator calls Translator#translate
what you want to do is very much possible with adventure
Whatβs the simple way to get a safe MiniMessage instance? By safe I mean only tags that present no risk being used by players, such as colors, decorations, and gradients for instance, but not NBT, click eventsβ¦
I just know about MiniMessage.standard() (all default tags) and MiniMessage.empty() no tag at allβ¦
You can individually enable or disable tags just as you want
Is there some sort of cache with adventure-webui? I swear to god i can make local changes that reflect in my forked version, but when I push them to our real web server, the changes (seemingly in the .kt files) for real just don't take. Also, running it in -PisDevelopment=true doesn't seem to matter.
I can confirm the .kt files on the prod server are correct
-# unrelated but not having a #webui at all anymore is understandable? but also sad π¦
Well, your browser will be caching the html and js yeah
Make sure you're hard reloading
nah it's not browser-level stuff pretty sure
tried the various ctrl-f5's of the world etc
it's just effectively a static file server, it can't cache files across builds
id assume you might have some cloudflare cache in front or other similar things?
Will converting components to native text convert the translated text? On Fabric I am not using adventure-platform-fabric because its version-specific (my mod supports multiple fabric versions in one jar). I have a PlatformPlayer interface, the implementation on Fabric looks like the following.
@Override
public void sendMessage(Component message) {
fabricPlayer.sendMessage(FabricConversionUtil.toNativeText(message));
}
private static Function<Component, Text> nativeTextMapperFunction = (component) -> Text.Serialization.fromJsonTree(GsonComponentSerializer.gson().serializeToTree(component), DynamicRegistryManager.EMPTY);
public static Text toNativeText(Component component) {
return nativeTextMapperFunction.apply(component);
}
Does the TranslationRegistry depend on platform specific behaviour?
it works? What's wrong?
I'm sending text what would I ever need to lookup in a registry besides translations?
hover event show item
your testing working does not mean every case is correct
fair enough I guess I'd like to know what breaks if you do
look at issues on platform-mod
I don't see anything related to hovering
I know I searched through closed issues
for "translate" and "hover"
and I got two results
and cover just led me to a completely unrelated issue
Ok so I just need to pass in an instance of BuiltInRegistries.Registry or whatever it is
that's fine
interesting didn't know that though
still not true
not sure if that would've ever come up but its good to have the case covered
datapack registries are a thing
I don't really care I'm not going to lie...
I mean I guess I could look through each one with a wrapper function
but I don't think that's all that important
you're putting in a lot of work into a worse implementation lol
unless you have a simple and easy way to add this, support for grabbing entires fro data pack registries is really not on my priorities list
I do, it's called adventure-platform-mod
Yeah and it has all the issues I feared it would
lots of minor ones but most importantly there's no multi version support
if this isn't possible in adventure I"ll just go ahead and do this
but I'm really hoping I won't have to do something like this
I'd rather stick to adventure APIs for accessability to future devs
I suppose I"m putting a lot of thought into it but I haven't written the code yet
I'm looking through the docs right now and I don't see anything about datapack registries?
what docs?
uh I googled first and went to the paper page and right now I'm downloading the javadocs
what javadocs? vanilla minecraft doesn't publish those
I enabled download javadocs in gradle and its downloading something for adventure
like you're making stupid choices with systems you don't understand, so you're going to keep having stupid problems
adventure is not vanilla minecraft
What "stupid decisions?"
supporting multiple platforms on multiple versions...?
reinventing the wheel, and supporting multiple game versions in one jar in the modded world
when you clearly know very little about the mojang codebase
Maybe I presented this unclearly but I have good reasons to make the decisions I have, give me a second to explain
I'm working on making GrimAC multiplatform. We support Bukkit, Fabric (1.20.1, 1.21.1, and 1.21.4 as of time of writingβyes this will work for most mods so long as they don't add new packets to the game for movement and purely client side movement) and have intentions of supporting Velocity, Bungeecoord, NeoForge, Sponge, etc... servers if possible.
We also support 1.7 to 1.21.X clients on each of these server versions.
Our code is largely packet based, and we handle multi-version support at the packet level (usually behind via but we take care of some packets before viaversion). Because the codebase is largely packet based the platform-specific integrations are rather small. 99% of the code is just screwing around with packets and so the actual maintenance cost of supporting many versions even in the modded space is very low
We have a set of platform-specific interfaces to implement on each platform and that's that. As for Fabric you can take a look at how its organized if you're curious but we have subprojects for each version we directly support. The amount of actual duplicated code is very small (~10kb per version most of which is config files where as the project as a whole is 8 MB)
Our use case for adventure is simply to have a nice cross-platform and modern way of working with text in the game, previously we simply used strings and bukkit color codes. The completely feature of adventure is amazing but it is not required.
I originally used adventure-platform-fabric but after implementing support for Fabric in Grim I realized we hadn't used a single line of code from adventure-paltform-fabric and so I removed it.
I understand Mojang's internal code changes widely between versions. Fun fact Mojang slightly changed the code for determning whether or not you were touching a block in 1.21.2 which caused falses in our player movement simulation model that took ages to fix and reimplemeint.
But the platform and version-specific hooks we need are not complicated. If you consider it reinventing the wheel to add cross-platform abstractions than I suppose from a certain perspective it is but it makes it possibly for us to continually update a codebase while supporting many platforms.
I hope now that you can see a little more of my situation, you can understand I didn't just decide to make stupid uninformed decisions. My choices were made given carefully consideration to the codebase I was working with and the nature of my project.
With that said, is there a way within adventure or platform-specific native code that can be abstracted into working with components to have translatable text, given the confines I"ve described?
If the answer is no I'll go along with my original solution
But I would still greatly appreciate it if you could share your knowledge to point me in the right direction and help me understand the edge cases. With luck they won't be important to my use case but I'd rather with your help be able to make a fully informed decision.
Hi, does anyone know how I can convert a Component to BaseComponent so i can use the traditional .spigot().sendMessage() for cross-compability?
Pls don't
You will lose features as bungees legacy chat components don't support all modern Minecraft features
You want to use adventure-platform-bukkit if you still care about spigot (you shouldn't)
Its not about caring, I don't like Spigot, i prefer paper, but I don't make the rules, there are still people using Spigot, even if is 10% of people, is less 10% of revenue.
Yeah i checked adventure-platform-bukkit, my idea is that MiniMessage will be only available for users that use paper
10% less revenue for how much increased work π
None cause everything is done and is not that "painful"
But i still have to work based on the spigot api, so using adventure-platform-bukkit would allow me to still support modern components?
But having this in mind of course
It's basically an abstraction that you will use to send messages instead of on the player object and it will either use the paper API internally if available or do hacks to make it work on legacy platforms
So if i want this feature to be only available for Paper, I assume i only have to shade this single dependency?
I don't really understand that requirement
Either you want to use adventure components on spigot or you don't
I want to allow Paper users to have the ability to use MiniMessage
I know this is a feature that I can even have on Spigot however I don't see why I would shade the whole minimessage library on the plugin, for that is just better for the user to go to Paper
Why would you withold that from spigot users?
Why are people so obsessed with file size? Lol
MiniMessage us like 20 classes
MiniMessage is already on Paper, i'm just saying if i have to still shade " adventure-platform-bukkit" or not
lol
Is not about file size, if paper already contains minimessage, there is no reason to have it on the plugin, on top of that if people really want minimessage they should be already on paper
Well, if you want one code path for both platforms, you need to shade it on paper too
Yeah I'll have a dynamic system that if is paper, it will support MiniMessage
So in this case what do I have to shade that is not included on paper?
Is "adventure-platform-bukkit" already included on paper, or do I have to shade only that?
No
Alright awesome
Spigot users need adventure API, adventure platform and MiniMessage, on paper API and MiniMessage is available
But the adventure version paper ships might not be compatible with the platform version you ship
Oh i see
Are there any incompabilities from Paper 1.16.5 minimessage platform to now?
No api breaks but new stuff will not be available on auch ancient versions obviously
Yeah it makes sense, but as I'm just working on the API, the text that the user uses is not my business, i should be fine then
If I would enter the painful valley of multi platform multi version support you would just shade and relocate everything and don't depend on what the platform provides
Lol is not that painful but just supporting Paper is more clean and easy i get. I'll try just shading the bukkit platform and if there is any problem I'll just shade everything, thank you MiniDigger
You just got used to the pain, lol
You might be right
1.8.8-1.21.4 support + cross-compability
What is the VirtualComponent? Is there any documentation for it?
If I register a custom tag to paper's instance of MiniMessage will that tag then be available in all plugins that also use the same instance?
Unsure if I should be asking this here or #paper-dev
e.g. it's used in MiniMessage to store a bit of data saying "btw this mess of colours in my children is a gradient from red to blue" so that if you turn that component back into MiniMessage it will know to use <gradient:red:blue> instead
Yes if you're doing it in a fork where you're changing the service provider or smth, but you can't modify the global MiniMessage instance normally
Hmm, interesting
Can I do something like a <plugin-prefix> tag with it?
And have a second component that replaces it?
π€
Well the easiest way to do that is just to use a custom tag resolver with MiniMessage e.g. Placeholder.component
Yeah, but I would have liked to serialise the component..
Ahh ok, do you think there would ever be API to allow registering custom tags on server startup, or would that be out of scope? I want to add some custom tags to make my life a little easier, mainly shortcuts for long gradient definitions aha
I will try it anyway, and see what I can achieve..
Yes, that is a long term goal of ours! Just a few hurdles in the way
Well in that case look at the gradient tags and you'll see an example of how they round trip it
Ooh ok, that's awesome, do you happen to know if there is an issue/PR already open for this that I could keep an eye on?
I'll make one
Thank you so much!
It would be nice to allow plugin devs on platforms that provide MiniMessage a way to mutate the tag resolvers available in the global MiniMessage instance. There are a few steps required before thi...
Thank you!
How does Tag.styling() works exactly? There is an example provided in Adventure's docs:
TagResolver.resolver("click-by-version", (args, context) -> {
final String version = args.popOr("version expected").value();
return Tag.styling(ClickEvent.openUrl("https://jd.advntr.dev/api/ " + version + "/"));
});``` however I'm wondering how would I append text somewhere near, can I do `<click-by-version>Some text here</click-by-version>` in that case?
Yeah that was it, just escape tags lol
Hey, when implementing a custom placeholder tag for MiniMessage I noticed that the Context doesn't pass down its Pointered target when using Context#deserialize. My placeholder tag uses the target to determine what to replace and when using it as with in a <translatable> tag this breaks. An example string that doesn't work would be <translatable:example.key:'<placeholder:lolxd/>'/>. When deserializing this string with a target it doesnt get passed down when the arguments are deserialized.
As a workaround I implemented my own translatable tag that passes the target to its arguments correctly, but I feel like this should be the default behaviour. Before making an issue on github about this I wanted to ask if this was intended.
Yeah that does sound like a bug - an issue would be appreciated, a PR to fix even better!!
Sending a Spark report in the adventure channel?
A person just pointed me here
Thanks for sharing! I'm not sure if I can see where your performance issues are though? Your max MSPT is only 37?
Yeah done a big look through that spark and there are no performance issues there so I'm not even sure what issues you are talking about
There's not even really anything we could feasibly do to improve that spark. I mean, the only thing I can think of is writing a non-throwing parseDouble/parseInt but like,,, let's not be silly haha
Its not that bad though? Once you set it up once there's like 0 maintenance cost
If you need some help with project setup for multi-platofrm multi-version take a look at ^
You pay a cost every time you look at that code, it's more complexity
Not true, there is a small, almost unnoticeable at first, overhead right there, after analysing the code of parsing ints and doubles, which can be backed by the spark profiler he sent, but its effects are observed when the method is called too many times, in a short period of time.
What overhead?
You mean what I mentioned here? :p
Yeah
Because I'm one at the server, this gets exponentially worse with each loaded hologram
The "expensive" part isn't the parsing it's the exception construction
But it also goes back to the Double being cached
Then please do share spark reports when you do have issues!!
That's not a lot, servers have a base level of overhead
Stuff doesn't scale directly
There shouldn't be any exceptions thrown, the value goes into an Optional, which can take null values π
parseDouble throws NumberFormatException
Is there an option to serialize/deserialize a component to bytes rather than serializing it to Gson and writing that as a string?
valueOf doesn't
But it throws NPE if the string is null
Yes it does
Throws:
NumberFormatException - if the string does not contain a parsable number
Oh yeah, it does
Nothing stopping you from turning the string into bytes afterwards
Jesus, why doesn't the java documentation just mark it correctly in the mobile version
it seems like you completely misunderstand what's going on. Double.valueOf returns a Double object while parseDouble returns a double primitive, so changing that part doesn't make any sense
That's what I am currently doing, but it's not as effective as having a dedicated option. I thought perhaps there is already something for this.
The Double object is cached
Not as effective how?
By the JVM
no it's not
the current implementation is literally new Double(parseDouble(s))
It is, exactly like String object is
Won't the Gson string be much larger in terms of the size it takes up, rather than having each data value use it's exact needed size?
what are you talking about? String has an interning mechanism, Double doesn't
Uh, I mean, sure you could write your own serializer that converts to a more packed format but we're talking about bytes here
Do you think that would be somewhat doable? Or has it been tried before and caused issues?
That answer is flawed. The docs only say that the method should be preferred over using new Double(), but there is no guarantee about any caching involved (otherwise, the current implementation would be broken)
Yeah it's been done before, Moulberry has adventure-binary-serializer but it's not updated. Generally nobody has bothered before because it's not necessary
What are you talking about? I'm not comparing to new Double(), but Double.parseDouble() vs Double.valueOf()
Thank you!
Current adventure implementation uses Double.parseDouble which creates a very bit of overhead, which is almost unnoticeable when it isn't abused.
okay, here's the current implementation of valueOf: https://github.com/openjdk/jdk/blob/7c883c284de4fa1cb55f4fd4cf4dc9115bee5e65/src/java.base/share/classes/java/lang/Double.java#L933
Now find the method for parsing
πΆ
yes, that's parseDouble, the method adventure already uses
πΆ
Guava: Doubles.tryParsing(String).
Returns null if the string can't be parsed. No exceptions thrown. More efficient than Double.parseDouble(String).
I don't remember last time i touched Multi-version code, if there are bugs most of the times is on the plugin, not on the multi modules core.
My multi modules are already done, for years now, with small maintenace cost over all this years
What costs more time is literally supporting a new version and in this news versions I just need to clone the module and change some dependencies/imports and that is what costs me more time
Making multi module when you intend to just do one plugin I would say is not worth it, if you want to make a lot of plugins that are wide-known, you have your perks, on top of that paper by itself doesnt support hybrid versions (modded), we have plenty of people that use modded servers
Just imagine somehow Paper contacted all of this modded hybrid softwares such as Arclight, etc... And talked to them to switch to Paper π
Yeah I'd be interested in seeing benchmarks with this (for reference all it does is a regex check before parsing, which we could do internally without guava bloat)
Isn't guava already in paper/minecraft used?
yeah but not in adventure
Hey, just curious, so even if is appearing orange, what really matters is the relation with the MSPT?
Well, I guess at this point, I see why people aren't considering Guava..
I just looked at the source code
It's again using Double.parseDouble
π
I mean, I'm not against using a regex check before parsing if it's faster - I just kinda doubt it would be
Not really, but generally speaking performance profiling is more accurate when done over a larger scale and when you're actually facing performance issues
At this point you could just copy-paste the source code of Double.parseDouble and return null instead of throwing an exception..
And that will be faster..
But this will be too much for 0.05 ms of performance..
Anyway, this runs smooth
If guava says it's more efficient I'm inclined to believe them, maybe I'll throw some benchmarks up
Nothing like a bit of Friday premature micro optimization
It's Thursday tho
Which means they intend to look at stuff tomorrow?
no nico is right i have no idea what day it is lmao
Lol I thought you already had a plan since yesterday you said Friday too about that other thing
well i did some jmh-ing and the answer is "yes it's technically faster to check against a nasty regex" but i've instead opted to rework the gradient/transition tags slightly to avoid checking against the double unless it knows it needs a double or needs to fail
so an identical perf improvement without the hassle of having a nasty regex in our codebase
πππ
Isn't NumberUtils.isCreatable(String) from apache lang a viable option too?
we also don't depend on apache lang either
do we care about supporting anything other than decimal fp strings? e.g. hex fp strings or exponential notation. if not the check can simply be reduced to a simple (?:\d+(?:\.\d*)?)|(?:\d*\.\d+) (or regex-less equivalent to only iterate the string once instead of twice)
i definitely do not care about non decimal fp strings no, but we also don't even need a regex check anyway
maaaybe Infinity and maaybe NaN, there's probably some freak out there using those in their custom tags
at least in gradient/transition tags those would be errors anyway iirc
yeah
but im also not even sure i care much for saving performance on error cases anyway
i mean, it's not exactly unknown that filling stack traces is not cheap, and it can easily be avoided if you know what you're dealing with
it's less of an error case and more of a "this is not the phase argument" case
yeah i've already fixed that by checking the colors first
well yeah but if you do <gradient:#123456:#abcdef> it will still need to check if the last argument is the phase argument by checking if it can parse to a double
yeah but if we check color first then we skip having to always fill the stack trace, instead only filling the stack trace in the case where it's an invalid phase argument
move the resolveColor tag inside the last arg check too?
that's more likely gonna be the more common case, still gonna throw an exception if it's the phase but that's probably less common
β¨ trade offs
i moved the resolveColor check before the check for the last arg entirely
so it'll now go
- is it a color, if so just use that
- are we the last arg, if so try and parse the double
- throw an exception
yes, that's what i'm talking about
,
that is not an error case, it's a "not phase" case, if the exception can be avoided, cool
whether by trying to parse the last argument as color first or by checking if it can be a double before actually trying to parse it and ending up with an exception
yeah the error case is if the last argument is a non-color and non-double in which case idm the overhead of parseDouble there really
but it is a color tho
that's not an error case
it tries to parse it as a double and the exception is created either way
sorry i think i forgot to explain that i already made a pr for this https://github.com/KyoriPowered/adventure/pull/1180
heck yeah
Loool, that looks awesome ππ
I will share with you guys, my very own method to work with MiniMessage because, sadly, it lacks features and deserialization is the only way to use some custom tags, like PlaceholdersAPI tags... here we go:
public class NamedColor {
private final String name;
private NamedColor(String name) {
this.name = name;
}
public String encase(String text) {
return "<" + this.name + ">" + text + "</" + this.name + ">";
}
public static NamedColor BLACK = new NamedColor("black");
public static NamedColor DARK_BLUE = new NamedColor("dark_blue");
public static NamedColor DARK_GREEN = new NamedColor("dark_green");
public static NamedColor DARK_AQUA = new NamedColor("dark_aqua");
public static NamedColor DARK_RED = new NamedColor("dark_red");
public static NamedColor DARK_PURPLE = new NamedColor("dark_purple");
public static NamedColor GOLD = new NamedColor("gold");
public static NamedColor GRAY = new NamedColor("gray");
public static NamedColor DARK_GRAY = new NamedColor("dark_gray");
public static NamedColor BLUE = new NamedColor("blue");
public static NamedColor GREEN = new NamedColor("green");
public static NamedColor AQUA = new NamedColor("aqua");
public static NamedColor RED = new NamedColor("red");
public static NamedColor LIGHT_PURPLE = new NamedColor("light_purple");
public static NamedColor YELLOW = new NamedColor("yellow");
public static NamedColor WHITE = new NamedColor("white");
}```
```java
public class RGBColor {
public static String encase(int color, String text) {
return "<color:#" + Integer.toHexString(color) + ">" + text + "</color>";
}
}```
public class Style {
public static class Bold {
public static String encase(String text) {
return "<b>" + text + "</b>";
}
}
public static class Italic {
public static String encase(String text) {
return "<i>" + text + "</i>";
}
}
public static class Underline {
public static String encase(String text) {
return "<u>" + text + "</u>";
}
}
public static class Strikethrough {
public static String encase(String text) {
return "<st>" + text + "</st>";
}
}
public static class Obfuscated {
public static String encase(String text) {
return "<obf>" + text + "</obf>";
}
}
}```
```java
public class ClickAction {
public static class ChangePage {
public static String encase(int page, String text) {
return "<click:change_page:" + page + ">" + text + "</click>";
}
}
public static class CopyToClipboard {
public static String encase(String value, String text) {
return "<click:copy_to_clipboard:" + value + ">" + text + "</click>";
}
}
public static class OpenFile {
public static String encase(String file, String text) {
return "<click:open_file:" + file + ">" + text + "</click>";
}
}
public static class OpenUrl {
public static String encase(String url, String text) {
return "<click:open_url:" + url + ">" + text + "</click>";
}
}
public static class RunCommand {
public static String encase(String command, String text) {
return "<click:run_command:" + command + ">" + text + "</click>";
}
}
public static class SuggestCommand {
public static String encase(String command, String text) {
return "<click:suggest_command:" + command + ">" + text + "</click>";
}
}
}```
Only to be used with something like:
player.sendMessage(MiniMessage.miniMessage().deserialize(NamedColor.RED.encase(Style.Bold.encase("Hello world!"))));
I wish I could have used Components directly, but there's still no way to have a <custom-tag> as a component π¦
and be serialisable at the same time
π€¨ what does this "fix" exactly? what kind of features does minimessage lack that this adds? all i can see is you're just building a minimessage string with methods instead
.
huh
just pass the resolved component..?
you only need to use minimessage if you are interfacing with user input via a config or something, in that case i don't see why you'd be using hardcoded strings (or why you'd be building them like that?), and yes you do need custom tags for custom tags; but if not, just pass the resolved component?
those hardcoded strings are default values for my config
if I pass directly a Component instead of a string, there is 1) no way to have dynamic placeholders.
- there is no Component, like
Component.tag("custom-tag")
unless, of course, you deserialise the string
uh, you can have dynamic placeholders by using a tag resolver
and also, Placeholder.component
i think you kinda have a fundemental misunderstanding of minimessage
You should be using MiniMessage everywhere - e.g. your MESSAGE_HEADER should be a MiniMessage string - then you can use MiniMessage placeholders in them
don't keep components lying around, they aren't useful
why? I want to have components, which should have been the core of the whole Adventure API
I can use Gson or anything else
I still can't use the components as I please.
i mean you can totally have components that when serializing with minimessage they serialize to your custom tag; that's kind of what virtual components are for
there's no documentation for it, sadly
(except the serialization api for custom tags isn't public yet)
internal package is a myth
those things I use, are hideous..
once this is out, I'm pretty sure everyone will finally choose to use adventure π
Your goal here is wrong - if you want to use MiniMessage and take advantage of tags, placeholders, dynamic tag resolvers, etc - you should be keeping stuff as MiniMessage strings where needed
coming to you in some number of years
"everyone" is certainly a statement
kezz is making a point, you want to make use of MiniMessage features outside of MiniMessage, your quest doesn't make any sense
then strip components
lmao
why needed?
What do you mean strip components?
why do you need components at this point in adventure if MiniMessage strings should be everywhere?
Because components are what Minecraft uses and unfortunately MiniMessage isn't in the vanilla client lol
basically all MiniMessages do is deserialisation
To give you an example, in our codebase we have around 100k lines of MiniMessage strings sitting in properties files, when we want to send one of these strings to a player we literally take that MiniMessage string and translate it right before sending it to the player - this lets us add dynamic or custom placeholders for the deserialization right when it's needed
not those one I am talking about.
if Minecraft has them, why does adventure needs new ones?
because adventure is a public open-source free api, not proprietary mojang code
use wrappers.
yeah
