#luckperms-api
1 messages ยท Page 42 of 1
because it might be better using PlayerAdapter for online players and modifyUser for offline players
I mean. I wouldn't mind if it was for online only
or getUser should work
one of the two, either from PlayerAdapter or UserManager
fun Player.setGroup(groupName: String) {
val group = BandiCore.luckPermsAPI.groupManager.getGroup(groupName) ?: throw GroupNotFoundException()
if (isOnline) {
BandiCore.luckPermsAPI.userManager.getUser(uniqueId).apply {
this?.data()?.clear()
val node = InheritanceNode.builder(group).build()
this?.data()?.add(node)
}
throw GroupChangedException()
}
BandiCore.luckPermsAPI.userManager.modifyUser(uniqueId) {
it.data().clear(NodeType.INHERITANCE::matches)
val node = InheritanceNode.builder(group).build()
it.data().add(node)
}
throw GroupChangedException()
}
```maybe?
don't quote me on that, but something like that might work
hmm but here you also used modifyUser
yeah but only if they're offline
just moved the exception throwing outside the lambda to avoid weird thingys with non-inlined lambdas throwing inside of the lambda and not terminating properly
btw, that ?: is called an elvis operator if you didn't know, it basically says "if the value to my left is null, do the action to my right"
yeah ik what it is
like it wants me to import it
I forgot how apply works somehow
but when I do, it does not want
replace it with this
(I forgot this lambda doesn't have parameters somehow lol)
it is the default name for a single argument in a lambda btw, if you didn't know that
also, looks like it returns a User? because lucko's a god and used @NotNull and @Nullable properly (these help the Kotlin compiler figure out if the type should be nullable or not)
right, updated my code with the new thingys btw @uncut panther
I saw the canges like floop
for some reason i like kotlin to be much more easy to type than Java
turns out @jaunty pecan is like mid-tier god, he forgot the @Nullable annotation on ? super User in modifyUser (unless Java doesn't let you have it there)
Hey BomBardyGamer! Please don't tag helpful/staff members directly.
it's entire purpose originally was to reduce Java boilerplate, so that makes sense
Should Player.setgroup not be OfflinePlayer.setGroup ?
because the player can be offline ๐คทโโ๏ธ
true
the way that works is really weird though
the documentation says that Player represents a player, online or not, but it only seems to be used in a context where the player is online
I still don't know how theBukkit.getOfflInePlayer works. Is it like it fetches an API?
depends I believe
Bukkit has some storage of all players that have joined before somewhere I believe
but some methods get from the API
Bukkit's just one big mess that's been built on and built on so many times now
like you have forks of forks of forks of forks of forks now
https://github.com/YatopiaMC/Yatopia this is a fork of Tuinity which is a fork of Paper which is a fork of Spigot which is a fork of Bukkit
btw update about the code:
I changed my group to crew but on /lp user Gezelligheid_ info my parent group is still owner and not crew
gotta be a reason for that
you're calling player.setGroup("crew") right?
just making sure you know how extension functions work
but it does changes my group
I am
so it changes your group but info doesn't reflect those changes huh?
also, please start using val where you don't need mutability ๐
you'll be surprised how many times that is
does it matter that much?
not really, but it's probably better to
okay
also, sure getOfflinePlayer actually returns anything btw?
I believe get by username was deprecated for a reason
myeah but then I'll better work with online players
it was deprecated because "persistent storage of users should be by UUID as names are no longer unique past a single session"
is OfflinePlayer#setGroup a bukkit thing?
ah ok
building now @craggy ember
right ho
still..
I wonder where info gets data from
like the command sets me to crew
but as soon as I run info it changes me back to owner
okay
seems to work rn
but
still the permission issue that I dont have perms for /op and such.
does this crew role have the perms for that?
well no. But I am an operator
even when i execute deop it gives me the contact admin
definitely not disabled?
definitelty
when I change my group manually with /lp user i can do stuff like /deop etc again
๐ค
its like my op gets 'removed' with the custom command
weird
yeah indeed
is there a way to reload the data of LP?
like after I have set the group of the player?
or wouldn't that change anything
Uuh not too familiar with Kotlin but wouldn't you need to return in the if block if the player is online?
would be handy yeah xD
Oh yeah I see, you're forgetting to save the user if they're online (something modifyUser does for you)
UserManager#saveUser(User)
hehe xD
I have no idea what apply does but I know you have to save the user :^)
that's basically just saying "right, all bets are off, if it's null, throw a NullPointerException, idgaf"
๐
apply basically allows you to apply certain things to an existing object
okay works. but yeah still the op issue
say in Java, you have something like this:java Person person = new Person(); person.setName("Hello"); person.setAge(12); in Kotlin, we can use apply there like this:```kotlin
val person = Person().apply {
setName("Hello")
setAge(12)
}
it basically takes an object, does some things to it, and returns the new modified object
Also, if the setgroup method is on the player object, they'll always be online lmao
And what op issue?
How come
the documentation says it represents a player, online or not
well If I change my group, I cant use /op or /deop or /reload anymore
You should never use reload anyway lol
i know
but it was testing purpose
Well I mean.. that sounds a whole lot like you don't have permission... what else can I say
Give the permission check command a try
(assuming you're on latest) lp user .. permission check <perm>
Will spit a bunch of very useful info
lol i just added them...
Yeah you're not on latest
/ver LuckPerms
The check command changed recently and it worked differently
!latest
5.2.94
lel
on the lastest version the op issue is fixed
i should consider updating more ๐ค
thankx for all the help doh

Do context calculators not work for regular perm checks? Was trying with the LP and Sponge classes, they show up just fine under user info, but when i add the context to a node it's not being satisfied by the context even though it's the same as displayed on the player info.
Yes they work
Have you checked how the resulting node looks in the editor (or any other other way to display the nodes)? @bold plover
yeah i figured it out, didn't break point it too many times turned out that subject was not always the player object if they were online, but lp uses the SubjectProxy wrapper for the subject, though luckily you can get the player by grabbing the command sender so i did just that.
cheers
yo
How do I access the api
i know, super noob question
I'm currently trying to make it where people can buy ranks via my Python Discord bot, wondering if there's a way to grab the users current rank + promote them
!cookbook
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
keep in mind LP only has a java api, so you'd need to make something or other to communicate between the 2
ah, alright
Isnโt it just minecraft.command.op? Lol
idk anymore..
Does LP load the data before or after PlayerChooseInitialServerEvent on velocity? Because I'm getting an error with Player#hasPermission (I'm not familiar with vc event order) https://bytebin.lucko.me/VyPTUU2sEK
Looks like the permission itself is null
Shouldnt be
wait im dumb sorry
nvm not related to api (or LP) but still confused I'm stupid lmfao I was using return instead of break in a for loop so it didnt get the perm from config
bet that's an output from less or something, since less hates colours
What?
nah went from my vps logs to my hastebin, renamed then to my website then send it to my local pc & uploaded it (was trying to use haste <file> but that didnt work
you didn't know less hates colours?
so does nano
nano ew
and vim
yeah that looks about right
I mean sure. But I'm missing context
the bytebin link he posted has fucked up colours in it
actually that's probably because it's just serving you plain text and doesn't recognise those
Not fucked up. Just how they are in raw text
yeah just me being dumb I guess
But the encoding is not right. There's some UTF-8 chars that aren't displayed correctly
Not even that as it seems. Or at least my terminal can properly interpret it. Just curling it restores it to how it's supposed to look
maybe just the browser
um, quick question
how do I obtain all the groups in the server?
without manually making a collection
GroupManager#getLoadedGroups?
cool, thanks
Any idea why this throws a nullpointer all the time
idk how it would be null but I made a check for it and it started working
Since we donโt know how you get the user object we canโt tell you what might cause it to be null
getting it from UUID
is the user offline
Iโm guessing those little squiggly lines are telling you it could be null ๐
is it possible to get offline player groups?
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
UserManager userManager = luckPerms.getUserManager();
CompletableFuture<User> userFuture = userManager.loadUser(uniqueId);
userFuture.thenAcceptAsync(user -> {
// Now we have a user which we can query.
// ...
});
this, right?
yes
It'll load the user from the database
get the nodes, filter for inheritancenode & get the group names
can you spoon feed me a little lol
that github links shows exactly how to get the groups
but will it work with offlineplayer thou
yes as long as you load the user
oh
UserManager userManager = this.plugin.getLpApi().getUserManager();
PlayerAdapter<Player> playerAdapter = this.plugin.getLpApi().getPlayerAdapter(Player.class);
CompletableFuture<User> userFuture = userManager.loadUser(p.getUniqueId());
userFuture.thenAcceptAsync(user -> {
Collection<Group> groups = user.getInheritedGroups(playerAdapter.getQueryOptions(user));
});
am I doing this right?
getQueryOptions needs Player object, not User
UserManager userManager = this.plugin.getLpApi().getUserManager();
CompletableFuture<User> userFuture = userManager.loadUser(p.getUniqueId());
userFuture.thenAcceptAsync(user -> {
Collection<Group> gr = user.getInheritedGroups(user.getQueryOptions());
});
this seems about right
Just donโt pass any parameters to that function. No need to worry about it @rocky aurora
How can I get a Players color?
(Also the Color of the Players role)
Or how can I get the Meta Keys of the Players group?
resolveInheritedNodes then filter for meta nodes?
you want to get a value for a meta key?
I want to get color meta data from the Players group.
i could send the code for it but... spoonfeeding bad
Uh
User#resoliveInheritedNodes(NodeType, QueryOptions)
Ok
uuh..
then filter for key, find first & get the value
i think
thats how I done it atleast
there's an easier way lol
How @nocturne elbow
Hey Basti ๐ฎ๐ก! Please don't tag helpful/staff members directly.
Uh ok sry bot
luckperms -> getgroupmanager -> getgroup -> getcacheddata -> getmetadata -> getmetavalue
ye
could've told me that a few weeks ago smh
Do you want to get the meta for the group or the one that the player ends up with?
so the meta the player ends up with
what are the default non contextual query options?
all global I think? 
is Flag.RESOLVE_INHERITANCE set?
uh
I mean, I guess I could just use EnumSet.noneOf(Flag.class) to make sure no flags are set
Set.of() 
EnumSet.noneOf superior xD
actually I really shouldn't be using noneOf here
you know Set.of isn't even a thing btw right?

it's the JDK I have set as default lol
lemme set AdoptOpenJDK 11 as default
OpenJDK best JDK
anyone who thinks otherwise is dum dum
change my mind
*performs a lobotomy*
what is the API to show someone's group?
!cookbook has example for that
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
it says it moved to another link
How to check if a player is in a group and add him to the group?
!api
Learn how to use the LuckPerms API in your project.
!cookbook
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
d;luckperms Node
public interface Node```
Node has 15 methods, and 10 sub interfaces.
Represents a LuckPerms "node".
The Node class encapsulates more than just permission assignments. Nodes are used to store data about inherited groups, as well as assigned prefixes, suffixes and meta values.
Combining these various states into one object (a "node") means that a holder only has to have one type of data set (a set of nodes) in order to take on various properties.
It is recommended that users of the API make use of Streams to manipulate data and obtain the required information.
This interface provides a number of methods to read the attributes of the node, as well as methods to query and extract additional state and properties from these settings.
Nodes have the following 4 key attributes:
<br />
*...
This description has been shortened as it was too long.
\o/
d;luckperms User
public interface User
extends PermissionHolder```
User has 1 super interfaces, 4 methods, and 1 extensions.
A player which holds permission data.
d;luckperms User#getInheritedNodes
@NonNull Collection<Group> getInheritedGroups(@NonNull QueryOptionsย queryOptions)```
Gets a collection of the Groups this holder inherits nodes from.
If Flag.RESOLVE_INHERITANCE is set, this will include holders inherited from both directly and indirectly (through directly inherited groups). It will effectively resolve the whole "inheritance tree".
If Flag.RESOLVE_INHERITANCE is not set, then the traversal will only go one level up the inheritance tree, and return only directly inherited groups.
The collection will be ordered according to the platforms inheritance rules. The groups which are inherited from first will appear earlier in the list.
The list will not contain the holder.
a collection of the groups the holder inherits from
queryOptions - the query options
wait... it doesn't just perform an exact search, it performs a LIKE search as well?
this bot's awesome!
thanks @versed flint!
great bot!
thanks
I might PR over some gateway intent changes if you'd be alright with that
pls do
me likes to contribute to others' projects ๐
a star would be awesome too
your wish is my command
btw there's loads of docs, type d;docs
d;docs
โข plotsquared-bukkit โข fawe
โข commons-compress โข sponge
โข commons-crypto โข waterfall-chat
โข commons-configuration2
โข commons-collections4
โข commons-codec
โข plotsquared
โข velocity
โข jda
โข waterfall
(telling you to run it because only the command runner can interact with the pagination)
nah
probably 50% of them automatically update
well, update daily
the other 50% is things like old spigot versions which obviously don't need to be updated
nice reference to the host container from Docker there
guessing this has a published Docker image?
I can make that as well whilst I'm at it if you like
I'd prefer to do it myself so I can actually learnt how to
I really need to learn docker properly
lemme link you to my Dockerfile as an example
basically, you create one of those, then run docker build -t image-name:version directory
or in your case, docker build -t docdex:1.0.0-beta .
I think
yeah you build the image and then push it
currently just using ptero
if you also look in bardybot, I have docker-push.sh, which used to be used by Travis to automatically push builds to Docker
it just logs into Docker Hub with docker login and then pushes with docker push
also, #piggypigletformod
I'm kidding lol
you should get something though, to recognise that thee is the creator of DocDex
d;info
one of the most useful bots I've ever seen
my name is there
true
oh also, Gradle thing here, but you know I managed to use dependencies in allprojects the other day
I think you can do it now
maybe was just me being dum dum in the past lol
where's the class that starts JDA btw?
JDARegisterable under the discord subproject
also, my guy be using ORM
my own orm
what's it like?
too verbose
not Kotlin friendly then
if I got it working the way I wanted to this would be unnecessary https://github.com/PiggyPiglet/DocDex/tree/master/discord/src/main/java/me/piggypiglet/docdex/db/tables
right, what are all the things the bot does btw?
or all the things the bot listens to
need to know this for gateway intents
erm
well it needs a member count for the info command
and server count
it deletes and adds emojis to messages (not always its own)
it makes messages
reads message history
deletes other peoples messages sometimes
edits messages
we should probably be in #general
yeah let's move there
Hello
hi
How do i get the Api? is it possible to:
private Plugin LuckPerms = Bukkit.getPluginManager().getPlugin("???");
or what do i have to type in the " "
!api
Learn how to use the LuckPerms API in your project.
Quick question
When I'm calling Permission#getPrimaryGroup in Vault
Does that return all of the player's parent groups
Gets the name of their primary group
group = 1, groups > 1
who ghost pinged me
@tired loom :p
mistake

How can I remove a specific amount of items from an inventory? With /rankup
!api
Learn how to use the LuckPerms API in your project.
This is less an API question and more a general development question. Luck may be the only one who has the proper answer to this but speculation is welcome.
What was the reasoning behind going with weights over a different system, such as explicit deny wins like what you find in Active Directory?
No particular reason
Iโm not familiar with active directory so canโt really compare
Understandable.
Essentially the difference there is in LP if you have multiple roles and you have a mix of allow and deny, the winner is determined by the weight. In AD, if you have multiple roles, it's calculated like this:
- If there are any denies, the result is deny.
- If there are no denies but there are allows, the result is allow.
- If there are neither, the result is no permission (behaves like a deny in that they don't have permission, but can be overridden by an allow).
That seems to be how WorldGuard does it if all applicable regions have the same priority
But you can still prioritize ALLOW over DENY if one of the applicable regions has a higher priority
For the StateFlags that is, kinda exclusive
I am writing the grief protection plugin for my server. I need to get data from luckperm to find out which group a player is in I guess how can I do that
i need this
how can i use this
Well that would include inherited groups as well
I do not fully understand
I just need to understand if a player is in the group I chose.
Do you know what inheritance is?
i guess no
!inheritance
Learn about inheritance.
I may not understand because my English is not good
okey i understand this
but i will use only group.owner
okay
You write that method somewhere and then you call it...? isPlayerInGroup(player, "owner")?
the font 
if(player.isOp() || isPlayerInGroup(player, "owner")) does this work
I don't see why it wouldn't
I'm a little inexperienced, sometimes I make small mistakes ๐
should i use player or player.getName()
anybody able to help
with the api?
- #support-1 or #support-2 for general LP help
-
If you are a server admin, please check the console for any errors.
it was a question for ShanePike
but my code is not working
i write this but not working
sorry my mistake i find my problem
how do I get the instance of luckperms on bungee
LuckPermsProvider.get()?
d;methods lp luckpermsprovider
net.luckperms.api.LuckPermsProvider#get```
ooh luckperms got docdex
That's new btw
I should asking in #support-1 ? Sorry for my eng.)
yes
is it possible to get a prefix of an offline player?
!cookbook
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
thank you ๐
How can I get an ordered list of my groups?
I've set the weights of each group
like is there an util or should I just implement it myself
.stream.sort?
I mean it's a set you're looking at right there, there is no guarantees it will be sorted (unless it's a SortedSet but there are no guarantees it's one either
)
That's an ad and ads are bad @severe zenith - not here thanks
k
Is there a way/is it safe to use LuckPerm's Redis library (Jedis) instead of shading Jedis myself?
How can I get when a players rank expires?
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
And for that you'll want to listen to NodeRemoveEvent, check that the target is a User and that the node is of NodeType.INHERITANCE and that it had an expiry
Not directly, there isn't a User#getParentGroupsExpiryTime method
You can use PermissionHolder#getNodes(NodeType) for NodeType.INHERITANCE and filter by those that have an expiry date and have not expired
Then get the expiry for each. Keep in mind that you can have multiple parent groups and multiple temporary parent groups so you may end up with 0, 1 or many resulting nodes 
okay thanks
anyone able to help me in with luckperms?
with the API...?
user.data().clear(user.getQueryOptions().context(), NodeMatcher.key(InheritanceNode.builder().group(group).build()));
api.getUserManager().saveUser(user);
}```
That should remove a user from ``group`` correct?
for some reason.. it is refusing to remove me from the group
but i can add a group with public void addGroup(String group) { user.data().add(InheritanceNode.builder().group(group).build()); api.getUserManager().saveUser(user); }
just fine..
Yeah that should work I think?
What happens if you don't pass the context to the clear method, only the NodeMatcher?
The thing is that that's what I used for a 1.15 plugin..
And it worked flawlessly
And add still works but that one doesnt
And I don't think I can't not pass the query context to the clear method
Since it requires it and won't compile if I dont
void clear(@NonNull Predicateย test)```
Clears any nodes which pass the predicate.
test - the predicate to test for nodes which should be removed
yeah you absolutely can lmao
unless you're compiling against an old af version
Which LP version are you using and which one are you compiling against?

I'm not currently at my computer nor really allowed on it as of now
Should be a 1.15 build of the lp api and the latest version of lp (or 4 days old)
Okay, whenever you can check and send those 2 infos over cuz they do be important tbh
I'mma test that now but afaik it should work fine
cool cool
Can confirm that clearing with clear(Predicate) works as you are actually expecting
clear(ContextSet, Predicate) will clear those that satisfy both the predicate and the context set
so the permission for that key (if you're doing NodeMatcher.key(...) that is) would need to satisfy all contexts passed in the set
So either will work?
I'll update the api and luckperms to make sure they are both latest stable and see what happens
Oh
when passing the contextset you are basically filtering all nodes that satisfy the contextset
so if you pass a contextset only for server=survival, you would get all nodes for server=survival, and if the node you're trying to clear does not exist there it won't clear them
'twas an example
That's the greatest usage of 'twas I've ever seen other than 'twas the night before Christmas
lmao
So I'm trying to look for an object in which it does not exist in the context specified?
I'm 100% sure that method has always existed (always = since v5.0)
So if I remove the context it should work as that method used to?
Otherwise it would specify since: X
yea
Make sure you're using an update api version lol v5.2 preferable (latest as of today)
I'm using a 5 month old version
But latest luckperms
So yeah I'll update and remove that context
Thank you for your help :)
For example, in here (in UserManager) savePlayerData has always existed (since v5.0, unspecified but it's the "new" api) existed, but modifyUser was introduced in v5.1 as it says there, and deletePlayerData since v5.2
There's a usermanager?
I made my own class to interact with players...
For nothing??
And my own group management class
net.luckperms.api.LuckPerms#getPlatform
net.luckperms.api.LuckPerms#getEventBus
net.luckperms.api.LuckPerms#getPlayerAdapter
net.luckperms.api.LuckPerms#getPluginMetadata
net.luckperms.api.LuckPerms#getTrackManager
net.luckperms.api.LuckPerms#getNodeBuilderRegistry
net.luckperms.api.LuckPerms#getMessagingService
net.luckperms.api.LuckPerms#getGroupManager
net.luckperms.api.LuckPerms#runUpdateTask
net.luckperms.api.LuckPerms#getUserManager
net.luckperms.api.LuckPerms#getNodeMatcherFactory
net.luckperms.api.LuckPerms#getServerName
net.luckperms.api.LuckPerms#getQueryOptionsRegistry
net.luckperms.api.LuckPerms#getActionLogger
net.luckperms.api.LuckPerms#registerMessengerProvider```
juicy stuff
I am using a user
But I think I'm getting that from something along the lines of getUser
Well yeah you eventually work with a User instance
but you get users with either the UserManager or the PlatformAdapter
And for groups I am using the group manager
UserManager lets you load/modify data from offline players (and many, many more things)
But the group manager was so long that I created my own class
For getting prefixes and weight
Then I am definitely using the userManaher already
I mean you can get those things pretty easily actually
Yeah but I made it easier lol
weight there's no mystery, you can just get the group and get the weight
prefix/suffix needs an extra step but still
new LuckPermsGroup("owner").getPrefix();
I wonder what that does BTS
Bts?
behind the scenes
Ah
There's alittle more than just getting the prefix for getPrefix.. it will return the group name of the group if it doesn't have the prefix and if the group is null it returns the "name + (null)"
Does it respect the prefix stacking settings though? ;p
Ah what now?
It gets players prefix, if that's null it gets group prefix..
The primary groups prefix
It shows the prefix just like essentials does
imagine I have a prison track, a staff track and a donors track, you can make it so it shows the final prefix as (for instance)
[Mod] โญ [Donor] โญ [G] -
Display multiple prefixes/suffixes alongside a player's name.
I spent Like 8 hours making my own chat thing aswell
Just so I could do that
And your telling me
That this plugin does it for me??
And you can get the final prefix with a single line lol
and it can get pretty wild.
lol
My brain is fried
:p
Of course if there's no evaluated prefix it will return null but that's something you can easily solve lol
Anyway, gnight :ablobwave:
Gn
hi i need help:
i'm using tebex "buycraft"
and i want to create packages like: vip, mvp
but i dont know how to give someone an luckperms rank??
what is the command
isnt it:
/lp user @p ?
Also please next time use #support-1 or #support-2 if it isn't related to the dev api
should i do this?
{name}
because it 100% isn't specific to luckperms
Hi everyone!
@jaunty pecan , I want to create a website where players can enter their names to see how much time they have until a secondary degree expires (for example VIP).
My time database doesn't look like chat (i mean i can't understand this: 1613695413) and I don't know how to calculate, can you tell me please?
Hey Brosky (Vlad)! Please don't tag helpful/staff members directly.
Epoch and unix timestamp converter for developers. Date and time function syntax reference for various programming languages.
Thanks!
And you can find soms api or do it yourself probably
I was using LP Api version 5.1 fefo..
Yeah well the method was doing what you were telling it to tbh lmao
You should be able to not pass any ContextSet at all in that case
yeah it works now, without the context
is there any way to re-arange the roles in the lp editor?
they're ordered by weight
Hi Guys, Is it possible To Make a Nick System Where It Nicks And Changes to a Prefix, Then when you unick it comes back the the orginal prefix, I am Using Luckperms for the prefixes
prefix:
format:
- "highest_not_on_track_levels"
- "highest_on_track_levels"
duplicates: first-only
start-spacer: ""
middle-spacer: " &8| "
end-spacer: " &8| "
suffix:
format:
- "highest"
duplicates: first-only
start-spacer: ""
middle-spacer: " "
end-spacer: ""```
So i currently have that but is there a way to say for example: if the owner doesn't want to show highest_on_track_levels is it possible to not show it for only the group owner?
No, those settings apply globally on the server
so i would have to make my own custom chat handler wouldn't i (which i conveniently already have)
if you can give some specific use cases i can make it so you can order by other methods, but i need to know what you'd like :P
heres an example of what i was trying to do:
Owner: it would only display owner, not the level
Manager: it would only display manager, not the level
...
Moderator: it would display moderator and the level
...
Member: it would only display the level
And for the re-arranging i just had to reload the page (it was sorting by creation not weight)
hey I have a little problem maybe its because of my ignorance of not knowing how lp works internally and probably there are easier ways to do this but
I have created a webapp that asks for nickname and password for a server and I have 2 groups on my minecraft server 1 that cannot do antything and second that allows for normal play eg interacting with other blocks and basic commands
app assumes that player has already been on server so the uuid is in the database. When webserver authenticates player it sets group to that player directly in the database
I mean it sets primary_group of that player in the luckperms_players table to that group.
I think it should work, entry in the database changes and stuff but in the game player still cannot do anything.
Or should I just update player directly in the user_permissions table
also there's code if it helps https://github.com/Fensi3321/mcauth
I know it's bad but it's my first webapp I have ever written and never used go xD
The primary group is not quite what it seems; the primary group isn't grabbed from storage, but by default the primary group is calculated at runtime and it's the direct parent group that weights the most (and tbh that is the behavior people expect so it shouldn't really be changed), so changing the db entry will most likely have no effect (just like the parent switchprimarygroup command, it even tells you it won't change based on the config setting)
A common misconception is that the primary group is the parent group, and that's not necessarily true, you can have many parent groups (but one primary group only);
IMO you shouldn't modify storage directly :p as it isn't reflected in real time on the loaded on-memory data (although that's nothing an /lp sync cannot fix), you should make some sort of bridge plugin that interfaced with the LP API that changes their parent groups as you need
oh okay
I've never wrote a plugin before so I assume it would be overkill for that
are there any other ways to automate that? I got really desperate and wrote that app today because few times my server got destroyed by some dudes that somehow got ip and destroyed my and my friend's works and stuff
(is it an offline mode server)
Well, there's nothing stopping you from changing what's in the db, but you would need to run /lp sync//lp networksync after modifying it, and yes you would need to add an entry in the user_permissions table for the node group.<group>
okay got it
thanks a lot
Hey can someone help me? This is my first time working with the luckperms API. Why doesn't it work with the maven?
and maven too?
yes
All your <dependency>...</dependency> tags go inside one single <dependencies>...</dependencies>
okay thx
how can i get the groups of the players that i can let it show in the tab and in the chat?
hi, so i got a problem, im doing a loop of group names and i created them using
if(getLuckPerms().getGroupManager().getGroup(groups) == null) getLuckPerms().getGroupManager().createAndLoadGroup(groups);
but if i want to get the group right after that with
getLuckPerms().getGroupManager().getGroup(groups)
its null
createAndLoadGroup takes some time to create (and.. load) the group
it returns a CompletableFuture so getGroup will return null until the future is done
You can run a method when the future is done as explained here: https://luckperms.net/wiki/Developer-API#using-completablefutures
!cookbook has an example command for that :)
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
I can't see anything about this in the wiki or cookbook - what would be the best way to get the users' next rank in a track?
If I load a user then later call getUser(UUID) would that work or would I need to call loadUser(UUID) again?
I think it's loaded for a minute but you should load it if the user is offline
if it's an online player you can just LuckPerms#getPlayerAdapter(Class) -> getUser(Player)
First you would get the desired track with the TrackManager, get all the groups the player is in (ideally it would be one), get its position and then get the one after
As this will never be true, and the user will always have atleast one, usually two (default and a rank on the track, as this is part of a network where default is global and the other is on a server which is unknown) - How would I find the "top" rank in the track which the user has?
anyone know why on my server everyone has the same ip?
Wdym "top rank"? Like, the last one on the track?
Hello! I have a question. I have the problem that whenever i give 1 person a role everybody else gets that role assigned too. How do I fix that problem?
with the API?
probably whenever i promote someone everyone else gets promoted with it and idk where my mistake is
uuh... what is this to do with the LP API exactly?
i followed a tutorial i created 5 roles and set prefix and also i did the track it works anc i can promote people but the prefix doesnt really work if i promote someone to mod it sometimes looks like [Member]mod and when i once get the prefix to be mod everyone becomes mod
Do you know what an API is?
im sorry i looked it up and ig its not what i thought it was
#support-1 or #support-2 for general LP support
precisely
oh btw for your previous question
you can get the next group on a track with this method
d;lp Track#getNext(Group)
@Nullable String getNext(@NonNull Groupย current)
throws NullPointerException, IllegalStateException```
Gets the next group on the track, after the one provided
null is returned if the group is not on the track.
current - the group before the group being requested
NullPointerException - if the group is null
IllegalStateException - if the group instance was not obtained from LuckPerms.
the group name, or null if the end of the track has been reached
yeah that doesn't help really
because for example, if I pull the users groups and filter to the two in the track, I will end up with default at a minimum and also another, example rank1
I don't want it to select default to then get the next group as rank1 if rank1 is the highest in the track
I asked How would I find the "top" rank in the track which the user has?, or the lastmost which they have
that was aimed at your first question
so the player will have default and another group, and both of them are on the same track?
I'm not getting the situation
let me send an example
pretend Basilisk is default, this is part of a larger network so the user will always have default rank, but then they may also have phoenix rank
oh I see what you're trying to do
I don't want to fetch their ranks and filter by the track to be left with default, and then selecting basilisk and it saying the next rank is centaur
you're trying to manually promote them yourself because they are on two groups on the same track and you can't simply /lp user .. promote them, right?
I need to know which rank they're currently on so that I can perform operations before they are promoted based on some config sided stuff
I hate spoon-feeding
but
I had to figure it out myself xD
This is what I would do (in theory this works, keep in mind I haven't tested any of this lol)
final Track track = this.luckPerms.getTrackManager().getTrack("track");
Validate.notNull(track, "yeet");
final User user = this.luckPerms.getPlayerAdapter(Player.class).getUser(player);
final QueryOptions queryOptions = user.getQueryOptions();
final List<String> playerGroups =
user.getInheritedGroups(queryOptions.toBuilder().flag(Flag.RESOLVE_INHERITANCE, false).build())
.stream()
.map(Group::getName)
.collect(Collectors.toList());
final String highestGroupOnTrack = track.getGroups()
.stream()
.sorted(Collections.reverseOrder())
.filter(playerGroups::contains)
.findFirst().orElse("default");
Can i get the group of a player with the API? but I need to get the group of the player for a spigot plugin and the Luckperms is only on the Bungee server.
That's stupid, LuckPerms needs to be installed on every server to work on them
It doesn't check permissions across the network
But anyway, if you really want to do that you will need a plugin on both spigot and bungee and mess with plugin messaging (https://www.spigotmc.org/wiki/bukkit-bungee-plugin-messaging-channel/ https://www.spigotmc.org/wiki/sending-a-custom-plugin-message-from-bungeecord/)
Hi. How can I get an users secondary group?
Add another inheritance node
Depend on LuckPerms and make sure tou load the api after luckperms
Is LP on the server? And make sure you're not shading the api in
might be depends
idk
maven
!paste your pom
Seeing a paste of the problem makes everything so much easier! Use https://bytebin.lucko.me/ for easy pasting!
Pastebin any relevant segments of the console log. If it's a startup error, this includes the entire startup log!
Pastebin the entire LuckPerms config file (passwords removed) as well as any other relevant files!
Learn how to use the LuckPerms API in your project.
yea shouldnt use systemPath, luckperms as a proper maven repo
probably the same case for bungeecord-lib you are using
i change systempPath and the same error xd
Did you try making it depends instead of depend?
in plugin.yml?
k
Lombok ๐ฅฒ
same error
tried depend, softdepend and depends
On bungee it's depends and share your new pom please
That looks good, you sure it's in depends?
Hum 
Does it still try to load before LP?
Because that sounds like a fucked up proxy plugin manager lmao
which method do I have to use if I want to check the group of a offline player?
!cookbook
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
Yo! Is there an easy way to get expiration time of the group/permission? I know how to check if someone is in specific group with player.haspermission("group.name"), but how to get expiration time?
!api basically you just need to use the LPAPI instead of Bukkit
Learn how to use the LuckPerms API in your project.
Okay! Thanks I'll look into this
It may be an easy question, but how to access expireAt from this structure? xD
d;lp node#getexpiry()
@Nullable Instant getExpiry()```
Gets the time when this node will expire.
the Instant when this node will expire, or null if it doesn't have an expiry time
The mere fact you asked "how to access expireAt from this structure" scares me just thinking how you are doing things 
I've converted it to string and wanted to access it that way xD It is my first time ever writing something in Java (I have some experience in C++)
Yeah, thanks a lot!
lol sounds hacky; the LP API is made so you don't have to write some hacky janky workarounds to make things work :d usually there are proper methods to achieve your goal
That's cool! I have to spend more time learning mincraft plugin coding and everything will be easier
Thank you one more time
nvm i found it
Hello! I'm working with the LuckPerms API for the first time, and I'm a bit lost on the topic of managing a user's groups. The docs on the website seem to skim over this.
My goal is simple: I want to add a user to a group using the group name. I was able to get the group object using getGroupManager().getGroup(<name>). However, it appears that to assign the user to it, I need it in the form of a Node... but there is no GroupNode or something like that. What should I use, then?
Can anybody please point me in the right direction? Many thanks ๐
!cookbook
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
Ah, useful. Thank you!
Hello!
What does it mean? I can't use api inside of the asynchronous task? In my Main class I have "public static LuckPerms api;" and when plugin enables "api = LuckPermsProvider.get();". So Can I use "Main.api.getPlayerAdapter(Player.class).getUser(player)" in async task?
What?
I'm trying to make code below execute async way and in method Time.getTimeReminder I use LP api and I don't know if it is correct as on previous screenshot it states that "Asynchronous task should never access any API in Bukkit"
You can use that in an async task, it's not really Bukkit API, but LP API
And you can use PlayerAdapter methods both synchronously and asynchronously
By "don't use bukkit api async" they mean more like world and entities modification, spawning, etc
yeah, just to add on to this, it means dont do anything with bukkit stuff. like dont do Bukkit.getPlayer() async, or Bukkit.getWorld("luckPermsLand") async
eeh there are a lot of things that are just okay but there is no "standard" on what should and shouldn't be done async
So I can't do Bukkit stuff, but player.sendMessage is okay, yes?
Yeah that's fine
Nice! Thank you a lot guys
I mean that is part of the Bukkit API, "Bukkit API" doesn't refer to things that are strictly under the Bukkit class, but the server API as a whole
But again
eeh there are a lot of things that are just okay but there is no "standard" on what should and shouldn't be done async
and things like sending messages is fine lol
One last question xD If I run part of my code asynchronously and in that part I call a method from another class (in that class I don't use async) will this method run asynchronously?
Or I have to do it in all my classes?
It'll run async
Basically, it runs on the same thread the caller is running on, if that makes any sense
Yeah it makes sense to me ๐
Thank you very very much โค๏ธ
Hello, in https://github.com/lucko/fabric-permissions-api/blob/master/USAGE.md I do not see how can I get a number from permission.
Example: I want to do permission check like
home.maxcount.5,
how can I check this number?
?
Fabric equivalent of Vault? :o
Till fabric gets a perm api i think?
Ok, thank)
That looks very lacking though..
For what you just asked it sounds a whole lot like you might want to use meta nodes instead of custom perms & parsing (you would need to depend directly on LP and use the actual LPAPI to get the value for the meta key), but if you really want to do it like that you would need to iterate through all inherited permissions, in Bukkit that's easy with the bukkit api itself, just a few method calls and some looping; I wouldn't know if you can get all perms a player has in fabric
Hopefully something like this will appear in the official fabric permissions api
For now I would suggest you depend directly upon LP ;););)
And tbh meta nodes (basically a key/value pair) and meta lookups are optimized for performance and fast querying, so you don't have to slowly iterate through all the nodes n stuff
But if you want to be more open to other perms platforms without depending directly on them (like the WIP pex2) you wouldn't depend on the LP API and wait until fabric implements their own api
it was written by luck to be minimal and allow permission plugins to extend and expand it, so until something overengineered and massive is added, which likely won't happen too soon, you're best off using LPAPI as it's made to do what you need
Thanks for answers, I'll try it.
Hello
So how can I set the prefix with luckperms in programming
My english not so good
!cookbook
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
Hey, I apply negated permissions to a player for cooldown purposes. Is it possible to, through the API, check for the following scenario:
- Check if the player has a negated timed permission node
- If the player has a negated node, if the player would have access to the permission without this node
- If so, the cooldown of the node
I thought using something like:
user.resolveInheritedNodes(NodeType.PERMISSION, QueryOptions.nonContextual())
.stream()
.filter(p -> p.getKey().equalsIgnoreCase(node))
.forEach(p -> System.out.println(" - " + p.getKey() + ": " + p.getValue() + ", " + p.getExpiry()));
However, this doesn't work for certain scenarios (eg when checking for: node.with.subnodes, node.with would be filtered out even though it changes the value of node.with.subnodes)
I feel like what you actually need is something strangely similar to the new permission check command
Beware though ๐ it's a bit of a convoluted logic https://github.com/lucko/LuckPerms/blob/master/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionCheck.java
The link? No
how can i use the player prefix in my plugin?
i need some help
i've added this to my server to use it with essentials x and i have no idea how to use it
@urban bane please don't post in multiple channels and adhere to the correct ones
Wew that looks quite complicated indeed. I'm going to solve it by just checking if the groups the player is in have the permission, then checking if the user has the node negated. It seems to work fine.
no, for example, i have a team list command, and i want the luckperms prefix to appear in the nick of the online player.
and that's how you get the prefix
then you need to create a separate file and put this code?
That repository is an example plugin with example commands
That code is sample code, you are supposed to read it, analyze it and see "oh okay, I see how this is done, I will adapt this to my needs"
is there a way to remove a certain group from a player via the api
Absolutely, you can check the SetGroupCommand example on the cookbook repo (more specifically this bit https://github.com/LuckPerms/api-cookbook/blob/master/src/main/java/me/lucko/lpcookbook/commands/SetGroupCommand.java#L55-L69)
But instead of clearing and adding an inheritance node, you would .clear(NodeMatcher.key(inheritanceNode))
And is there also a way to add and not set a group?
what?
You mean, if a player doesn't have a group, add one?
Well yeah you could do that check, but I mean you can just add it anyway, if they already have that Node nothing will change
nope add a group ontop of his exiting ones
I have a subserver where you will get a rank if you are the owner of it (private server system) and i want to add a group with perms to him and not to remove his original one
HanniSagt.getLuckPerms().getUserManager().modifyUser(uuid, (User user) -> {
user.data().clear(NodeType.INHERITANCE::matches);
Node node = null;
node = InheritanceNode.builder(group).build();
DataMutateResult result = user.data().add(node);
// Check to see the result of adding the node.
if (result.wasSuccessful()) {
System.out.println("Success -> Added permission group");
} else {
System.out.println("Failed -> Failed to add permission group");
}
});
this is my current code
Just don't call clear?
lol
thank you anyway 
with the api.?
?
they deleted their message smh
You sure you're not imagening things?

?

how can I get the rank of a player in luckperms?
!cookbook
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
thx
hi i search to change a specific prefix for a user (priority 60)
`// Find the highest priority of their other prefixes
// We need to do this because they might inherit a prefix from a parent group,
// and we want the prefix we set to override that!
Map<Integer, String> inheritedPrefixes = user.getCachedData().getMetaData(QueryOptions.nonContextual()).getPrefixes();
int priority = inheritedPrefixes.keySet().stream().mapToInt(i -> i + 10).max().orElse(10);
// Create a node to add to the player.
Node node = PrefixNode.builder("K", priority).build();`
In this exemple found here : https://github.com/LuckPerms/api-cookbook/blob/master/src/main/java/me/lucko/lpcookbook/commands/SetPrefixCommand.java
It show how to add a prefix for the highest priority
So if i want to change a prefix should i do like that with priority to 60 ?
Is there any way to modify instead or create ?
What class do i use for the playeradapter to get the prefix of a player through bungee?
rn i have this: CachedMetaData user = api.getPlayerAdapter(ProxiedPlayer.class).getMetaData(sender);
Means you havent set a prefix then
._. i whiffed, wasnt in the group
Player adapter classes per platform are specified in the javadocs https://javadoc.io/static/net.luckperms/api/5.2/net/luckperms/api/LuckPerms.html#getPlayerAdapter-java.lang.Class-
Fabric is missing 
It's in the sources though (https://github.com/lucko/LuckPerms/blob/master/api/src/main/java/net/luckperms/api/LuckPerms.java#L121-L146), the javadoc haven't been updated on that page cuz Luck 
Guys user.getPrefix doesnt exist, how u get it ? 0_o
Nodes (and by extension, PrefixNodes) are immutable/unmodifiable, what you would do is remove the prefix node you found on the user (you would get the user's PrefixNodes and filter by weight 60) and then you would add the prefix node you just built. If you
!api @final adder
Learn how to use the LuckPerms API in your project.
User#getPrefix doesn't, but Merijn named their CachedMetaData "user" so yeah :p
Oh mybad sorry
Hello, I'm trying to get which track, selected player on. Simply I got group of player and search in all tracks. But its bit complicated. Is there any simple way to get players tracks? I can post my code if need
Paste it on https://paste.helpch.at/ see what you've got
So you want to get the tracks the player is on?
Yes in this way I can get value of required blocks by config
Yeah, that is going to require a number of loops. There isn't really a "simple" way, the simplest it can get is the way you would think of anyway:
- Get the player parent groups
- Get the loaded tracks
- Check for each track if their groups contains at least one of the player parent groups (there's your for loops right here, for each track for each group)
You could simplify that by a factor of a lot by using the Java Stream API (see https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/package-summary.html and the examples using streams on this page too (you can just Ctrl F "stream" lol) https://luckperms.net/wiki/Developer-API-Usage) but if you're not too knowledgeable, it's not the easiest of topics to get into lol
I also type with stream lib actually but thx for informations
Stream works as like for loops this is why I didn't want use it
But thx so much ^^
They kinda do from an outer perspective, yeah, but you can do things like #map, #filter, #peek, and many, many more things!
Streams are amazing but you pay for performance though
although it isn't really an issue unless it's something super heavy you call every tick lmao
Aight tysm bud ^^
Hi, i'm new in this API and i don't know how can i get the player prefix. I tried java api.getUserManager().getUser(e.getPlayer().getUniqueId()).getCachedData().getMetaData().getPrefix(); but i don't know what does ,,contexts'' in getMetaData() mean. Can somebody help me?
Don't /reload
even when I donโt give / reload, it gives this same error
Is this your own plugin you're making?
yes
You can not-provide contexts, but when passing them they act as a filter of what you're looking for
!contexts fyi
You can set a permission or group on a per-world/per-server basis, through what we call "contexts".
!paste your server logs then
Seeing a paste of the problem makes everything so much easier! Use https://bytebin.lucko.me/ for easy pasting!
Pastebin any relevant segments of the console log. If it's a startup error, this includes the entire startup log!
Pastebin the entire LuckPerms config file (passwords removed) as well as any other relevant files!
I asked for the log so that's actually perfect
Did you add LP to your plugin's depend list?
Also, get the LuckPerms instance inside your onEnable, that's when it becomes available
continues the same error
!paste your plugin.yml please
Seeing a paste of the problem makes everything so much easier! Use https://bytebin.lucko.me/ for easy pasting!
Pastebin any relevant segments of the console log. If it's a startup error, this includes the entire startup log!
Pastebin the entire LuckPerms config file (passwords removed) as well as any other relevant files!
is it the exact same error?
also I'm assuming you didn't /reload and you fully restarted instead ๐
add a space between the - and LuckPerms
Learn how to use the LuckPerms API in your project.
!api downlaod
Learn how to use the LuckPerms API in your project.
!getPrefix()
Sorry! I do not understand the command !getprefix
Type !help for a list of commands.
How about getting the player prefix?
Because in the api usage appear CachedMetaData metaData = user.getCachedData().getMetaData(); and it said that that "user" was not found so its confuse
So its only confuse the webpage about api
Please i cant found any page that talk about how getting luckperms prefix rank
!cookbook
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
!api
Learn how to use the LuckPerms API in your project.
How can I set the prefixes with luckpermsapi? I can't find anything on the wiki page
!cookbook
The cookbook is a working example plugin which shows how to get/change data for users and groups, listen to LuckPerms events, and more.
I don't mean the group directly via command
Thered code examples there
I just want to do the group with group group ... and put the prefixes there
What
You can download LuckPerms for Bukkit/Spigot/Paper, BungeeCord, Sponge, Fabric, Nukkit and Velocity.
!api
Learn how to use the LuckPerms API in your project.
!api download
Learn how to use the LuckPerms API in your project.
First link
!api
Learn how to use the LuckPerms API in your project.
!translte
Sorry! I do not understand the command !translte
Type !help for a list of commands.
!help
!advanced
!api
!argumentbased
!ask
!bulkupdate
!bungee
!bungeecheck
!cauldron
!colours
!commandequivalents
!commands
!config
!context
!cookbook
!default
!downloads
!editor
!editorsafety
!errors
!essentials
!extensions
!extracontexts
!faq
!formatting
!helpchat
!inheritance
!install
!libsdir
!locale
!meta
!migration
!notworking
!nowildcard
!pasteit
!permissions
!placeholders
!selfhosting
!stacking
!storage
!suggestions
!switchstorage
!sync
!testingperms
!tracks
!translations
!upgrade
!usage
!userinfo
!verbose
!weight
!whyluckperms
!wiki
!translations
Translations for LuckPerms are managed on Crowdin. Any contributions are very welcome!
!api @odd jackal
Learn how to use the LuckPerms API in your project.
Hey there,
For a proxy plugin, we're relying on the LuckPerms API to retrieve usernames from offline players. But we've found out that some, not all, of the usernames are in lowercase. Is there any way to fix this?
Every name should be lowercase from LP
Some of them are uppercase though.
https://imgur.com/a/gnw3LEM
Editor iirc gets it from online players, and not the db (which saves lowercase)
all players I took An image of were online though
I'm getting a NullPointerException on the thrid line where "player" is an OfflinePlayer
User user = api.getUserManager().getUser(player.getUniqueId());
Collection<Node> nodes = user.data().toCollection();```
Is there some sort of incompatibility when using OfflinePlayers or am I just missing something?
Yes, getUser doesn't work on offline players because the there is no data loaded
you have to use loadUser instead
!api
Learn how to use the LuckPerms API in your project.
hey
so Im having problems with the prefix
;-;
Ive been on this for a while now
Is this to do with the API?
nah your right lemme go in #support-1
And this will still work if the player is, in fact, online?
Or do I have to do an isOnline check?
getUser will work on online players, yes
Okay. Thank you so much!
How would i change a groups alias/name using lp api?
(I already have an instance of the group)
Specifically i have an instance of the default group and i want to change it's alias
Also is this the best way of getting the default group: (It is async)
Group group = groupManager.createAndLoadGroup("default").join();
I couldn't find a getDefaultGroup or similar
you can probably just getGroup, default is always present since it can't be renamed nor deleted
build a DisplayNameNode and add it to the group's data
Ah i thought the nodes was just for permissions, thanks.
Permissions are nodes, but not all nodes are permission nodes
d;sub_interfaces luckperms Node
net.luckperms.api.node.types.RegexPermissionNode
net.luckperms.api.node.types.InheritanceNode
net.luckperms.api.node.types.MetaNode
net.luckperms.api.node.types.PrefixNode
net.luckperms.api.node.ScopedNode
net.luckperms.api.node.types.SuffixNode
net.luckperms.api.node.types.DisplayNameNode
net.luckperms.api.node.types.WeightNode
net.luckperms.api.node.types.PermissionNode
net.luckperms.api.node.types.ChatMetaNode```
all those are different types of nodes, there is PermissionNode just like there are others
ffs I've contributed to DocDex and I know less about it than you do lol
I also contributed :^)
and the Fefo one-line commit streak continues
mine was 36 additions and 15 deletions
!api
Learn how to use the LuckPerms API in your project.



