Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63878166db | ||
|
|
2ea43d4b2e | ||
|
|
442c7d46f9 | ||
|
|
971bb67b51 | ||
|
|
020aff66aa | ||
|
|
198b86d7c3 | ||
|
|
84e7fd4d09 | ||
|
|
4027129052 | ||
|
|
63f67ca72c | ||
|
|
2adaea2dac | ||
|
|
5e48224c78 | ||
|
|
cc1d8984da | ||
|
|
8d9b4182f4 | ||
|
|
f972113d11 | ||
|
|
4d5a24f2c4 | ||
|
|
e2b575dd24 | ||
|
|
7fae141e33 | ||
|
|
6f90e545fc | ||
|
|
ee3bb22c2c | ||
|
|
361a4d66bc | ||
|
|
e1bac438aa | ||
|
|
ac9706b83f | ||
|
|
fea757887c | ||
|
|
1eab127f50 | ||
|
|
92e008ff0a | ||
|
|
9659333d0e | ||
|
|
d8020e77fe | ||
|
|
232d17436c | ||
|
|
1461651e22 | ||
|
|
ef556f7cf7 | ||
|
|
47ca6b162b | ||
|
|
f72a5cb6b5 | ||
|
|
cd0fd80b33 | ||
|
|
0fd7f643a7 | ||
|
|
6c7c1b67b8 | ||
|
|
4514a17eaf | ||
|
|
adbd2fc81f | ||
|
|
8b506b6a95 | ||
|
|
426c8565fd | ||
|
|
bd6d3ab7c0 | ||
|
|
d12d13d6ea | ||
|
|
cc08390abe | ||
|
|
b460e282b1 | ||
|
|
005d19f2a3 | ||
|
|
8817e17d2c | ||
|
|
0f23b7a460 | ||
|
|
21ae1dbac0 | ||
|
|
6cb0f5e810 | ||
|
|
2ac7d3dfe6 | ||
|
|
bfaa543ecd | ||
|
|
f893b1c632 | ||
|
|
cb5a28f043 | ||
|
|
bd9718c5af | ||
|
|
97a0dbebcb | ||
|
|
df324de9ec | ||
|
|
6fa690a49d | ||
|
|
2bb1aa7511 | ||
|
|
0bef0902c0 | ||
|
|
f10f60e27f | ||
|
|
91337b49ea | ||
|
|
f5e41f7e7e | ||
|
|
fe0e82f285 | ||
|
|
8996cf02af | ||
|
|
e37c77a1be | ||
|
|
11998b2dd6 | ||
|
|
8754123535 | ||
|
|
91d75424f4 | ||
|
|
c5c99abd16 | ||
|
|
6c88f7629e | ||
|
|
98c71739f8 | ||
|
|
25551641fc | ||
|
|
00b701f129 | ||
|
|
ab082aa311 | ||
|
|
dc32c84bb3 | ||
|
|
0bb4161397 | ||
|
|
4a049ca732 | ||
|
|
d5ac45d230 | ||
|
|
6b3e4bdc71 | ||
|
|
5c0d82f306 | ||
|
|
5a6176def5 | ||
|
|
13ebc87b29 | ||
|
|
1ca1bcf1d1 | ||
|
|
ea5a05d770 | ||
|
|
ed85ab1bfd | ||
|
|
c09e4a1aa0 | ||
|
|
ee36fa9d81 | ||
|
|
bfa5fc43cd | ||
|
|
5d6389249a | ||
|
|
637cb0d836 | ||
|
|
bfebe6a5d0 | ||
|
|
4cbbbd390f | ||
|
|
c120fa6a4d | ||
|
|
918ea7503a | ||
|
|
dbe07827bd | ||
|
|
98eb756951 | ||
|
|
86eeeb5b94 | ||
|
|
a3e6628e11 | ||
|
|
84bc4217de | ||
|
|
b88819b9bb | ||
|
|
c7a0e59919 | ||
|
|
9984d4be42 | ||
|
|
a1c91b9007 | ||
|
|
6a256d59f5 | ||
|
|
fca2f1e6de | ||
|
|
ec7994a561 | ||
|
|
2839c36ea2 | ||
|
|
9f22bf2fbf | ||
|
|
5f0df1b167 | ||
|
|
3bf2fab2e9 | ||
|
|
73d76d860e | ||
|
|
bcfcb64931 | ||
|
|
a19cb71394 | ||
|
|
52731fe68e | ||
|
|
7845d89f10 | ||
|
|
3d358e57ff | ||
|
|
bd9ae9dbd5 | ||
|
|
f281927578 | ||
|
|
665c53093a | ||
|
|
10fbc24f43 | ||
|
|
6631e9144e | ||
|
|
7ae532f082 | ||
|
|
1af55e3720 | ||
|
|
fe32aa2d33 | ||
|
|
f6460c2802 | ||
|
|
045c10048d | ||
|
|
308356de80 | ||
|
|
8771d4c5e5 | ||
|
|
cd25681cd3 | ||
|
|
ad6a11819d | ||
|
|
b17da055af | ||
|
|
2fd896508b | ||
|
|
99348fce53 | ||
|
|
eb0d758efc | ||
|
|
c03aca35d6 | ||
|
|
f484e87828 | ||
|
|
07b2df7c7e | ||
|
|
cab15d39c3 | ||
|
|
36335c10a4 | ||
|
|
642d14d003 | ||
|
|
175808e251 | ||
|
|
14d952a212 | ||
|
|
37e09caac5 | ||
|
|
4d7a6cb658 | ||
|
|
cc80fe5105 | ||
|
|
b79f6b0fdd | ||
|
|
83e9ac04b2 | ||
|
|
8cecfe5b7c | ||
|
|
54aed80db8 | ||
|
|
0d89fc9d28 | ||
|
|
cee34d0c31 | ||
|
|
d2e60eb5ac | ||
|
|
c71742a996 | ||
|
|
fe139f8420 | ||
|
|
bb015d0c88 | ||
|
|
94809c2a66 | ||
|
|
141d3e26ea | ||
|
|
efb958ba44 | ||
|
|
9f0fe9e0cb | ||
|
|
2028d65579 | ||
|
|
c98c60b120 | ||
|
|
6805574553 | ||
|
|
c3128dec0d | ||
|
|
b65639cd76 | ||
|
|
42e9f43443 | ||
|
|
c40ad63291 | ||
|
|
0964762217 | ||
|
|
3553a0f9fe | ||
|
|
24304a61a7 | ||
|
|
497846e5a6 | ||
|
|
0729be0f0a | ||
|
|
2adea2d3dc | ||
|
|
30d7768299 | ||
|
|
3a7fadb843 | ||
|
|
779bbb9f88 | ||
|
|
a721cc0b7c | ||
|
|
3973aa1000 | ||
|
|
ac9fe74785 | ||
|
|
46c9e3b713 | ||
|
|
05b82cdbab | ||
|
|
3086724e92 | ||
|
|
fbac03e372 | ||
|
|
2518a7c8e5 | ||
|
|
bbec0932fd | ||
|
|
bca766c20d | ||
|
|
bb3afa21a4 | ||
|
|
85451a9a20 | ||
|
|
d475ace76c | ||
|
|
9f3395f256 | ||
|
|
c6bda0875c | ||
|
|
4f63a00bad | ||
|
|
0a3141841c | ||
|
|
6fea194ef5 | ||
|
|
e66ab1be0d | ||
|
|
5ce8217cd5 | ||
|
|
2ed45c92a6 | ||
|
|
9f7d431d34 | ||
|
|
d937c9ce06 | ||
|
|
6a96d40da4 | ||
|
|
2eabe845d7 | ||
|
|
4cfee76202 | ||
|
|
446fa48d9a | ||
|
|
9546987970 | ||
|
|
7a624fb449 | ||
|
|
26de6cf86f | ||
|
|
5fe7302965 | ||
|
|
a779b31ca5 | ||
|
|
8fa629a243 | ||
|
|
0864cf756c | ||
|
|
e9d72df890 | ||
|
|
c39a44c3ac | ||
|
|
7e8402b542 | ||
|
|
a050a2604f | ||
|
|
abad672bef | ||
|
|
fe3d715f09 | ||
|
|
e151fbe298 | ||
|
|
2ccb475aa0 | ||
|
|
4c83d439af | ||
|
|
352f3bd263 | ||
|
|
b73b73e221 | ||
|
|
c454d17826 | ||
|
|
098f8d8231 | ||
|
|
c1e3660551 | ||
|
|
3ceb53aa4f | ||
|
|
a33f326cfc | ||
|
|
83883aa7e6 | ||
|
|
3fae4e5e9e | ||
|
|
4e9b11f30a | ||
|
|
46dc4e5104 | ||
|
|
9c8bdb1166 | ||
|
|
242993763c | ||
|
|
b84518e1f1 | ||
|
|
b2593d409e | ||
|
|
d3b3a8af38 | ||
|
|
ec2cb5007c | ||
|
|
ca33cee79d | ||
|
|
2d456bd346 | ||
|
|
10680668db | ||
|
|
0e64b61be4 | ||
|
|
96c53091d0 | ||
|
|
6e64f80c81 | ||
|
|
8906e4c4fc | ||
|
|
cc5d7ea873 | ||
|
|
6237d58ad6 | ||
|
|
fae5ebe226 | ||
|
|
9a92920120 | ||
|
|
dc5c6b0138 | ||
|
|
88c432496b | ||
|
|
63b890d522 | ||
|
|
cd5c8d7cdf | ||
|
|
d80017ba7b | ||
|
|
5eb8a262be | ||
|
|
7474842b45 | ||
|
|
9093385de3 | ||
|
|
bd349ac4a3 | ||
|
|
37367fe91f | ||
|
|
dce792083b | ||
|
|
06f7900318 | ||
|
|
d8ac199858 | ||
|
|
9cf21e2927 | ||
|
|
86a15b9a66 | ||
|
|
31b57df567 | ||
|
|
a07f876c85 | ||
|
|
2eb0c1e67e | ||
|
|
6325e25630 | ||
|
|
6fdd349654 | ||
|
|
01e17adf82 | ||
|
|
acdd5f3faa | ||
|
|
4d3c692402 | ||
|
|
787f691f44 | ||
|
|
500385cd3e | ||
|
|
6df64a29dc | ||
|
|
233324f6c9 | ||
|
|
da253c47da |
No files matched your search
@@ -1 +1,2 @@
|
||||
github: lucko
|
||||
patreon: luckdev
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
name: 🐛 Bug report
|
||||
about: Report an issue or problem with the way LuckPerms is functioning.
|
||||
title: ''
|
||||
labels: 'type: issue'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Before going any further, please check to see if your problem is fixed by updating to a newer version. The latest development builds can be obtained from https://luckperms.net/download -->
|
||||
|
||||
### Description
|
||||
<!-- Please provide a short description of the issue in the space below. -->
|
||||
|
||||
|
||||
### Reproduction steps
|
||||
<!-- Please provide a clear list of steps we should follow in order to reproduce your issue in the space below. -->
|
||||
|
||||
1. Open the config.yml file and set example to true.
|
||||
2. Restart the server
|
||||
3. Run /lp user example permission set x from the console
|
||||
4. See error
|
||||
|
||||
|
||||
### Expected behaviour
|
||||
<!-- Please provide a description of what you expected to happen. -->
|
||||
|
||||
|
||||
### Environment details
|
||||
<!-- Please provide details of your server environment in the space below. -->
|
||||
|
||||
* Server type/version: `ExampleSpigot` running version `1.12.2` build `???`
|
||||
* LuckPerms version: `v???`
|
||||
|
||||
<!-- If you think it would be helpful, please also include a "pastebin" of any relevant config files or log output. You should use https://gist.github.com/ to upload, then include the link below. -->
|
||||
|
||||
|
||||
### Any other relevant details
|
||||
<!-- Please include any other relevant details in the space below. -->
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 💬 Ask a question
|
||||
url: https://discord.gg/luckperms
|
||||
about: We use Discord to provide support for the project. If you have a question, need help, or aren't sure if you've found a bug or not, please come and talk to us there!
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: 💡 Suggestion
|
||||
about: Suggest an idea for an improvement or change to LuckPerms.
|
||||
title: ''
|
||||
labels: 'type: suggestion'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Description
|
||||
<!-- Please provide a short description of the suggestion in the space below. -->
|
||||
|
||||
|
||||
### Proposed behaviour
|
||||
<!-- Please provide a short explanation of how the feature should work / be changed, and how this will effect the project. -->
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||

|
||||
# LuckPerms
|
||||
[](https://ci.lucko.me/job/LuckPerms/)
|
||||
[](https://javadoc.io/doc/me.lucko.luckperms/luckperms-api)
|
||||
[](https://search.maven.org/artifact/me.lucko.luckperms/luckperms-api)
|
||||
[](https://javadoc.io/doc/net.luckperms/api)
|
||||
[](https://search.maven.org/artifact/net.luckperms/api)
|
||||
[](https://discord.gg/luckperms)
|
||||
|
||||
LuckPerms is an advanced permissions implementation aiming to be a fast, reliable and flexible alternative to existing permission plugins. The project's main goals are centered around high performance and a wide feature set, filling the gaps of functionality and building upon existing features found in other plugins.
|
||||
LuckPerms is a permissions plugin for Minecraft servers. It allows server admins to control what features players can use by creating groups and assigning permissions.
|
||||
|
||||
LuckPerms also includes an extensive API for developers, and support for a variety of Minecraft server software & data storage options.
|
||||
It is:
|
||||
|
||||
Still not convinced? More information can be found on the wiki, under: [Why LuckPerms?](https://github.com/lucko/LuckPerms/wiki/Why-LuckPerms)
|
||||
* **fast** - written with performance and scalability in mind.
|
||||
* **reliable** - trusted by thousands of server admins, and the largest of server networks.
|
||||
* **easy to use** - setup permissions using commands, directly in config files, or using the web editor.
|
||||
* **flexible** - supports a variety of data storage options, and works on lots of different server types.
|
||||
* **extensive** - a plethora of customization options and settings which can be changed to suit your server.
|
||||
* **free** - available for download and usage at no cost, and permissively licensed so it can remain free forever.
|
||||
|
||||
For more information, see the wiki article on [Why LuckPerms?](https://github.com/lucko/LuckPerms/wiki/Why-LuckPerms)
|
||||
|
||||
## Useful Links
|
||||
|
||||
The latest **downloads** can be found on the [project's homepage](https://luckperms.net/).
|
||||
|
||||
More information about the project & how to use the plugin can be found in the [wiki](https://github.com/lucko/LuckPerms/wiki).
|
||||
The latest downloads & other useful links can be found on the project homepage at [luckperms.net](https://luckperms.net/).
|
||||
|
||||
## Building
|
||||
LuckPerms uses Gradle to handle dependencies & building.
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
group = 'net.luckperms'
|
||||
project.version = '5.0'
|
||||
project.version = '5.2'
|
||||
|
||||
dependencies {
|
||||
compileOnly 'org.checkerframework:checker-qual:2.5.5'
|
||||
@@ -56,7 +56,7 @@ if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePass
|
||||
pom {
|
||||
project {
|
||||
name 'LuckPerms API'
|
||||
description 'An advanced permissions plugin for Bukkit/Spigot, BungeeCord, Sponge, Nukkit and Velocity.'
|
||||
description 'A permissions plugin for Minecraft servers.'
|
||||
url 'https://luckperms.net'
|
||||
|
||||
licenses {
|
||||
@@ -68,9 +68,10 @@ if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePass
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id 'lucko'
|
||||
name 'Luck'
|
||||
url 'https://lucko.me'
|
||||
email 'git@lucko.me'
|
||||
url 'https://github.com/lucko'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,11 @@ import net.luckperms.api.model.group.GroupManager;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.luckperms.api.model.user.UserManager;
|
||||
import net.luckperms.api.node.NodeBuilderRegistry;
|
||||
import net.luckperms.api.node.matcher.NodeMatcherFactory;
|
||||
import net.luckperms.api.platform.Platform;
|
||||
import net.luckperms.api.platform.PlayerAdapter;
|
||||
import net.luckperms.api.platform.PluginMetadata;
|
||||
import net.luckperms.api.query.QueryOptionsRegistry;
|
||||
import net.luckperms.api.track.Track;
|
||||
import net.luckperms.api.track.TrackManager;
|
||||
|
||||
@@ -114,6 +117,32 @@ public interface LuckPerms {
|
||||
*/
|
||||
@NonNull TrackManager getTrackManager();
|
||||
|
||||
/**
|
||||
* Gets the {@link PlayerAdapter} instance, a utility class for adapting platform Player
|
||||
* instances to {@link User}s.
|
||||
*
|
||||
* <p>The {@code playerClass} parameter must be equal to the class or interface used by the
|
||||
* server platform to represent players.</p>
|
||||
*
|
||||
* <p>Specifically:</p>
|
||||
*
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@code org.bukkit.entity.Player}</li>
|
||||
* <li>{@code net.md_5.bungee.api.connection.ProxiedPlayer}</li>
|
||||
* <li>{@code org.spongepowered.api/entity.living.player.Player}</li>
|
||||
* <li>{@code cn.nukkit.Player}</li>
|
||||
* <li>{@code com.velocitypowered.api.proxy.Player}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param playerClass the class used by the platform to represent players
|
||||
* @param <T> the player class type
|
||||
* @return the player adapter
|
||||
* @throws IllegalArgumentException if the player class is not correct
|
||||
* @since 5.1
|
||||
*/
|
||||
<T> @NonNull PlayerAdapter<T> getPlayerAdapter(@NonNull Class<T> playerClass);
|
||||
|
||||
/**
|
||||
* Gets the {@link Platform}, which represents the server platform the
|
||||
* plugin is running on.
|
||||
@@ -172,6 +201,14 @@ public interface LuckPerms {
|
||||
*/
|
||||
@NonNull NodeBuilderRegistry getNodeBuilderRegistry();
|
||||
|
||||
/**
|
||||
* Gets the {@link QueryOptionsRegistry}.
|
||||
*
|
||||
* @return the query options registry
|
||||
* @since 5.1
|
||||
*/
|
||||
@NonNull QueryOptionsRegistry getQueryOptionsRegistry();
|
||||
|
||||
/**
|
||||
* Gets the {@link MetaStackFactory}.
|
||||
*
|
||||
@@ -183,6 +220,14 @@ public interface LuckPerms {
|
||||
*/
|
||||
@NonNull MetaStackFactory getMetaStackFactory();
|
||||
|
||||
/**
|
||||
* Gets the {@link NodeMatcherFactory}.
|
||||
*
|
||||
* @return the node matcher factory
|
||||
* @since 5.1
|
||||
*/
|
||||
@NonNull NodeMatcherFactory getNodeMatcherFactory();
|
||||
|
||||
/**
|
||||
* Schedules the execution of an update task, and returns an encapsulation
|
||||
* of the task as a {@link CompletableFuture}.
|
||||
|
||||
@@ -25,7 +25,10 @@
|
||||
|
||||
package net.luckperms.api.cacheddata;
|
||||
|
||||
import net.luckperms.api.context.ContextManager;
|
||||
import net.luckperms.api.model.PermissionHolder;
|
||||
import net.luckperms.api.model.group.Group;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
@@ -56,23 +59,58 @@ public interface CachedDataManager {
|
||||
@NonNull Container<CachedMetaData> metaData();
|
||||
|
||||
/**
|
||||
* Gets PermissionData from the cache, given a specified context.
|
||||
* Gets PermissionData from the cache, using the given query options.
|
||||
*
|
||||
* @param queryOptions the query options
|
||||
* @return a permission data instance
|
||||
* @throws NullPointerException if contexts is null
|
||||
*/
|
||||
@NonNull CachedPermissionData getPermissionData(@NonNull QueryOptions queryOptions);
|
||||
|
||||
/**
|
||||
* Gets MetaData from the cache, given a specified context.
|
||||
* Gets MetaData from the cache, using the given query options.
|
||||
*
|
||||
* @param queryOptions the query options
|
||||
* @return a meta data instance
|
||||
* @throws NullPointerException if contexts is null
|
||||
*/
|
||||
@NonNull CachedMetaData getMetaData(@NonNull QueryOptions queryOptions);
|
||||
|
||||
/**
|
||||
* Gets PermissionData from the cache, using the most appropriate query options
|
||||
* available at the time.
|
||||
*
|
||||
* <p>For {@link User}s, the most appropriate query options will be their
|
||||
* {@link ContextManager#getQueryOptions(User) current active query options} if the
|
||||
* corresponding player is online, and otherwise, will fallback to
|
||||
* {@link ContextManager#getStaticQueryOptions() the current static query options}
|
||||
* if they are offline.</p>
|
||||
*
|
||||
* <p>For {@link Group}s, the most appropriate query options will always be
|
||||
* {@link ContextManager#getStaticQueryOptions()} the current static query options.</p>
|
||||
*
|
||||
* @return a permission data instance
|
||||
* @since 5.1
|
||||
*/
|
||||
@NonNull CachedPermissionData getPermissionData();
|
||||
|
||||
/**
|
||||
* Gets MetaData from the cache, using the most appropriate query options
|
||||
* available at the time.
|
||||
*
|
||||
* <p>For {@link User}s, the most appropriate query options will be their
|
||||
* {@link ContextManager#getQueryOptions(User) current active query options} if the
|
||||
* corresponding player is online, and otherwise, will fallback to
|
||||
* {@link ContextManager#getStaticQueryOptions() the current static query options}
|
||||
* if they are offline.</p>
|
||||
*
|
||||
* <p>For {@link Group}s, the most appropriate query options will always be
|
||||
* {@link ContextManager#getStaticQueryOptions()} the current static query options.</p>
|
||||
*
|
||||
* @return a meta data instance
|
||||
* @since 5.1
|
||||
* @see PermissionHolder#getQueryOptions()
|
||||
*/
|
||||
@NonNull CachedMetaData getMetaData();
|
||||
|
||||
/**
|
||||
* Invalidates all cached {@link CachedPermissionData} and {@link CachedMetaData}
|
||||
* instances.
|
||||
|
||||
@@ -48,42 +48,52 @@ public interface CachedMetaData extends CachedData {
|
||||
@Nullable String getMetaValue(String key);
|
||||
|
||||
/**
|
||||
* Gets the user's highest priority prefix, or null if the user has no prefixes
|
||||
* Gets the holder's highest priority prefix, or null if the holder has no prefixes
|
||||
*
|
||||
* @return a prefix string, or null
|
||||
*/
|
||||
@Nullable String getPrefix();
|
||||
|
||||
/**
|
||||
* Gets the user's highest priority suffix, or null if the user has no suffixes
|
||||
* Gets the holder's highest priority suffix, or null if the holder has no suffixes
|
||||
*
|
||||
* @return a suffix string, or null
|
||||
*/
|
||||
@Nullable String getSuffix();
|
||||
|
||||
/**
|
||||
* Gets an immutable copy of the meta this user has.
|
||||
* Gets an immutable copy of the meta this holder has.
|
||||
*
|
||||
* @return an immutable map of meta
|
||||
*/
|
||||
@NonNull Map<String, List<String>> getMeta();
|
||||
|
||||
/**
|
||||
* Gets an immutable sorted map of all of the prefixes the user has, whereby the first value is the highest priority
|
||||
* prefix.
|
||||
* Gets an immutable sorted map of all of the prefixes the holder has, whereby the first
|
||||
* value is the highest priority prefix.
|
||||
*
|
||||
* @return a sorted map of prefixes
|
||||
*/
|
||||
@NonNull SortedMap<Integer, String> getPrefixes();
|
||||
|
||||
/**
|
||||
* Gets an immutable sorted map of all of the suffixes the user has, whereby the first value is the highest priority
|
||||
* suffix.
|
||||
* Gets an immutable sorted map of all of the suffixes the holder has, whereby the first
|
||||
* value is the highest priority suffix.
|
||||
*
|
||||
* @return a sorted map of suffixes
|
||||
*/
|
||||
@NonNull SortedMap<Integer, String> getSuffixes();
|
||||
|
||||
/**
|
||||
* Gets the name of the holders primary group.
|
||||
*
|
||||
* <p>Will return {@code null} for Group holder types.</p>
|
||||
*
|
||||
* @return the name of the primary group
|
||||
* @since 5.1
|
||||
*/
|
||||
@Nullable String getPrimaryGroup();
|
||||
|
||||
/**
|
||||
* Gets the definition used for the prefix stack
|
||||
*
|
||||
|
||||
@@ -26,12 +26,64 @@
|
||||
package net.luckperms.api.context;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents an individual context pair.
|
||||
*
|
||||
* <p>Context keys and values may not be null or empty. A key/value will be
|
||||
* deemed empty if it's length is zero, or if it consists of only space
|
||||
* characters.</p>
|
||||
*
|
||||
* @see ContextSet
|
||||
*/
|
||||
public interface Context {
|
||||
|
||||
/**
|
||||
* Tests whether {@code key} is valid.
|
||||
*
|
||||
* <p>Context keys and values may not be null or empty. A key/value will be
|
||||
* deemed empty if it's length is zero, or if it consists of only space
|
||||
* characters.</p>
|
||||
*
|
||||
* <p>An exception is thrown when an invalid key is added to a {@link ContextSet}.</p>
|
||||
*
|
||||
* @param key the key to test
|
||||
* @return true if valid, false otherwise.
|
||||
* @since 5.1
|
||||
*/
|
||||
static boolean isValidKey(@Nullable String key) {
|
||||
if (key == null || key.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// look for a non-whitespace character
|
||||
for (int i = 0, n = key.length(); i < n; i++) {
|
||||
if (key.charAt(i) != ' ') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether {@code value} is valid.
|
||||
*
|
||||
* <p>Context keys and values may not be null or empty. A key/value will be
|
||||
* deemed empty if it's length is zero, or if it consists of only space
|
||||
* characters.</p>
|
||||
*
|
||||
* <p>An exception is thrown when an invalid value is added to a {@link ContextSet}.</p>
|
||||
*
|
||||
* @param value the value to test
|
||||
* @return true if valid, false otherwise.
|
||||
* @since 5.1
|
||||
*/
|
||||
static boolean isValidValue(@Nullable String value) {
|
||||
return isValidKey(value); // the same for now...
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the context key.
|
||||
*
|
||||
|
||||
@@ -37,11 +37,11 @@ import java.util.Optional;
|
||||
* Manages {@link ContextCalculator}s, and calculates applicable contexts for a
|
||||
* given type.
|
||||
*
|
||||
* This interface accepts {@link Object} types as a parameter to avoid having to depend
|
||||
* <p>This interface accepts {@link Object} types as a parameter to avoid having to depend
|
||||
* on specific server implementations. In all cases, the "player" or "subject" type for
|
||||
* the platform must be used.
|
||||
* the platform must be used.</p>
|
||||
*
|
||||
* Specifically:
|
||||
* <p>Specifically:</p>
|
||||
*
|
||||
* <p></p>
|
||||
* <ul>
|
||||
@@ -138,6 +138,18 @@ public interface ContextManager {
|
||||
*/
|
||||
void unregisterCalculator(@NonNull ContextCalculator<?> calculator);
|
||||
|
||||
/**
|
||||
* Signal to the {@link ContextManager} that a {@code subject}s
|
||||
* current contexts have changed.
|
||||
*
|
||||
* <p>It is not strictly necessary to make a call to this method every time a context
|
||||
* changes.</p>
|
||||
*
|
||||
* @param subject the subject
|
||||
* @since 5.2
|
||||
*/
|
||||
void signalContextUpdate(@NonNull Object subject);
|
||||
|
||||
/**
|
||||
* Gets the {@link ContextSetFactory}, responsible for creating
|
||||
* {@link ContextSet} instances.
|
||||
@@ -150,7 +162,11 @@ public interface ContextManager {
|
||||
* Invalidates the lookup cache for a given subject
|
||||
*
|
||||
* @param subject the subject
|
||||
* @deprecated use {@link #signalContextUpdate(Object)}
|
||||
*/
|
||||
void invalidateCache(@NonNull Object subject);
|
||||
@Deprecated
|
||||
default void invalidateCache(@NonNull Object subject) {
|
||||
signalContextUpdate(subject);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.luckperms.api.context;
|
||||
|
||||
import net.luckperms.api.query.OptionKey;
|
||||
|
||||
/**
|
||||
* Mode for determining whether a {@link ContextSet} satisfies another.
|
||||
*
|
||||
* @since 5.2
|
||||
* @see ContextSet#isSatisfiedBy(ContextSet, ContextSatisfyMode)
|
||||
*/
|
||||
public enum ContextSatisfyMode {
|
||||
|
||||
/**
|
||||
* Mode where a {@link ContextSet} A will be satisfied by another set B, if at least one of the
|
||||
* key-value entries per key in A are also in B.
|
||||
*
|
||||
* <p>For example, given <code>A = {server=survival, world=overworld, world=nether}</code>,
|
||||
* another set {@code X} will satisfy {@code A} if {@code X} contains
|
||||
* <code>server=survival AND (world=overworld OR world=nether)</code>.</p>
|
||||
*/
|
||||
AT_LEAST_ONE_VALUE_PER_KEY,
|
||||
|
||||
/**
|
||||
* Mode where a {@link ContextSet} A will be satisfied by another set B, if all key-value
|
||||
* entries in A are also in B.
|
||||
*
|
||||
* <p>For example, given <code>A = {server=survival, world=overworld, world=nether}</code>,
|
||||
* another set {@code X} will satisfy {@code A} if {@code X} contains
|
||||
* <code>server=survival AND world=overworld AND world=nether</code>.</p>
|
||||
*/
|
||||
ALL_VALUES_PER_KEY;
|
||||
|
||||
/**
|
||||
* The {@link OptionKey} for {@link ContextSatisfyMode}.
|
||||
*/
|
||||
public static final OptionKey<ContextSatisfyMode> KEY = OptionKey.of("contextsatisfymode", ContextSatisfyMode.class);
|
||||
|
||||
}
|
||||
@@ -40,19 +40,33 @@ import java.util.Set;
|
||||
* something will apply.</p>
|
||||
*
|
||||
* <p>A single "context" consists of a key and a value, both strings. The key
|
||||
* represents the type of context, and the value represents the setting of the
|
||||
* context key.</p>
|
||||
* describes the type of the context, and the value represents what the key is
|
||||
* set to.</p>
|
||||
*
|
||||
* <p>For example, a context with {@code key=world} and {@code value=world_nether}
|
||||
* describes that a subject is in the "world_nether" world.</p>
|
||||
*
|
||||
* <p>Contexts are exposed to end users and manipulated when managing permissions.
|
||||
* For this reason, context keys should strike a balance between being descriptive
|
||||
* and succinct.</p>
|
||||
*
|
||||
* <p>Context keys and values are case-insensitive, and will be automatically
|
||||
* converted to {@link String#toLowerCase() lowercase} when added to a
|
||||
* context set. Keys and values cannot be null or empty (len=0 or consisting of
|
||||
* only whitespace).</p>
|
||||
*
|
||||
* <p>If a context key is formed of more than one word, the parts should be
|
||||
* separated by the '{@code -}' character. (e.g. "{@code server-type}")</p>
|
||||
*
|
||||
* <p>If a context key is likely to conflict with another plugin, it should be
|
||||
* appropriately namespaced using the name of the plugin providing the context.
|
||||
* The namespace should be at the start of the context key, and separated using
|
||||
* the '{@code :}' character. (e.g. "{@code worldguard:region}" for WorldGuard
|
||||
* regions)</p>
|
||||
*
|
||||
* <p>Contexts can be combined with each other to form so called
|
||||
* "context sets" - simply a collection of context pairs.</p>
|
||||
*
|
||||
* <p>Context keys and values are case-insensitive, and will be converted to
|
||||
* {@link String#toLowerCase() lowercase} by all implementations.</p>
|
||||
*
|
||||
* <p>Context keys and values may not be null or empty. A key/value will be
|
||||
* deemed empty if it's length is zero, or if it consists of only space
|
||||
* characters.</p>
|
||||
*
|
||||
* <p>Two default ContextSet implementations are provided.
|
||||
* {@link MutableContextSet} allows the addition and removal of context keys
|
||||
* after construction, and {@link ImmutableContextSet} does not.</p>
|
||||
@@ -197,17 +211,47 @@ public interface ContextSet extends Iterable<Context> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this {@link ContextSet} is fully "satisfied" by another set.
|
||||
* Returns if the {@link ContextSet} contains any of the given context pairings.
|
||||
*
|
||||
* <p>For a context set to "satisfy" another, it must itself contain all of
|
||||
* the context pairings in the other set.</p>
|
||||
*
|
||||
* <p>Mathematically, this method returns true if this set is a <b>subset</b> of the other.</p>
|
||||
*
|
||||
* @param other the other set to check
|
||||
* @return true if all entries in this set are also in the other set
|
||||
* @param key the key to look for
|
||||
* @param values the values to look for
|
||||
* @return true if the set contains any of the pairs
|
||||
* @since 5.2
|
||||
*/
|
||||
boolean isSatisfiedBy(@NonNull ContextSet other);
|
||||
default boolean containsAny(@NonNull String key, @NonNull Iterable<String> values) {
|
||||
Objects.requireNonNull(key, "key");
|
||||
Objects.requireNonNull(values, "values");
|
||||
|
||||
for (String value : values) {
|
||||
if (contains(key, value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this {@link ContextSet} is "satisfied" by another set.
|
||||
*
|
||||
* <p>{@link ContextSatisfyMode#AT_LEAST_ONE_VALUE_PER_KEY} is the mode used by this method.</p>
|
||||
*
|
||||
* @param other the other set
|
||||
* @return true if this context set is satisfied by the other
|
||||
*/
|
||||
default boolean isSatisfiedBy(@NonNull ContextSet other) {
|
||||
return isSatisfiedBy(other, ContextSatisfyMode.AT_LEAST_ONE_VALUE_PER_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this {@link ContextSet} is "satisfied" by another set, according to the given
|
||||
* {@code mode}.
|
||||
*
|
||||
* @param other the other set
|
||||
* @param mode the mode to use
|
||||
* @return true if this context set is satisfied by the other
|
||||
* @since 5.2
|
||||
*/
|
||||
boolean isSatisfiedBy(@NonNull ContextSet other, @NonNull ContextSatisfyMode mode);
|
||||
|
||||
/**
|
||||
* Returns if the {@link ContextSet} is empty.
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.luckperms.api.event.context;
|
||||
|
||||
import net.luckperms.api.context.ContextManager;
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Called when a subject's current/active contexts are updated.
|
||||
*
|
||||
* <p>There are no guarantees that this event will be called for every update. It is merely to be
|
||||
* used as a "hint" for plugins which depend on the current active contexts for a player.</p>
|
||||
*
|
||||
* <p>It will always be fired following a call to
|
||||
* {@link ContextManager#signalContextUpdate(Object)}.</p>
|
||||
*
|
||||
* <p>The {@link #getSubject() subject} is always an instance of the platform's subject type. See
|
||||
* {@link ContextManager} for details.</p>
|
||||
*
|
||||
* <p>Unlike most other LuckPerms events, this event is not fired asynchronously. Care should be
|
||||
* taken to ensure listeners are lightweight. Additionally, listeners should ensure they do not
|
||||
* cause further updates to player context, thus possibly causing a stack overflow.</p>
|
||||
*
|
||||
* @since 5.2
|
||||
*/
|
||||
public interface ContextUpdateEvent extends LuckPermsEvent {
|
||||
|
||||
/**
|
||||
* Gets the subject whose contexts were updated.
|
||||
*
|
||||
* @return the subject
|
||||
*/
|
||||
@Param(0)
|
||||
@NonNull Object getSubject();
|
||||
|
||||
/**
|
||||
* Gets the subject whose contexts were updated, casted to a given type.
|
||||
*
|
||||
* @param subjectClass the type to cast to
|
||||
* @param <T> the subject type
|
||||
* @return the casted subject
|
||||
*/
|
||||
default <T> @NonNull Optional<T> getSubject(@NonNull Class<T> subjectClass) {
|
||||
Object subject = getSubject();
|
||||
return subjectClass.isInstance(subject) ? Optional.of(subjectClass.cast(subject)) : Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,8 +26,8 @@
|
||||
package net.luckperms.api.event.group;
|
||||
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
import net.luckperms.api.event.cause.CreationCause;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
import net.luckperms.api.model.group.Group;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
package net.luckperms.api.event.group;
|
||||
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
import net.luckperms.api.event.cause.DeletionCause;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
import net.luckperms.api.node.Node;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
package net.luckperms.api.event.log;
|
||||
|
||||
import net.luckperms.api.actionlog.Action;
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
package net.luckperms.api.event.log;
|
||||
|
||||
import net.luckperms.api.actionlog.Action;
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
package net.luckperms.api.event.log;
|
||||
|
||||
import net.luckperms.api.actionlog.Action;
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
import net.luckperms.api.platform.PlatformEntity;
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
package net.luckperms.api.event.log;
|
||||
|
||||
import net.luckperms.api.actionlog.Action;
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
package net.luckperms.api.event.sync;
|
||||
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
package net.luckperms.api.event.sync;
|
||||
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.type.Cancellable;
|
||||
|
||||
/**
|
||||
* Called before a sync task runs
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
package net.luckperms.api.event.track;
|
||||
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
import net.luckperms.api.event.cause.CreationCause;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
import net.luckperms.api.track.Track;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
package net.luckperms.api.event.track;
|
||||
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
import net.luckperms.api.event.cause.DeletionCause;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
package net.luckperms.api.event.user.track;
|
||||
|
||||
import net.luckperms.api.event.LuckPermsEvent;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
import net.luckperms.api.event.type.Sourced;
|
||||
import net.luckperms.api.event.util.Param;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.luckperms.api.track.Track;
|
||||
|
||||
|
||||
@@ -26,18 +26,24 @@
|
||||
package net.luckperms.api.model;
|
||||
|
||||
import net.luckperms.api.cacheddata.CachedDataManager;
|
||||
import net.luckperms.api.context.ContextManager;
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
import net.luckperms.api.model.data.NodeMap;
|
||||
import net.luckperms.api.model.group.Group;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.NodeType;
|
||||
import net.luckperms.api.query.Flag;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Generic superinterface for an object which holds permissions.
|
||||
@@ -108,6 +114,24 @@ public interface PermissionHolder {
|
||||
*/
|
||||
@NonNull String getFriendlyName();
|
||||
|
||||
/**
|
||||
* Gets the most appropriate query options available at the time for the
|
||||
* {@link PermissionHolder}.
|
||||
*
|
||||
* <p>For {@link User}s, the most appropriate query options will be their
|
||||
* {@link ContextManager#getQueryOptions(User) current active query options} if the
|
||||
* corresponding player is online, and otherwise, will fallback to
|
||||
* {@link ContextManager#getStaticQueryOptions() the current static query options}
|
||||
* if they are offline.</p>
|
||||
*
|
||||
* <p>For {@link Group}s, the most appropriate query options will always be
|
||||
* {@link ContextManager#getStaticQueryOptions()} the current static query options.</p>
|
||||
*
|
||||
* @return query options
|
||||
* @since 5.1
|
||||
*/
|
||||
@NonNull QueryOptions getQueryOptions();
|
||||
|
||||
/**
|
||||
* Gets the holders {@link CachedDataManager} cache.
|
||||
*
|
||||
@@ -121,7 +145,7 @@ public interface PermissionHolder {
|
||||
* @param dataType the data type
|
||||
* @return the data
|
||||
*/
|
||||
NodeMap getData(@NonNull DataType dataType);
|
||||
@NonNull NodeMap getData(@NonNull DataType dataType);
|
||||
|
||||
/**
|
||||
* Gets the holders {@link DataType#NORMAL} data.
|
||||
@@ -149,35 +173,60 @@ public interface PermissionHolder {
|
||||
@NonNull NodeMap transientData();
|
||||
|
||||
/**
|
||||
* Gets a flattened/squashed view of the holders permissions.
|
||||
* Gets a flattened view of the holders own {@link Node}s.
|
||||
*
|
||||
* <p>This list is constructed using the values
|
||||
* of both the transient and enduring backing multimaps.</p>
|
||||
* <p>This list is constructed using the values of both the {@link #data() normal}
|
||||
* and {@link #transientData() transient} backing node maps.</p>
|
||||
*
|
||||
* <p>This means that it <b>may contain</b> duplicate entries.</p>
|
||||
*
|
||||
* <p>Use {@link #getDistinctNodes()} for a view without duplicates.</p>
|
||||
* <p>It <b>may contain</b> duplicate entries if the same node is added to both the normal
|
||||
* and transient node maps. You can use {@link #getDistinctNodes()} for a view without
|
||||
* duplicates.</p>
|
||||
*
|
||||
* <p>This method <b>does not</b> resolve inheritance rules.</p>
|
||||
*
|
||||
* @return a list of the holders own nodes.
|
||||
* @return a collection of the holders own nodes.
|
||||
*/
|
||||
@NonNull Collection<Node> getNodes();
|
||||
default @NonNull Collection<Node> getNodes() {
|
||||
/* This default method is overridden in the implementation, and is just here
|
||||
to demonstrate what this method does in the API sources. */
|
||||
List<Node> nodes = new ArrayList<>();
|
||||
nodes.addAll(data().toCollection());
|
||||
nodes.addAll(transientData().toCollection());
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a sorted set of all held nodes.
|
||||
* Gets a flattened view of the holders own {@link Node}s of the given {@code type}.
|
||||
*
|
||||
* @param type the type of node to filter by
|
||||
* @param <T> the node type
|
||||
* @return a filtered collection of the holders own nodes
|
||||
* @see #getNodes()
|
||||
* @since 5.1
|
||||
*/
|
||||
default <T extends Node> @NonNull Collection<T> getNodes(@NonNull NodeType<T> type) {
|
||||
/* This default method is overridden in the implementation, and is just here
|
||||
to demonstrate what this method does in the API sources. */
|
||||
return getNodes().stream()
|
||||
.filter(type::matches)
|
||||
.map(type::cast)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a flattened and sorted view of the holders own distinct {@link Node}s.
|
||||
*
|
||||
* <p>Effectively a sorted version of {@link #getNodes()}, without duplicates. Use the
|
||||
* aforementioned method if you don't require either of these attributes.</p>
|
||||
*
|
||||
* <p>This method <b>does not</b> resolve inheritance rules.</p>
|
||||
*
|
||||
* @return an immutable set of permissions in priority order
|
||||
* @return a sorted set of the holders own distinct nodes
|
||||
*/
|
||||
@NonNull SortedSet<Node> getDistinctNodes();
|
||||
|
||||
/**
|
||||
* Recursively resolves this holders permissions.
|
||||
* Gets a resolved view of the holders own and inherited {@link Node}s.
|
||||
*
|
||||
* <p>The returned list will contain every inherited
|
||||
* node the holder has, in the order that they were inherited in.</p>
|
||||
@@ -189,22 +238,66 @@ public interface PermissionHolder {
|
||||
* with the entries from the end of the inheritance tree appearing last.</p>
|
||||
*
|
||||
* @param queryOptions the query options
|
||||
* @return a list of nodes
|
||||
* @return a list of the holders inherited nodes
|
||||
*/
|
||||
@NonNull Collection<Node> resolveInheritedNodes(@NonNull QueryOptions queryOptions);
|
||||
|
||||
/**
|
||||
* Gets a mutable sorted set of the nodes that this object has and inherits, filtered by context
|
||||
* Gets a resolved view of the holders own and inherited {@link Node}s of a given {@code type}.
|
||||
*
|
||||
* <p>Nodes are sorted into priority order. The order of inheritance is only important during
|
||||
* the process of flattening inherited entries.</p>
|
||||
* @param type the type of node to filter by
|
||||
* @param queryOptions the query options
|
||||
* @param <T> the node type
|
||||
* @return a filtered list of the holders inherited nodes
|
||||
* @see #resolveInheritedNodes(QueryOptions)
|
||||
* @since 5.1
|
||||
*/
|
||||
default <T extends Node> @NonNull Collection<T> resolveInheritedNodes(@NonNull NodeType<T> type, @NonNull QueryOptions queryOptions) {
|
||||
/* This default method is overridden in the implementation, and is just here
|
||||
to demonstrate what this method does in the API sources. */
|
||||
return resolveInheritedNodes(queryOptions).stream()
|
||||
.filter(type::matches)
|
||||
.map(type::cast)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a resolved and sorted view of the holders own and inherited distinct {@link Node}s.
|
||||
*
|
||||
* <p>Effectively a sorted version of {@link #resolveInheritedNodes(QueryOptions)},
|
||||
* without duplicates. Use the aforementioned method if you don't require either of these
|
||||
* attributes.</p>
|
||||
*
|
||||
* <p>Inheritance is performed according to the platforms rules, and the order will vary
|
||||
* depending on the accumulation order. By default, the holders own nodes are first in the list,
|
||||
* with the entries from the end of the inheritance tree appearing last.</p>
|
||||
*
|
||||
* @param queryOptions the query options
|
||||
* @return an immutable sorted set of permissions
|
||||
* @throws NullPointerException if the context is null
|
||||
* @return a sorted set of the holders distinct inherited nodes
|
||||
*/
|
||||
@NonNull SortedSet<Node> resolveDistinctInheritedNodes(@NonNull QueryOptions queryOptions);
|
||||
|
||||
/**
|
||||
* Gets a collection of the {@link Group}s this holder inherits nodes from.
|
||||
*
|
||||
* <p>If {@link 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".</p>
|
||||
*
|
||||
* <p>If {@link Flag#RESOLVE_INHERITANCE} is not set, then the traversal will only go one
|
||||
* level up the inheritance tree, and return only directly inherited groups.</p>
|
||||
*
|
||||
* <p>The collection will be ordered according to the platforms inheritance rules. The groups
|
||||
* which are inherited from first will appear earlier in the list.</p>
|
||||
*
|
||||
* <p>The list will not contain the holder.</p>
|
||||
*
|
||||
* @param queryOptions the query options
|
||||
* @return a collection of the groups the holder inherits from
|
||||
* @since 5.1
|
||||
*/
|
||||
@NonNull Collection<Group> getInheritedGroups(@NonNull QueryOptions queryOptions);
|
||||
|
||||
/**
|
||||
* Removes any temporary permissions that have expired.
|
||||
*
|
||||
|
||||
@@ -26,11 +26,15 @@
|
||||
package net.luckperms.api.model.group;
|
||||
|
||||
import net.luckperms.api.node.HeldNode;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.matcher.NodeMatcher;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -98,6 +102,27 @@ public interface GroupManager {
|
||||
*/
|
||||
@NonNull CompletableFuture<Void> deleteGroup(@NonNull Group group);
|
||||
|
||||
/**
|
||||
* Loads (or creates) a group from the plugin's storage provider, applies the given
|
||||
* {@code action}, then saves the group's data back to storage.
|
||||
*
|
||||
* <p>This method effectively calls {@link #createAndLoadGroup(String)}, followed by the
|
||||
* {@code action}, then {@link #saveGroup(Group)}, and returns an encapsulation of the whole
|
||||
* process as a {@link CompletableFuture}. </p>
|
||||
*
|
||||
* @param name the name of the group
|
||||
* @param action the action to apply to the group
|
||||
* @return a future to encapsulate the operation
|
||||
* @since 5.1
|
||||
*/
|
||||
default @NonNull CompletableFuture<Void> modifyGroup(@NonNull String name, @NonNull Consumer<? super Group> action) {
|
||||
/* This default method is overridden in the implementation, and is just here
|
||||
to demonstrate what this method does in the API sources. */
|
||||
return createAndLoadGroup(name)
|
||||
.thenApplyAsync(group -> { action.accept(group); return group; })
|
||||
.thenCompose(this::saveGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all groups into memory.
|
||||
*
|
||||
@@ -105,13 +130,25 @@ public interface GroupManager {
|
||||
*/
|
||||
@NonNull CompletableFuture<Void> loadAllGroups();
|
||||
|
||||
/**
|
||||
* Searches the {@link Group#data() normal node maps} of all known {@link Group}s for {@link Node}
|
||||
* entries matching the given {@link NodeMatcher matcher}.
|
||||
*
|
||||
* @param matcher the matcher
|
||||
* @return the entries which matched
|
||||
* @since 5.1
|
||||
*/
|
||||
@NonNull <T extends Node> CompletableFuture<Map<String, Collection<T>>> searchAll(@NonNull NodeMatcher<? extends T> matcher);
|
||||
|
||||
/**
|
||||
* Searches for a list of groups with a given permission.
|
||||
*
|
||||
* @param permission the permission to search for
|
||||
* @return a list of held permissions, or null if the operation failed
|
||||
* @throws NullPointerException if the permission is null
|
||||
* @deprecated use {@link #searchAll(NodeMatcher)}
|
||||
*/
|
||||
@Deprecated
|
||||
@NonNull CompletableFuture<List<HeldNode<String>>> getWithPermission(@NonNull String permission);
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,11 +27,15 @@ package net.luckperms.api.model.user;
|
||||
|
||||
import net.luckperms.api.model.PlayerSaveResult;
|
||||
import net.luckperms.api.node.HeldNode;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.matcher.NodeMatcher;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -59,7 +63,7 @@ public interface UserManager {
|
||||
/**
|
||||
* Loads a user from the plugin's storage provider into memory.
|
||||
*
|
||||
* @param uniqueId the uuid of the user
|
||||
* @param uniqueId the uuid of the user
|
||||
* @param username the username, if known
|
||||
* @return the resultant user
|
||||
* @throws NullPointerException if the uuid is null
|
||||
@@ -111,6 +115,27 @@ public interface UserManager {
|
||||
*/
|
||||
@NonNull CompletableFuture<Void> saveUser(@NonNull User user);
|
||||
|
||||
/**
|
||||
* Loads a user from the plugin's storage provider, applies the given {@code action},
|
||||
* then saves the user's data back to storage.
|
||||
*
|
||||
* <p>This method effectively calls {@link #loadUser(UUID)}, followed by the {@code action},
|
||||
* then {@link #saveUser(User)}, and returns an encapsulation of the whole process as a
|
||||
* {@link CompletableFuture}. </p>
|
||||
*
|
||||
* @param uniqueId the uuid of the user
|
||||
* @param action the action to apply to the user
|
||||
* @return a future to encapsulate the operation
|
||||
* @since 5.1
|
||||
*/
|
||||
default @NonNull CompletableFuture<Void> modifyUser(@NonNull UUID uniqueId, @NonNull Consumer<? super User> action) {
|
||||
/* This default method is overridden in the implementation, and is just here
|
||||
to demonstrate what this method does in the API sources. */
|
||||
return loadUser(uniqueId)
|
||||
.thenApplyAsync(user -> { action.accept(user); return user; })
|
||||
.thenCompose(this::saveUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves data about a player to the uuid caching system.
|
||||
*
|
||||
@@ -122,6 +147,17 @@ public interface UserManager {
|
||||
*/
|
||||
@NonNull CompletableFuture<PlayerSaveResult> savePlayerData(@NonNull UUID uniqueId, @NonNull String username);
|
||||
|
||||
/**
|
||||
* Deletes any data about a given player from the uuid caching system.
|
||||
*
|
||||
* <p>Note that this method does not affect any saved user/permissions data.</p>
|
||||
*
|
||||
* @param uniqueId the users mojang unique id
|
||||
* @return a future encapsulating the result of the operation
|
||||
* @since 5.2
|
||||
*/
|
||||
@NonNull CompletableFuture<Void> deletePlayerData(@NonNull UUID uniqueId);
|
||||
|
||||
/**
|
||||
* Gets a set all "unique" user UUIDs.
|
||||
*
|
||||
@@ -131,13 +167,25 @@ public interface UserManager {
|
||||
*/
|
||||
@NonNull CompletableFuture<Set<UUID>> getUniqueUsers();
|
||||
|
||||
/**
|
||||
* Searches the {@link User#data() normal node maps} of all known {@link User}s for {@link Node}
|
||||
* entries matching the given {@link NodeMatcher matcher}.
|
||||
*
|
||||
* @param matcher the matcher
|
||||
* @return the entries which matched
|
||||
* @since 5.1
|
||||
*/
|
||||
@NonNull <T extends Node> CompletableFuture<Map<UUID, Collection<T>>> searchAll(@NonNull NodeMatcher<? extends T> matcher);
|
||||
|
||||
/**
|
||||
* Searches for a list of users with a given permission.
|
||||
*
|
||||
* @param permission the permission to search for
|
||||
* @return a list of held permissions
|
||||
* @throws NullPointerException if the permission is null
|
||||
* @deprecated use {@link #searchAll(NodeMatcher)}
|
||||
*/
|
||||
@Deprecated
|
||||
@NonNull CompletableFuture<List<HeldNode<UUID>>> getWithPermission(@NonNull String permission);
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.luckperms.api.node;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
/**
|
||||
* Dummy implementation of {@link NodeEqualityPredicate}, used for the given constant
|
||||
* implementations.
|
||||
*
|
||||
* <p>The implementation rule of not calling {@link Node#equals(Node, NodeEqualityPredicate)} is
|
||||
* intentionally disregarded by this dummy implementation. The equals method has a special case for
|
||||
* the dummy instances, preventing a stack overflow.</p>
|
||||
*/
|
||||
final class DummyNodeEqualityPredicate implements NodeEqualityPredicate {
|
||||
private final String name;
|
||||
|
||||
DummyNodeEqualityPredicate(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areEqual(@NonNull Node o1, @NonNull Node o2) {
|
||||
return o1.equals(o2, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NodeEqualityPredicate#" + this.name;
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
*
|
||||
* @param <T> the identifier type of the holder
|
||||
*/
|
||||
@Deprecated
|
||||
public interface HeldNode<T> {
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,7 @@ import net.luckperms.api.node.types.WeightNode;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
@@ -63,15 +64,24 @@ import java.util.stream.Stream;
|
||||
* node, as well as methods to query and extract additional state and properties
|
||||
* from these settings.</p>
|
||||
*
|
||||
* <p>Nodes have the following attributes:</p>
|
||||
* <p>Nodes have the following 4 key attributes:</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link #getKey() key} - the key of the node</li>
|
||||
* <li>{@link #getValue() value} - the value of the node (false for negated)</li>
|
||||
* <li>{@link #getContexts() context} - the contexts required for this node to apply </li>
|
||||
* <li>{@link #getContexts() context} - the contexts required for this node to apply</li>
|
||||
* <li>{@link #getExpiry() expiry} - the time when this node should expire</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>These are the key attributes which are considered when evaluating node
|
||||
* {@link #equals(Object) equality}.</p>
|
||||
*
|
||||
* <p>Nodes can also optionally have {@link #metadata(NodeMetadataKey) metadata} attached to them,
|
||||
* added during construction using {@link NodeBuilder#withMetadata(NodeMetadataKey, Object)}, and
|
||||
* queried using {@link #metadata(NodeMetadataKey)} and {@link #getMetadata(NodeMetadataKey)}.
|
||||
* Such metadata is never considered when evaluating {@link #equals(Object)} or
|
||||
* {@link #equals(Node, NodeEqualityPredicate)} (any form of equality check).</p>
|
||||
*
|
||||
* <p>There are a number of node types, all of which extend from this class:</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
@@ -95,7 +105,7 @@ public interface Node {
|
||||
* @param key the key
|
||||
* @return the node builder
|
||||
*/
|
||||
static @NonNull NodeBuilder builder(@NonNull String key) {
|
||||
static @NonNull NodeBuilder<?, ?> builder(@NonNull String key) {
|
||||
return LuckPermsProvider.get().getNodeBuilderRegistry().forKey(key);
|
||||
}
|
||||
|
||||
@@ -153,8 +163,8 @@ public interface Node {
|
||||
/**
|
||||
* Gets the time when this node will expire.
|
||||
*
|
||||
* @return the {@link Instant} when this node will expire, or null if it
|
||||
* doesn't have an expiry time
|
||||
* @return the {@link Instant} when this node will expire, or
|
||||
* {@code null} if it doesn't have an expiry time
|
||||
*/
|
||||
@Nullable Instant getExpiry();
|
||||
|
||||
@@ -167,6 +177,17 @@ public interface Node {
|
||||
*/
|
||||
boolean hasExpired();
|
||||
|
||||
/**
|
||||
* Gets the time until this node will expire.
|
||||
*
|
||||
* <p>Returns {@code null} if the node doesn't have an expiry time,
|
||||
* and a {@link Duration#isNegative() negative} duration if it has already expired.</p>
|
||||
*
|
||||
* @return the duration until the nodes expiry
|
||||
* @since 5.1
|
||||
*/
|
||||
@Nullable Duration getExpiryDuration();
|
||||
|
||||
/**
|
||||
* Gets the contexts required for this node to apply.
|
||||
*
|
||||
|
||||
@@ -31,7 +31,9 @@ import net.luckperms.api.node.metadata.NodeMetadataKey;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAmount;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -85,7 +87,20 @@ public interface NodeBuilder<N extends ScopedNode<N, B>, B extends NodeBuilder<N
|
||||
/**
|
||||
* Sets the time when the node should expire.
|
||||
*
|
||||
* <p>The expiry timestamp is calculated relative to the current
|
||||
* <p>The expiry time is calculated relative to the current
|
||||
* system time.</p>
|
||||
*
|
||||
* @param duration how long the node should be added for
|
||||
* @return the builder
|
||||
* @see Node#getExpiry()
|
||||
* @since 5.1
|
||||
*/
|
||||
@NonNull B expiry(@Nullable TemporalAmount duration);
|
||||
|
||||
/**
|
||||
* Sets the time when the node should expire.
|
||||
*
|
||||
* <p>The expiry time is calculated relative to the current
|
||||
* system time.</p>
|
||||
*
|
||||
* @param duration how long the node should be added for
|
||||
@@ -97,8 +112,7 @@ public interface NodeBuilder<N extends ScopedNode<N, B>, B extends NodeBuilder<N
|
||||
throw new IllegalArgumentException("duration must be positive");
|
||||
}
|
||||
long seconds = Objects.requireNonNull(unit, "unit").toSeconds(duration);
|
||||
long timeNow = System.currentTimeMillis() / 1000L;
|
||||
return expiry(timeNow + seconds);
|
||||
return expiry(Duration.ofSeconds(seconds));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,64 +45,91 @@ public interface NodeBuilderRegistry {
|
||||
/**
|
||||
* Gets a {@link NodeBuilder} applicable for the given key.
|
||||
*
|
||||
* <p>Prefer using the {@link Node#builder(String)} accessor.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return the node builder
|
||||
* @see Node#builder(String)
|
||||
*/
|
||||
@NonNull NodeBuilder<?, ?> forKey(String key);
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeBuilder} for {@link PermissionNode}s.
|
||||
*
|
||||
* <p>Prefer using the {@link PermissionNode#builder()} accessor.</p>
|
||||
*
|
||||
* @return the node builder
|
||||
* @see PermissionNode#builder()
|
||||
*/
|
||||
PermissionNode.@NonNull Builder forPermission();
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeBuilder} for {@link RegexPermissionNode}s.
|
||||
*
|
||||
* <p>Prefer using the {@link RegexPermissionNode#builder()} accessor.</p>
|
||||
*
|
||||
* @return the node builder
|
||||
* @see RegexPermissionNode#builder()
|
||||
*/
|
||||
RegexPermissionNode.@NonNull Builder forRegexPermission();
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeBuilder} for {@link InheritanceNode}s.
|
||||
*
|
||||
* <p>Prefer using the {@link InheritanceNode#builder()} accessor.</p>
|
||||
*
|
||||
* @return the node builder
|
||||
* @see InheritanceNode#builder()
|
||||
*/
|
||||
InheritanceNode.@NonNull Builder forInheritance();
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeBuilder} for {@link PrefixNode}s.
|
||||
*
|
||||
* <p>Prefer using the {@link PrefixNode#builder()} accessor.</p>
|
||||
*
|
||||
* @return the node builder
|
||||
* @see PrefixNode#builder()
|
||||
*/
|
||||
PrefixNode.@NonNull Builder forPrefix();
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeBuilder} for {@link SuffixNode}s.
|
||||
*
|
||||
* <p>Prefer using the {@link SuffixNode#builder()} accessor.</p>
|
||||
*
|
||||
* @return the node builder
|
||||
* @see SuffixNode#builder()
|
||||
*/
|
||||
SuffixNode.@NonNull Builder forSuffix();
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeBuilder} for {@link MetaNode}s.
|
||||
*
|
||||
* <p>Prefer using the {@link MetaNode#builder()} accessor.</p>
|
||||
*
|
||||
* @return the node builder
|
||||
* @see MetaNode#builder()
|
||||
*/
|
||||
MetaNode.@NonNull Builder forMeta();
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeBuilder} for {@link WeightNode}s.
|
||||
*
|
||||
* <p>Prefer using the {@link WeightNode#builder()} accessor.</p>
|
||||
*
|
||||
* @return the node builder
|
||||
* @see WeightNode#builder()
|
||||
*/
|
||||
WeightNode.@NonNull Builder forWeight();
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeBuilder} for {@link DisplayNameNode}s.
|
||||
*
|
||||
* <p>Prefer using the {@link DisplayNameNode#builder()} accessor.</p>
|
||||
*
|
||||
* @return the node builder
|
||||
* @see DisplayNameNode#builder()
|
||||
*/
|
||||
DisplayNameNode.@NonNull Builder forDisplayName();
|
||||
|
||||
|
||||
@@ -30,7 +30,18 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* A rule for determining if two nodes are equal.
|
||||
* An equality test for determining if two nodes are to be considered equal.
|
||||
*
|
||||
* <p>Recall that {@link Node}s have 4 key attributes: key, value, context, expiry.</p>
|
||||
*
|
||||
* <p>In the default {@link Node#equals(Object)} implementation (equivalent to {@link #EXACT}),
|
||||
* all 4 of these key attributes are considered. However, there are occasions where such strict
|
||||
* equality checking is not desired, hence the use of this class.</p>
|
||||
*
|
||||
* <p>{@link NodeEqualityPredicate}s can either be used inline, by directly calling the
|
||||
* {@link #areEqual(Node, Node)} method, or can be passed as a parameter to the
|
||||
* {@link Node#equals(Node, NodeEqualityPredicate)} method. Either approach is valid, and both will
|
||||
* result in the same result.</p>
|
||||
*
|
||||
* <p>Generally, implementations of this interface should fulfil the same
|
||||
* requirements as the {@link Object#equals(Object)} contract.</p>
|
||||
@@ -61,60 +72,88 @@ public interface NodeEqualityPredicate {
|
||||
return other -> areEqual(node, other);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Some 'default' implementations of NodeEqualityPredicate are provided below.
|
||||
*
|
||||
* These are implemented in the common code, by a special case in the
|
||||
* implementation of Node#equals. As noted above, this should generally be
|
||||
* avoided.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents an exact match.
|
||||
*
|
||||
* <p>All attributes of the nodes must match for them to be considered
|
||||
* equal.</p>
|
||||
*/
|
||||
NodeEqualityPredicate EXACT = new NodeEqualityPredicate() {
|
||||
@Override public boolean areEqual(@NonNull Node o1, @NonNull Node o2) { return o1.equals(o2, this); }
|
||||
};
|
||||
|
||||
/**
|
||||
* All attributes must match, except for
|
||||
* {@link Node#getValue() value}, which is ignored.
|
||||
*/
|
||||
NodeEqualityPredicate IGNORE_VALUE = new NodeEqualityPredicate() {
|
||||
@Override public boolean areEqual(@NonNull Node o1, @NonNull Node o2) { return o1.equals(o2, this); }
|
||||
};
|
||||
|
||||
/**
|
||||
* All attributes must match, except for the
|
||||
* {@link Node#getExpiry() expiry time}, which is ignored.
|
||||
* <p>Returns true if: (and)</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link Node#getKey() key} = key</li>
|
||||
* <li>{@link Node#getValue() value} = value</li>
|
||||
* <li>{@link Node#getContexts() context} = context</li>
|
||||
* <li>{@link Node#getExpiry() expiry} = expiry</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note that with this setting, whether a node is temporary or not is
|
||||
* still considered.</p>
|
||||
* <p>All 4 attributes of the nodes must match to be considered equal.</p>
|
||||
*
|
||||
* <p>This is the default form of equality, used by {@link Node#equals(Object)}.</p>
|
||||
*/
|
||||
NodeEqualityPredicate IGNORE_EXPIRY_TIME = new NodeEqualityPredicate() {
|
||||
@Override public boolean areEqual(@NonNull Node o1, @NonNull Node o2) { return o1.equals(o2, this); }
|
||||
};
|
||||
NodeEqualityPredicate EXACT = new DummyNodeEqualityPredicate("EXACT");
|
||||
|
||||
/**
|
||||
* All attributes must match, except for
|
||||
* {@link Node#getValue() value} and the
|
||||
* Only the {@link Node#getKey() key}s need match, all other attributes are ignored.
|
||||
*/
|
||||
NodeEqualityPredicate ONLY_KEY = new DummyNodeEqualityPredicate("ONLY_KEY");
|
||||
|
||||
/**
|
||||
* All attributes must match, except for {@link Node#getValue() value}, which is ignored.
|
||||
*
|
||||
* <p>Returns true if: (and)</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link Node#getKey() key} = key</li>
|
||||
* <li>{@link Node#getContexts() context} = context</li>
|
||||
* <li>{@link Node#getExpiry() expiry} = expiry</li>
|
||||
* </ul>
|
||||
*/
|
||||
NodeEqualityPredicate IGNORE_VALUE = new DummyNodeEqualityPredicate("IGNORE_VALUE");
|
||||
|
||||
/**
|
||||
* All attributes must match, except for the {@link Node#getExpiry() expiry time}, which is
|
||||
* ignored.
|
||||
*
|
||||
* <p>Note that with this setting, whether a node has an expiry or not is still considered.</p>
|
||||
*
|
||||
* <p>Returns true if: (and)</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link Node#getKey() key} = key</li>
|
||||
* <li>{@link Node#getValue() value} = value</li>
|
||||
* <li>{@link Node#getContexts() context} = context</li>
|
||||
* <li>{@link Node#hasExpiry() has expiry} = has expiry</li>
|
||||
* </ul>
|
||||
*/
|
||||
NodeEqualityPredicate IGNORE_EXPIRY_TIME = new DummyNodeEqualityPredicate("IGNORE_EXPIRY_TIME");
|
||||
|
||||
/**
|
||||
* All attributes must match, except for {@link Node#getValue() value} and the
|
||||
* {@link Node#getExpiry() expiry time}, which are ignored.
|
||||
*
|
||||
* <p>Note that with this setting, whether a node has an expiry or not is still considered.</p>
|
||||
*
|
||||
* <p>Returns true if: (and)</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link Node#getKey() key} = key</li>
|
||||
* <li>{@link Node#getContexts() context} = context</li>
|
||||
* <li>{@link Node#hasExpiry() has expiry} = has expiry</li>
|
||||
* </ul>
|
||||
*/
|
||||
NodeEqualityPredicate IGNORE_EXPIRY_TIME_AND_VALUE = new NodeEqualityPredicate() {
|
||||
@Override public boolean areEqual(@NonNull Node o1, @NonNull Node o2) { return o1.equals(o2, this); }
|
||||
};
|
||||
NodeEqualityPredicate IGNORE_EXPIRY_TIME_AND_VALUE = new DummyNodeEqualityPredicate("IGNORE_EXPIRY_TIME_AND_VALUE");
|
||||
|
||||
/**
|
||||
* All attributes must match, except for
|
||||
* {@link Node#getValue() value} and the if the node is
|
||||
* {@link Node#hasExpiry() temporary}, which are ignored.
|
||||
* All attributes must match, except for {@link Node#getValue() value} and the if the node
|
||||
* {@link Node#hasExpiry() has an expiry}, which are ignored.
|
||||
*
|
||||
* <p>Effectively only considers the key and the context.</p>
|
||||
*
|
||||
* <p>Returns true if: (and)</p>
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@link Node#getKey() key} = key</li>
|
||||
* <li>{@link Node#getContexts() context} = context</li>
|
||||
* </ul>
|
||||
*/
|
||||
NodeEqualityPredicate IGNORE_VALUE_OR_IF_TEMPORARY = new NodeEqualityPredicate() {
|
||||
@Override public boolean areEqual(@NonNull Node o1, @NonNull Node o2) { return o1.equals(o2, this); }
|
||||
};
|
||||
NodeEqualityPredicate IGNORE_VALUE_OR_IF_TEMPORARY = new DummyNodeEqualityPredicate("IGNORE_VALUE_OR_IF_TEMPORARY");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.luckperms.api.node.matcher;
|
||||
|
||||
import net.luckperms.api.LuckPermsProvider;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.NodeEqualityPredicate;
|
||||
import net.luckperms.api.node.NodeType;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* A predicate which matches certain {@link Node}s.
|
||||
*
|
||||
* @param <T> the node type matched
|
||||
* @since 5.1
|
||||
*/
|
||||
public interface NodeMatcher<T extends Node> extends Predicate<Node> {
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches nodes with the same {@link Node#getKey() key}.
|
||||
*
|
||||
* <p>The {@link String#equalsIgnoreCase(String)} method is used to test key equality.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return the matcher
|
||||
*/
|
||||
static @NonNull NodeMatcher<Node> key(@NonNull String key) {
|
||||
return LuckPermsProvider.get().getNodeMatcherFactory().key(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches nodes with the same {@link Node#getKey() key}.
|
||||
*
|
||||
* <p>The {@link String#equalsIgnoreCase(String)} method is used to test key equality.</p>
|
||||
*
|
||||
* @param node the node to use for the key
|
||||
* @param <T> the node type
|
||||
* @return the matcher
|
||||
*/
|
||||
static <T extends Node> @NonNull NodeMatcher<T> key(@NonNull T node) {
|
||||
return LuckPermsProvider.get().getNodeMatcherFactory().key(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches nodes with a {@link Node#getKey() key} starting
|
||||
* with the given string.
|
||||
*
|
||||
* @param startingWith the string to match
|
||||
* @return the matcher
|
||||
*/
|
||||
static @NonNull NodeMatcher<Node> keyStartsWith(@NonNull String startingWith) {
|
||||
return LuckPermsProvider.get().getNodeMatcherFactory().keyStartsWith(startingWith);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches nodes which are
|
||||
* {@link Node#equals(Node, NodeEqualityPredicate) equal to} the given {@code other} node
|
||||
* according to the {@link NodeEqualityPredicate}.
|
||||
*
|
||||
* @param other the other node to test against
|
||||
* @param equalityPredicate the equality predicate
|
||||
* @param <T> the node type
|
||||
* @return the matcher
|
||||
*/
|
||||
static <T extends Node> @NonNull NodeMatcher<T> equals(@NonNull T other, @NonNull NodeEqualityPredicate equalityPredicate) {
|
||||
return LuckPermsProvider.get().getNodeMatcherFactory().equals(other, equalityPredicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches {@link MetaNode}s with the same
|
||||
* {@link MetaNode#getMetaKey() meta key}.
|
||||
*
|
||||
* <p>The {@link String#equalsIgnoreCase(String)} method is used to test key equality.</p>
|
||||
*
|
||||
* @param metaKey the meta key
|
||||
* @return the matcher
|
||||
*/
|
||||
static @NonNull NodeMatcher<MetaNode> metaKey(@NonNull String metaKey) {
|
||||
return LuckPermsProvider.get().getNodeMatcherFactory().metaKey(metaKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches {@link MetaNode}s with the same
|
||||
* {@link MetaNode#getMetaKey() meta key}.
|
||||
*
|
||||
* <p>The {@link String#equalsIgnoreCase(String)} method is used to test key equality.</p>
|
||||
*
|
||||
* @param metaNode the meta node to use for the meta key
|
||||
* @return the matcher
|
||||
*/
|
||||
static @NonNull NodeMatcher<MetaNode> metaKey(@NonNull MetaNode metaNode) {
|
||||
return metaKey(metaNode.getMetaKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches {@link Node}s with the same
|
||||
* type as the given {@link NodeType}.
|
||||
*
|
||||
* <p>{@link NodeType#PERMISSION}, {@link NodeType#CHAT_META} and
|
||||
* {@link NodeType#META_OR_CHAT_META} are not supported by this method.</p>
|
||||
*
|
||||
* @param type the node type
|
||||
* @param <T> the node type
|
||||
* @return the matcher
|
||||
*/
|
||||
static <T extends Node> @NonNull NodeMatcher<T> type(NodeType<? extends T> type) {
|
||||
return LuckPermsProvider.get().getNodeMatcherFactory().type(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if the given {@link Node} matches.
|
||||
*
|
||||
* @param node the node to test
|
||||
* @return true if the node matched
|
||||
*/
|
||||
@Override
|
||||
boolean test(@NonNull Node node);
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.luckperms.api.node.matcher;
|
||||
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.NodeEqualityPredicate;
|
||||
import net.luckperms.api.node.NodeType;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
/**
|
||||
* A factory which creates {@link NodeMatcher}s.
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
public interface NodeMatcherFactory {
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches nodes with the same {@link Node#getKey() key}.
|
||||
*
|
||||
* <p>The {@link String#equalsIgnoreCase(String)} method is used to test key equality.</p>
|
||||
*
|
||||
* <p>Prefer using the {@link NodeMatcher#key(String)} accessor.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return the matcher
|
||||
*/
|
||||
@NonNull NodeMatcher<Node> key(@NonNull String key);
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches nodes with the same {@link Node#getKey() key}.
|
||||
*
|
||||
* <p>The {@link String#equalsIgnoreCase(String)} method is used to test key equality.</p>
|
||||
*
|
||||
* <p>Prefer using the {@link NodeMatcher#key(Node)} accessor.</p>
|
||||
*
|
||||
* @param node the node to use for the key
|
||||
* @param <T> the node type
|
||||
* @return the matcher
|
||||
*/
|
||||
<T extends Node> @NonNull NodeMatcher<T> key(@NonNull T node);
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches nodes with a {@link Node#getKey() key} starting
|
||||
* with the given string.
|
||||
*
|
||||
* <p>Prefer using the {@link NodeMatcher#keyStartsWith(String)} accessor.</p>
|
||||
*
|
||||
* @param startingWith the string to match
|
||||
* @return the matcher
|
||||
*/
|
||||
@NonNull NodeMatcher<Node> keyStartsWith(@NonNull String startingWith);
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches nodes which are
|
||||
* {@link Node#equals(Node, NodeEqualityPredicate) equal to} the given {@code other} node
|
||||
* according to the {@link NodeEqualityPredicate}.
|
||||
*
|
||||
* <p>Prefer using the {@link NodeMatcher#equals(Node, NodeEqualityPredicate)} accessor.</p>
|
||||
*
|
||||
* @param other the other node to test against
|
||||
* @param equalityPredicate the equality predicate
|
||||
* @param <T> the node type
|
||||
* @return the matcher
|
||||
*/
|
||||
@NonNull <T extends Node> NodeMatcher<T> equals(@NonNull T other, @NonNull NodeEqualityPredicate equalityPredicate);
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches {@link MetaNode}s with the same
|
||||
* {@link MetaNode#getMetaKey() meta key}.
|
||||
*
|
||||
* <p>The {@link String#equalsIgnoreCase(String)} method is used to test key equality.</p>
|
||||
*
|
||||
* <p>Prefer using the {@link NodeMatcher#metaKey(String)} accessor.</p>
|
||||
*
|
||||
* @param metaKey the meta key
|
||||
* @return the matcher
|
||||
*/
|
||||
@NonNull NodeMatcher<MetaNode> metaKey(@NonNull String metaKey);
|
||||
|
||||
/**
|
||||
* Gets a {@link NodeMatcher} which matches {@link Node}s with the same
|
||||
* type as the given {@link NodeType}.
|
||||
*
|
||||
* <p>{@link NodeType#PERMISSION}, {@link NodeType#CHAT_META} and
|
||||
* {@link NodeType#META_OR_CHAT_META} are not supported by this method.</p>
|
||||
*
|
||||
* <p>Prefer using the {@link NodeMatcher#type(NodeType)} accessor.</p>
|
||||
*
|
||||
* @param type the node type
|
||||
* @param <T> the node type
|
||||
* @return the matcher
|
||||
*/
|
||||
<T extends Node> @NonNull NodeMatcher<T> type(NodeType<? extends T> type);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.luckperms.api.platform;
|
||||
|
||||
import net.luckperms.api.cacheddata.CachedDataManager;
|
||||
import net.luckperms.api.cacheddata.CachedMetaData;
|
||||
import net.luckperms.api.cacheddata.CachedPermissionData;
|
||||
import net.luckperms.api.context.ContextManager;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.luckperms.api.model.user.UserManager;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A utility class for adapting platform Player instances to LuckPerms {@link User}s.
|
||||
*
|
||||
* <p>Note: this class will only work for online players.</p>
|
||||
*
|
||||
* <p>The "player type" parameter must be equal to the class or interface used by the
|
||||
* server platform to represent players.</p>
|
||||
*
|
||||
* <p>Specifically:</p>
|
||||
*
|
||||
* <p></p>
|
||||
* <ul>
|
||||
* <li>{@code org.bukkit.entity.Player}</li>
|
||||
* <li>{@code net.md_5.bungee.api.connection.ProxiedPlayer}</li>
|
||||
* <li>{@code org.spongepowered.api/entity.living.player.Player}</li>
|
||||
* <li>{@code cn.nukkit.Player}</li>
|
||||
* <li>{@code com.velocitypowered.api.proxy.Player}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <T> the player type
|
||||
* @since 5.1
|
||||
*/
|
||||
public interface PlayerAdapter<T> {
|
||||
|
||||
/**
|
||||
* Gets the {@link User} instance for the given {@code player}.
|
||||
*
|
||||
* @param player the player
|
||||
* @return the user
|
||||
* @see UserManager#getUser(UUID)
|
||||
*/
|
||||
@NonNull User getUser(@NonNull T player);
|
||||
|
||||
/**
|
||||
* Gets current {@link ImmutableContextSet active context} for the {@code player}.
|
||||
*
|
||||
* @param player the player
|
||||
* @return the active context for the player
|
||||
* @see ContextManager#getContext(Object)
|
||||
*/
|
||||
@NonNull ImmutableContextSet getContext(@NonNull T player);
|
||||
|
||||
/**
|
||||
* Gets current {@link QueryOptions active query options} for the {@code player}.
|
||||
*
|
||||
* @param player the player
|
||||
* @return the active query options for the player
|
||||
* @see ContextManager#getQueryOptions(Object)
|
||||
*/
|
||||
@NonNull QueryOptions getQueryOptions(@NonNull T player);
|
||||
|
||||
/**
|
||||
* Gets the current {@link CachedPermissionData} for the {@code player},
|
||||
* using their {@link #getQueryOptions(Object) active query options}.
|
||||
*
|
||||
* @param player the player
|
||||
* @return the cached permission data for the player
|
||||
* @see CachedDataManager#getPermissionData()
|
||||
*/
|
||||
default @NonNull CachedPermissionData getPermissionData(@NonNull T player) {
|
||||
return getUser(player).getCachedData().getPermissionData(getQueryOptions(player));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current {@link CachedMetaData} for the {@code player},
|
||||
* using their {@link #getQueryOptions(Object) active query options}.
|
||||
*
|
||||
* @param player the player
|
||||
* @return the cached meta data for the player
|
||||
* @see CachedDataManager#getMetaData()
|
||||
*/
|
||||
default @NonNull CachedMetaData getMetaData(@NonNull T player) {
|
||||
return getUser(player).getCachedData().getMetaData(getQueryOptions(player));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,9 @@ package net.luckperms.api.query;
|
||||
|
||||
/**
|
||||
* The flags which can be set for a query.
|
||||
*
|
||||
* <p>By default (in places like new instances of {@link QueryOptions.Builder} and
|
||||
* {@link QueryOptions#defaultContextualOptions()}), all {@link Flag}s are set to true.</p>
|
||||
*/
|
||||
public enum Flag {
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
package net.luckperms.api.query;
|
||||
|
||||
import net.luckperms.api.LuckPermsProvider;
|
||||
import net.luckperms.api.context.ContextSatisfyMode;
|
||||
import net.luckperms.api.context.ContextSet;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
|
||||
@@ -71,7 +72,7 @@ public interface QueryOptions {
|
||||
* @return the query options
|
||||
*/
|
||||
static @NonNull QueryOptions contextual(@NonNull ContextSet context) {
|
||||
return defaultContextualOptions().toBuilder().context(context).build();
|
||||
return builder(QueryMode.CONTEXTUAL).context(context).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,7 +95,7 @@ public interface QueryOptions {
|
||||
* @return the default non contextual query options
|
||||
*/
|
||||
static @NonNull QueryOptions nonContextual() {
|
||||
return DefaultQueryOptions.nonContextual();
|
||||
return LuckPermsProvider.get().getQueryOptionsRegistry().defaultNonContextualOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +108,7 @@ public interface QueryOptions {
|
||||
* @return the default contextual query options
|
||||
*/
|
||||
static @NonNull QueryOptions defaultContextualOptions() {
|
||||
return DefaultQueryOptions.contextual();
|
||||
return LuckPermsProvider.get().getQueryOptionsRegistry().defaultContextualOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,10 +167,29 @@ public interface QueryOptions {
|
||||
* Gets whether this {@link QueryOptions} satisfies the given required
|
||||
* {@link ContextSet context}.
|
||||
*
|
||||
* <p>{@link ContextSatisfyMode#AT_LEAST_ONE_VALUE_PER_KEY} is used if this {@link QueryOptions}
|
||||
* instance doesn't have the {@link ContextSatisfyMode#KEY option key} set.</p>
|
||||
*
|
||||
* @param contextSet the contexts
|
||||
* @return the result
|
||||
*/
|
||||
boolean satisfies(@NonNull ContextSet contextSet);
|
||||
default boolean satisfies(@NonNull ContextSet contextSet) {
|
||||
return satisfies(contextSet, ContextSatisfyMode.AT_LEAST_ONE_VALUE_PER_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this {@link QueryOptions} satisfies the given required
|
||||
* {@link ContextSet context}.
|
||||
*
|
||||
* <p>The {@code defaultContextSatisfyMode} parameter is used if this {@link QueryOptions}
|
||||
* instance doesn't have the {@link ContextSatisfyMode#KEY option key} set.</p>
|
||||
*
|
||||
* @param contextSet the contexts
|
||||
* @param defaultContextSatisfyMode the default context satisfy mode to use
|
||||
* @return the result
|
||||
* @since 5.2
|
||||
*/
|
||||
boolean satisfies(@NonNull ContextSet contextSet, @NonNull ContextSatisfyMode defaultContextSatisfyMode);
|
||||
|
||||
/**
|
||||
* Converts this {@link QueryOptions} to a mutable builder.
|
||||
@@ -208,6 +228,8 @@ public interface QueryOptions {
|
||||
/**
|
||||
* Sets the value of the given flag.
|
||||
*
|
||||
* <p>By default, all {@link Flag}s are set to true.</p>
|
||||
*
|
||||
* @param flag the flag
|
||||
* @param value the value to set
|
||||
* @return this builder
|
||||
@@ -220,6 +242,8 @@ public interface QueryOptions {
|
||||
* <p>Note that this is a set operation, not append. Existing flags will
|
||||
* be overridden.</p>
|
||||
*
|
||||
* <p>By default, all {@link Flag}s are set to true.</p>
|
||||
*
|
||||
* @param flags the flags
|
||||
* @return this builder
|
||||
*/
|
||||
|
||||
+19
-28
@@ -23,46 +23,37 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.metastacking;
|
||||
package net.luckperms.api.query;
|
||||
|
||||
import net.luckperms.api.metastacking.MetaStackElement;
|
||||
import net.luckperms.api.node.types.ChatMetaNode;
|
||||
|
||||
import java.util.Optional;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
/**
|
||||
* Represents a specific entry in a {@link MetaStack}.
|
||||
* An entry is basically a live/mutable version of a {@link MetaStackElement}.
|
||||
* A registry providing useful {@link QueryOptions} instances.
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
public interface MetaStackEntry {
|
||||
public interface QueryOptionsRegistry {
|
||||
|
||||
/**
|
||||
* Gets the stack this entry belongs to.
|
||||
* Gets the default {@link QueryMode#CONTEXTUAL contextual}
|
||||
* query options.
|
||||
*
|
||||
* @return the parent stack
|
||||
* <p>Prefer using the {@link QueryOptions#defaultContextualOptions()} accessor.</p>
|
||||
*
|
||||
* @return the default contextual query options
|
||||
* @see QueryOptions#defaultContextualOptions()
|
||||
*/
|
||||
MetaStack getParentStack();
|
||||
@NonNull QueryOptions defaultContextualOptions();
|
||||
|
||||
/**
|
||||
* Gets the element this entry was formed form
|
||||
* Gets the default {@link QueryMode#NON_CONTEXTUAL non contextual}
|
||||
* query options.
|
||||
*
|
||||
* @return the forming element
|
||||
*/
|
||||
MetaStackElement getElement();
|
||||
|
||||
/**
|
||||
* Gets the value currently held by this entry.
|
||||
* <p>Prefer using the {@link QueryOptions#nonContextual()} accessor.</p>
|
||||
*
|
||||
* @return the entry
|
||||
* @return the default non contextual query options
|
||||
* @see QueryOptions#nonContextual()
|
||||
*/
|
||||
Optional<ChatMetaNode<?, ?>> getCurrentValue();
|
||||
|
||||
/**
|
||||
* Accumulates a node to this entry
|
||||
*
|
||||
* @param node the node to accumulate
|
||||
* @return if the node was accepted
|
||||
*/
|
||||
boolean accumulateNode(ChatMetaNode<?, ?> node);
|
||||
@NonNull QueryOptions defaultNonContextualOptions();
|
||||
|
||||
}
|
||||
@@ -32,10 +32,12 @@ import java.util.Objects;
|
||||
final class SimpleOptionKey<T> implements OptionKey<T> {
|
||||
private final String name;
|
||||
private final Class<T> type;
|
||||
private final int hashCode;
|
||||
|
||||
SimpleOptionKey(String name, Class<T> type) {
|
||||
this.name = name.toLowerCase();
|
||||
this.type = type;
|
||||
this.hashCode = Objects.hash(this.name, this.type); // cache hashcode
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,6 +66,6 @@ final class SimpleOptionKey<T> implements OptionKey<T> {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.name, this.type);
|
||||
return this.hashCode;
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,8 @@ import java.util.function.Consumer;
|
||||
* it is possible that more {@link DataType}s may be added in the future.
|
||||
* Ideally the {@link Comparator} implementations should be able to handle these
|
||||
* smoothly.</p>
|
||||
*
|
||||
* @see DataQueryOrderFunction
|
||||
*/
|
||||
public enum DataQueryOrder implements Comparator<DataType> {
|
||||
|
||||
@@ -60,10 +62,7 @@ public enum DataQueryOrder implements Comparator<DataType> {
|
||||
if (o1 == o2) {
|
||||
return 0;
|
||||
}
|
||||
return Boolean.compare(
|
||||
o1 == DataType.TRANSIENT,
|
||||
o2 == DataType.TRANSIENT
|
||||
);
|
||||
return o1 == DataType.TRANSIENT ? 1 : -1;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -76,10 +75,7 @@ public enum DataQueryOrder implements Comparator<DataType> {
|
||||
if (o1 == o2) {
|
||||
return 0;
|
||||
}
|
||||
return -Boolean.compare(
|
||||
o1 == DataType.TRANSIENT,
|
||||
o2 == DataType.TRANSIENT
|
||||
);
|
||||
return o1 == DataType.TRANSIENT ? -1 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -44,6 +44,18 @@ public interface DataQueryOrderFunction {
|
||||
*/
|
||||
OptionKey<DataQueryOrderFunction> KEY = OptionKey.of("dataqueryorderfunction", DataQueryOrderFunction.class);
|
||||
|
||||
/**
|
||||
* Creates a {@link DataQueryOrderFunction} that always returns the given
|
||||
* {@code comparator}.
|
||||
*
|
||||
* @param comparator the comparator
|
||||
* @return the data query order function
|
||||
* @since 5.2
|
||||
*/
|
||||
static DataQueryOrderFunction always(Comparator<DataType> comparator) {
|
||||
return id -> comparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link DataQueryOrder} comparator for the given
|
||||
* {@link PermissionHolder.Identifier holder identifier}.
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.luckperms.api.query.dataorder;
|
||||
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Represents which different {@link DataType}s are used for a query.
|
||||
*
|
||||
* <p>The {@link DataTypeFilter} enum simply represents some default
|
||||
* implementations of the {@link Predicate} required by {@link QueryOptions}
|
||||
* and the {@link #values(Predicate)} method.</p>
|
||||
*
|
||||
* <p>Users are free to implement their own predicate. However, be aware that
|
||||
* it is possible that more {@link DataType}s may be added in the future.
|
||||
* Ideally the {@link Predicate} implementations should be able to handle these
|
||||
* smoothly.</p>
|
||||
*
|
||||
* @see DataTypeFilterFunction
|
||||
* @since 5.2
|
||||
*/
|
||||
public enum DataTypeFilter implements Predicate<DataType> {
|
||||
|
||||
/**
|
||||
* A data type filter indicating that all {@link DataType}s should be used.
|
||||
*/
|
||||
ALL {
|
||||
@Override
|
||||
public boolean test(DataType dataType) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A data type filter indicating that no {@link DataType}s should be used.
|
||||
*/
|
||||
NONE {
|
||||
@Override
|
||||
public boolean test(DataType dataType) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A data type filter indicating that only {@link DataType#NORMAL} should be used.
|
||||
*/
|
||||
NORMAL_ONLY {
|
||||
@Override
|
||||
public boolean test(DataType dataType) {
|
||||
return dataType == DataType.NORMAL;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A data type filter indicating that only {@link DataType#TRANSIENT} should be used.
|
||||
*/
|
||||
TRANSIENT_ONLY {
|
||||
@Override
|
||||
public boolean test(DataType dataType) {
|
||||
return dataType == DataType.TRANSIENT;
|
||||
}
|
||||
};
|
||||
|
||||
private static final List<DataType> ALL_LIST = Collections.unmodifiableList(Arrays.asList(DataType.NORMAL, DataType.TRANSIENT));
|
||||
private static final List<DataType> NORMAL_ONLY_LIST = Collections.unmodifiableList(Collections.singletonList(DataType.NORMAL));
|
||||
private static final List<DataType> TRANSIENT_ONLY_LIST = Collections.unmodifiableList(Collections.singletonList(DataType.TRANSIENT));
|
||||
|
||||
/**
|
||||
* Gets a {@link List} of all {@link DataType}s, filtered by the {@code predicate}.
|
||||
*
|
||||
* @param predicate the predicate to filter with
|
||||
* @return the list of data types
|
||||
*/
|
||||
public static @NonNull List<DataType> values(@NonNull Predicate<? super DataType> predicate) {
|
||||
boolean normal = predicate.test(DataType.NORMAL);
|
||||
boolean trans = predicate.test(DataType.TRANSIENT);
|
||||
|
||||
if (normal && trans) {
|
||||
return ALL_LIST;
|
||||
} else if (normal) {
|
||||
return NORMAL_ONLY_LIST;
|
||||
} else if (trans) {
|
||||
return TRANSIENT_ONLY_LIST;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+26
-27
@@ -23,48 +23,47 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.metastacking;
|
||||
package net.luckperms.api.query.dataorder;
|
||||
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
import net.luckperms.api.node.types.ChatMetaNode;
|
||||
import net.luckperms.api.model.PermissionHolder;
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
import net.luckperms.api.query.OptionKey;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* A live stack of {@link MetaStackEntry} instances, formed from a
|
||||
* {@link MetaStackDefinition}.
|
||||
* A function that generates a {@link DataTypeFilter} predicate for
|
||||
* {@link PermissionHolder}s as required during inheritance.
|
||||
*
|
||||
* This class is used to construct a formatted string, by accumulating
|
||||
* nodes to each element.
|
||||
* @since 5.2
|
||||
*/
|
||||
public interface MetaStack {
|
||||
public interface DataTypeFilterFunction {
|
||||
|
||||
/**
|
||||
* Gets the definition this stack is based upon
|
||||
*
|
||||
* @return the definition of the stack
|
||||
* The {@link OptionKey} for {@link DataTypeFilterFunction}.
|
||||
*/
|
||||
MetaStackDefinition getDefinition();
|
||||
OptionKey<DataTypeFilterFunction> KEY = OptionKey.of("datatypefilterfunction", DataTypeFilterFunction.class);
|
||||
|
||||
/**
|
||||
* Gets the target of this stack
|
||||
* Creates a {@link DataTypeFilterFunction} that always returns the given
|
||||
* {@code predicate}.
|
||||
*
|
||||
* @return the stack target
|
||||
* @param predicate the predicate
|
||||
* @return the data type filter function
|
||||
*/
|
||||
ChatMetaType getTargetType();
|
||||
static DataTypeFilterFunction always(Predicate<DataType> predicate) {
|
||||
return id -> predicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted string, as defined by the {@link MetaStackDefinition},
|
||||
* using the accumulated elements in the stack.
|
||||
* Gets the {@link DataTypeFilter} predicate for the given
|
||||
* {@link PermissionHolder.Identifier holder identifier}.
|
||||
*
|
||||
* @return the string output
|
||||
* @param holderIdentifier the holder identifier
|
||||
* @return the predicate to use
|
||||
*/
|
||||
String toFormattedString();
|
||||
|
||||
/**
|
||||
* Tries to accumulate the given node to all elements in the stack.
|
||||
*
|
||||
* @param node the node to accumulate
|
||||
*/
|
||||
void accumulateToAll(ChatMetaNode<?, ?> node);
|
||||
@NonNull Predicate<DataType> getTypeFilter(PermissionHolder.@NonNull Identifier holderIdentifier);
|
||||
|
||||
}
|
||||
+25
-30
@@ -23,42 +23,37 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.luckperms.api.query;
|
||||
package net.luckperms.api.query.meta;
|
||||
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
import net.luckperms.api.query.OptionKey;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Some default {@link QueryOptions} instances.
|
||||
* A function that selects the {@link MetaNode#getMetaValue() meta value} to be used in queries
|
||||
* against a given {@link MetaNode#getMetaKey() meta key}.
|
||||
*
|
||||
* @since 5.1
|
||||
*/
|
||||
final class DefaultQueryOptions {
|
||||
private DefaultQueryOptions() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
public interface MetaValueSelector {
|
||||
|
||||
private static boolean setup = false;
|
||||
private static final EnumSet<Flag> DEFAULT_FLAGS = EnumSet.allOf(Flag.class);
|
||||
private static QueryOptions contextual;
|
||||
private static QueryOptions nonContextual;
|
||||
/**
|
||||
* The {@link OptionKey} for {@link MetaValueSelector}.
|
||||
*/
|
||||
OptionKey<MetaValueSelector> KEY = OptionKey.of("metavalueselector", MetaValueSelector.class);
|
||||
|
||||
private static void setup() {
|
||||
if (setup) {
|
||||
return;
|
||||
}
|
||||
setup = true;
|
||||
contextual = QueryOptions.contextual(ImmutableContextSet.empty(), DEFAULT_FLAGS);
|
||||
nonContextual = QueryOptions.nonContextual(DEFAULT_FLAGS);
|
||||
}
|
||||
|
||||
static QueryOptions contextual() {
|
||||
setup();
|
||||
return contextual;
|
||||
}
|
||||
|
||||
static QueryOptions nonContextual() {
|
||||
setup();
|
||||
return nonContextual;
|
||||
}
|
||||
/**
|
||||
* Selects the meta value to map to the given key.
|
||||
*
|
||||
* <p>The {@code values} list is guaranteed to contain at least 1 element.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @param values the values, in the order in which they were accumulated.
|
||||
* @return the selected value
|
||||
*/
|
||||
@NonNull String selectValue(@NonNull String key, @NonNull List<String> values);
|
||||
|
||||
}
|
||||
+2
-2
@@ -16,7 +16,7 @@ subprojects {
|
||||
apply plugin: 'net.minecrell.licenser'
|
||||
|
||||
group = 'me.lucko.luckperms'
|
||||
version = '5.0-SNAPSHOT'
|
||||
version = '5.2-SNAPSHOT'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
@@ -45,7 +45,7 @@ subprojects {
|
||||
}
|
||||
|
||||
project.ext.majorVersion = '5'
|
||||
project.ext.minorVersion = '0'
|
||||
project.ext.minorVersion = '2'
|
||||
project.ext.patchVersion = determinePatchVersion()
|
||||
project.ext.apiVersion = project.ext.majorVersion + '.' + project.ext.minorVersion
|
||||
project.ext.fullVersion = project.ext.apiVersion + '.' + project.ext.patchVersion
|
||||
|
||||
+5
-4
@@ -3,16 +3,16 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
|
||||
maven { url 'https://papermc.io/repo/repository/maven-public/' }
|
||||
maven { url 'https://libraries.minecraft.net/' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':common')
|
||||
|
||||
compileOnly 'org.spigotmc:spigot-api:1.14-R0.1-SNAPSHOT'
|
||||
compileOnly 'net.kyori:text-adapter-bukkit:3.0.2'
|
||||
compileOnly 'me.lucko:commodore:1.3'
|
||||
compileOnly 'com.destroystokyo.paper:paper-api:1.15.2-R0.1-SNAPSHOT'
|
||||
compileOnly 'net.kyori:text-adapter-bukkit:3.0.5'
|
||||
compileOnly 'me.lucko:commodore:1.7'
|
||||
compileOnly('net.milkbowl.vault:VaultAPI:1.6') {
|
||||
exclude(module: 'bukkit')
|
||||
}
|
||||
@@ -55,6 +55,7 @@ shadowJar {
|
||||
relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine'
|
||||
relocate 'okio', 'me.lucko.luckperms.lib.okio'
|
||||
relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3'
|
||||
relocate 'net.bytebuddy', 'me.lucko.luckperms.lib.bytebuddy'
|
||||
relocate 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore'
|
||||
relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb'
|
||||
relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql'
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit;
|
||||
|
||||
import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent;
|
||||
|
||||
import me.lucko.luckperms.bukkit.util.CommandMapUtil;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentTokenizer;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.event.EventHandler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitAsyncCommandExecutor extends BukkitCommandExecutor {
|
||||
public BukkitAsyncCommandExecutor(LPBukkitPlugin plugin, PluginCommand command) {
|
||||
super(plugin, command);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onAsyncTabComplete(AsyncTabCompleteEvent e) {
|
||||
if (!e.isCommand()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String buffer = e.getBuffer();
|
||||
if (buffer.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer.charAt(0) == '/') {
|
||||
buffer = buffer.substring(1);
|
||||
}
|
||||
|
||||
int firstSpace = buffer.indexOf(' ');
|
||||
if (firstSpace < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
String commandLabel = buffer.substring(0, firstSpace);
|
||||
Command command = CommandMapUtil.getCommandMap(this.plugin.getBootstrap().getServer()).getCommand(commandLabel);
|
||||
if (command != this.command) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sender wrapped = this.plugin.getSenderFactory().wrap(e.getSender());
|
||||
List<String> arguments = ArgumentTokenizer.TAB_COMPLETE.tokenizeInput(buffer.substring(firstSpace + 1));
|
||||
List<String> completions = tabCompleteCommand(wrapped, arguments);
|
||||
|
||||
e.setCompletions(completions);
|
||||
e.setHandled(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,46 +25,144 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import me.lucko.luckperms.bukkit.util.CommandMapUtil;
|
||||
import me.lucko.luckperms.common.command.CommandManager;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentTokenizer;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.ServerCommandEvent;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BukkitCommandExecutor extends CommandManager implements CommandExecutor, TabExecutor {
|
||||
private static final Splitter TAB_COMPLETE_ARGUMENT_SPLITTER = Splitter.on(COMMAND_SEPARATOR_PATTERN);
|
||||
private static final Splitter ARGUMENT_SPLITTER = Splitter.on(COMMAND_SEPARATOR_PATTERN).omitEmptyStrings();
|
||||
private static final Joiner ARGUMENT_JOINER = Joiner.on(' ');
|
||||
public class BukkitCommandExecutor extends CommandManager implements CommandExecutor, TabExecutor, Listener {
|
||||
private static final boolean SELECT_ENTITIES_SUPPORTED;
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
static {
|
||||
boolean selectEntitiesSupported = false;
|
||||
try {
|
||||
Server.class.getMethod("selectEntities", CommandSender.class, String.class);
|
||||
selectEntitiesSupported = true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
// ignore
|
||||
}
|
||||
SELECT_ENTITIES_SUPPORTED = selectEntitiesSupported;
|
||||
}
|
||||
|
||||
public BukkitCommandExecutor(LPBukkitPlugin plugin) {
|
||||
protected final LPBukkitPlugin plugin;
|
||||
protected final PluginCommand command;
|
||||
|
||||
public BukkitCommandExecutor(LPBukkitPlugin plugin, PluginCommand command) {
|
||||
super(plugin);
|
||||
this.plugin = plugin;
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public void register() {
|
||||
this.command.setExecutor(this);
|
||||
this.command.setTabCompleter(this);
|
||||
this.plugin.getBootstrap().getServer().getPluginManager().registerEvents(this, this.plugin.getBootstrap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NonNull CommandSender sender, @NonNull Command command, @NonNull String label, @NonNull String[] args) {
|
||||
Sender lpSender = this.plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = stripQuotes(ARGUMENT_SPLITTER.splitToList(ARGUMENT_JOINER.join(args)));
|
||||
|
||||
onCommand(lpSender, label, arguments);
|
||||
Sender wrapped = this.plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = resolveSelectors(sender, ArgumentTokenizer.EXECUTE.tokenizeInput(args));
|
||||
executeCommand(wrapped, label, arguments);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(@NonNull CommandSender sender, @NonNull Command command, @NonNull String label, @NonNull String[] args) {
|
||||
Sender lpSender = this.plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = stripQuotes(TAB_COMPLETE_ARGUMENT_SPLITTER.splitToList(ARGUMENT_JOINER.join(args)));
|
||||
Sender wrapped = this.plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = resolveSelectors(sender, ArgumentTokenizer.TAB_COMPLETE.tokenizeInput(args));
|
||||
return tabCompleteCommand(wrapped, arguments);
|
||||
}
|
||||
|
||||
return onTabComplete(lpSender, arguments);
|
||||
// Support LP commands prefixed with a '/' from the console.
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onConsoleCommand(ServerCommandEvent e) {
|
||||
if (!(e.getSender() instanceof ConsoleCommandSender)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String buffer = e.getCommand();
|
||||
if (buffer.isEmpty() || buffer.charAt(0) != '/') {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = buffer.substring(1);
|
||||
|
||||
String commandLabel;
|
||||
int firstSpace = buffer.indexOf(' ');
|
||||
if (firstSpace == -1) {
|
||||
commandLabel = buffer;
|
||||
} else {
|
||||
commandLabel = buffer.substring(0, firstSpace);
|
||||
}
|
||||
|
||||
Command command = CommandMapUtil.getCommandMap(this.plugin.getBootstrap().getServer()).getCommand(commandLabel);
|
||||
if (command != this.command) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.setCommand(buffer);
|
||||
}
|
||||
|
||||
private List<String> resolveSelectors(CommandSender sender, List<String> args) {
|
||||
if (!SELECT_ENTITIES_SUPPORTED) {
|
||||
return args;
|
||||
}
|
||||
|
||||
if (!this.plugin.getConfiguration().get(ConfigKeys.RESOLVE_COMMAND_SELECTORS)) {
|
||||
return args;
|
||||
}
|
||||
|
||||
for (ListIterator<String> it = args.listIterator(); it.hasNext(); ) {
|
||||
String arg = it.next();
|
||||
if (arg.isEmpty() || arg.charAt(0) != '@') {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Player> matchedPlayers;
|
||||
try {
|
||||
matchedPlayers = this.plugin.getBootstrap().getServer().selectEntities(sender, arg).stream()
|
||||
.filter(e -> e instanceof Player)
|
||||
.map(e -> ((Player) e))
|
||||
.collect(Collectors.toList());
|
||||
} catch (IllegalArgumentException e) {
|
||||
this.plugin.getLogger().warn("Error parsing selector '" + arg + "' for " + sender + " executing " + args);
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (matchedPlayers.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (matchedPlayers.size() > 1) {
|
||||
this.plugin.getLogger().warn("Error parsing selector '" + arg + "' for " + sender + " executing " + args +
|
||||
": ambiguous result (more than one player matched) - " + matchedPlayers);
|
||||
continue;
|
||||
}
|
||||
|
||||
Player player = matchedPlayers.get(0);
|
||||
it.set(player.getUniqueId().toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit;
|
||||
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.config.generic.adapter.ConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
@@ -71,8 +71,8 @@ public class BukkitConfigAdapter implements ConfigurationAdapter {
|
||||
|
||||
@Override
|
||||
public List<String> getStringList(String path, List<String> def) {
|
||||
List<String> ret = this.configuration.getStringList(path);
|
||||
return ret == null ? def : ret;
|
||||
List<String> list = this.configuration.getStringList(path);
|
||||
return list == null ? def : list;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit;
|
||||
|
||||
import me.lucko.luckperms.bukkit.compat.CraftBukkitUtil;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.sender.SenderFactory;
|
||||
import me.lucko.luckperms.common.util.TextUtils;
|
||||
@@ -42,9 +40,8 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitSenderFactory extends SenderFactory<CommandSender> {
|
||||
|
||||
public BukkitSenderFactory(LuckPermsPlugin plugin) {
|
||||
public class BukkitSenderFactory extends SenderFactory<LPBukkitPlugin, CommandSender> {
|
||||
public BukkitSenderFactory(LPBukkitPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@@ -78,20 +75,24 @@ public class BukkitSenderFactory extends SenderFactory<CommandSender> {
|
||||
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, Component message) {
|
||||
if (CraftBukkitUtil.isChatCompatible() && sender instanceof Player) {
|
||||
if (sender instanceof Player) {
|
||||
TextAdapter.sendComponent(sender, message);
|
||||
} else {
|
||||
// Fallback to legacy format
|
||||
sendMessage(sender, TextUtils.toLegacy(message));
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to legacy format
|
||||
sendMessage(sender, TextUtils.toLegacy(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Tristate getPermissionValue(CommandSender sender, String node) {
|
||||
boolean isSet = sender.isPermissionSet(node);
|
||||
boolean val = sender.hasPermission(node);
|
||||
|
||||
return !isSet ? val ? Tristate.TRUE : Tristate.UNDEFINED : Tristate.of(val);
|
||||
if (sender.hasPermission(node)) {
|
||||
return Tristate.TRUE;
|
||||
} else if (sender.isPermissionSet(node)) {
|
||||
return Tristate.FALSE;
|
||||
} else {
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -99,6 +100,11 @@ public class BukkitSenderFactory extends SenderFactory<CommandSender> {
|
||||
return sender.hasPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCommand(CommandSender sender, String command) {
|
||||
getPlugin().getBootstrap().getServer().dispatchCommand(sender, command);
|
||||
}
|
||||
|
||||
private static final class SyncMessengerAgent implements Runnable {
|
||||
private final CommandSender sender;
|
||||
private final String message;
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit;
|
||||
|
||||
import me.lucko.luckperms.bukkit.compat.NullSafeConsoleCommandSender;
|
||||
import me.lucko.luckperms.bukkit.util.NullSafeConsoleCommandSender;
|
||||
import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader;
|
||||
import me.lucko.luckperms.common.dependencies.classloader.ReflectionClassLoader;
|
||||
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
|
||||
@@ -39,13 +39,18 @@ import org.bukkit.Server;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Bootstrap plugin for LuckPerms running on Bukkit.
|
||||
@@ -81,12 +86,13 @@ public class LPBukkitBootstrap extends JavaPlugin implements LuckPermsBootstrap
|
||||
/**
|
||||
* The time when the plugin was enabled
|
||||
*/
|
||||
private long startTime;
|
||||
private Instant startTime;
|
||||
|
||||
// load/enable latches
|
||||
private final CountDownLatch loadLatch = new CountDownLatch(1);
|
||||
private final CountDownLatch enableLatch = new CountDownLatch(1);
|
||||
private boolean serverStarting = true;
|
||||
private boolean serverStopping = false;
|
||||
|
||||
// if the plugin has been loaded on an incompatible version
|
||||
private boolean incompatibleVersion = false;
|
||||
@@ -149,7 +155,9 @@ public class LPBukkitBootstrap extends JavaPlugin implements LuckPermsBootstrap
|
||||
return;
|
||||
}
|
||||
|
||||
this.startTime = System.currentTimeMillis();
|
||||
this.serverStarting = true;
|
||||
this.serverStopping = false;
|
||||
this.startTime = Instant.now();
|
||||
try {
|
||||
this.plugin.enable();
|
||||
|
||||
@@ -166,8 +174,8 @@ public class LPBukkitBootstrap extends JavaPlugin implements LuckPermsBootstrap
|
||||
return;
|
||||
}
|
||||
|
||||
this.serverStopping = true;
|
||||
this.plugin.disable();
|
||||
this.serverStarting = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,6 +192,10 @@ public class LPBukkitBootstrap extends JavaPlugin implements LuckPermsBootstrap
|
||||
return this.serverStarting;
|
||||
}
|
||||
|
||||
public boolean isServerStopping() {
|
||||
return this.serverStopping;
|
||||
}
|
||||
|
||||
// provide information about the plugin
|
||||
|
||||
@Override
|
||||
@@ -192,7 +204,7 @@ public class LPBukkitBootstrap extends JavaPlugin implements LuckPermsBootstrap
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartupTime() {
|
||||
public Instant getStartupTime() {
|
||||
return this.startTime;
|
||||
}
|
||||
|
||||
@@ -245,13 +257,23 @@ public class LPBukkitBootstrap extends JavaPlugin implements LuckPermsBootstrap
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> getPlayerList() {
|
||||
return getServer().getOnlinePlayers().stream().map(Player::getName);
|
||||
public Collection<String> getPlayerList() {
|
||||
Collection<? extends Player> players = getServer().getOnlinePlayers();
|
||||
List<String> list = new ArrayList<>(players.size());
|
||||
for (Player player : players) {
|
||||
list.add(player.getName());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<UUID> getOnlinePlayers() {
|
||||
return getServer().getOnlinePlayers().stream().map(Player::getUniqueId);
|
||||
public Collection<UUID> getOnlinePlayers() {
|
||||
Collection<? extends Player> players = getServer().getOnlinePlayers();
|
||||
List<UUID> list = new ArrayList<>(players.size());
|
||||
for (Player player : players) {
|
||||
list.add(player.getUniqueId());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -260,6 +282,19 @@ public class LPBukkitBootstrap extends JavaPlugin implements LuckPermsBootstrap
|
||||
return player != null && player.isOnline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String identifyClassLoader(ClassLoader classLoader) throws ReflectiveOperationException {
|
||||
Class<?> pluginClassLoaderClass = Class.forName("org.bukkit.plugin.java.PluginClassLoader");
|
||||
if (pluginClassLoaderClass.isInstance(classLoader)) {
|
||||
Method getPluginMethod = pluginClassLoaderClass.getDeclaredMethod("getPlugin");
|
||||
getPluginMethod.setAccessible(true);
|
||||
|
||||
JavaPlugin plugin = (JavaPlugin) getPluginMethod.invoke(classLoader);
|
||||
return plugin.getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean checkIncompatibleVersion() {
|
||||
try {
|
||||
Class.forName("com.google.gson.JsonElement");
|
||||
|
||||
@@ -25,29 +25,31 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit;
|
||||
|
||||
import me.lucko.luckperms.bukkit.brigadier.LuckPermsBrigadier;
|
||||
import me.lucko.luckperms.bukkit.calculator.BukkitCalculatorFactory;
|
||||
import me.lucko.luckperms.bukkit.compat.LuckPermsBrigadier;
|
||||
import me.lucko.luckperms.bukkit.context.BukkitContextManager;
|
||||
import me.lucko.luckperms.bukkit.context.WorldCalculator;
|
||||
import me.lucko.luckperms.bukkit.inject.permissible.LPPermissible;
|
||||
import me.lucko.luckperms.bukkit.inject.permissible.LuckPermsPermissible;
|
||||
import me.lucko.luckperms.bukkit.inject.permissible.PermissibleInjector;
|
||||
import me.lucko.luckperms.bukkit.inject.permissible.PermissibleMonitoringInjector;
|
||||
import me.lucko.luckperms.bukkit.inject.server.InjectorDefaultsMap;
|
||||
import me.lucko.luckperms.bukkit.inject.server.InjectorPermissionMap;
|
||||
import me.lucko.luckperms.bukkit.inject.server.InjectorSubscriptionMap;
|
||||
import me.lucko.luckperms.bukkit.inject.server.LPDefaultsMap;
|
||||
import me.lucko.luckperms.bukkit.inject.server.LPPermissionMap;
|
||||
import me.lucko.luckperms.bukkit.inject.server.LPSubscriptionMap;
|
||||
import me.lucko.luckperms.bukkit.inject.server.LuckPermsDefaultsMap;
|
||||
import me.lucko.luckperms.bukkit.inject.server.LuckPermsPermissionMap;
|
||||
import me.lucko.luckperms.bukkit.inject.server.LuckPermsSubscriptionMap;
|
||||
import me.lucko.luckperms.bukkit.listeners.BukkitAutoOpListener;
|
||||
import me.lucko.luckperms.bukkit.listeners.BukkitCommandListUpdater;
|
||||
import me.lucko.luckperms.bukkit.listeners.BukkitConnectionListener;
|
||||
import me.lucko.luckperms.bukkit.listeners.BukkitPlatformListener;
|
||||
import me.lucko.luckperms.bukkit.messaging.BukkitMessagingFactory;
|
||||
import me.lucko.luckperms.bukkit.util.PluginManagerUtil;
|
||||
import me.lucko.luckperms.bukkit.vault.VaultHookManager;
|
||||
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
|
||||
import me.lucko.luckperms.common.api.implementation.ApiUser;
|
||||
import me.lucko.luckperms.common.calculator.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.config.generic.adapter.ConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.dependencies.Dependency;
|
||||
import me.lucko.luckperms.common.event.AbstractEventBus;
|
||||
import me.lucko.luckperms.common.messaging.MessagingFactory;
|
||||
@@ -62,7 +64,6 @@ import me.lucko.luckperms.common.tasks.CacheHousekeepingTask;
|
||||
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
|
||||
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.event.user.UserDataRecalculateEvent;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import org.bukkit.OfflinePlayer;
|
||||
@@ -74,7 +75,8 @@ import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -93,9 +95,9 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
private StandardGroupManager groupManager;
|
||||
private StandardTrackManager trackManager;
|
||||
private BukkitContextManager contextManager;
|
||||
private LPSubscriptionMap subscriptionMap;
|
||||
private LPPermissionMap permissionMap;
|
||||
private LPDefaultsMap defaultPermissionMap;
|
||||
private LuckPermsSubscriptionMap subscriptionMap;
|
||||
private LuckPermsPermissionMap permissionMap;
|
||||
private LuckPermsDefaultsMap defaultPermissionMap;
|
||||
private VaultHookManager vaultHookManager = null;
|
||||
|
||||
public LPBukkitPlugin(LPBukkitBootstrap bootstrap) {
|
||||
@@ -112,15 +114,6 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
this.senderFactory = new BukkitSenderFactory(this);
|
||||
}
|
||||
|
||||
private static boolean isBrigadierSupported() {
|
||||
try {
|
||||
Class.forName("com.mojang.brigadier.CommandDispatcher");
|
||||
return true;
|
||||
} catch (ClassNotFoundException var1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<Dependency> getGlobalDependencies() {
|
||||
Set<Dependency> dependencies = super.getGlobalDependencies();
|
||||
@@ -150,15 +143,24 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
protected void registerCommands() {
|
||||
this.commandManager = new BukkitCommandExecutor(this);
|
||||
PluginCommand cmd = this.bootstrap.getCommand("luckperms");
|
||||
cmd.setExecutor(this.commandManager);
|
||||
cmd.setTabCompleter(this.commandManager);
|
||||
PluginCommand command = this.bootstrap.getCommand("luckperms");
|
||||
if (command == null) {
|
||||
getLogger().severe("Unable to register /luckperms command with the server");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAsyncTabCompleteSupported()) {
|
||||
this.commandManager = new BukkitAsyncCommandExecutor(this, command);
|
||||
} else {
|
||||
this.commandManager = new BukkitCommandExecutor(this, command);
|
||||
}
|
||||
|
||||
this.commandManager.register();
|
||||
|
||||
// setup brigadier
|
||||
if (isBrigadierSupported()) {
|
||||
if (isBrigadierSupported() && getConfiguration().get(ConfigKeys.REGISTER_COMMAND_LIST_DATA)) {
|
||||
try {
|
||||
LuckPermsBrigadier.register(this, cmd);
|
||||
LuckPermsBrigadier.register(this, command);
|
||||
} catch (Exception e) {
|
||||
if (!(e instanceof RuntimeException && e.getMessage().contains("not supported by the server"))) {
|
||||
e.printStackTrace();
|
||||
@@ -182,16 +184,19 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
@Override
|
||||
protected void setupContextManager() {
|
||||
this.contextManager = new BukkitContextManager(this);
|
||||
this.contextManager.registerCalculator(new WorldCalculator(this));
|
||||
|
||||
WorldCalculator worldCalculator = new WorldCalculator(this);
|
||||
this.bootstrap.getServer().getPluginManager().registerEvents(worldCalculator, this.bootstrap);
|
||||
this.contextManager.registerCalculator(worldCalculator);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupPlatformHooks() {
|
||||
// inject our own custom permission maps
|
||||
Runnable[] injectors = new Runnable[]{
|
||||
new InjectorSubscriptionMap(this),
|
||||
new InjectorPermissionMap(this),
|
||||
new InjectorDefaultsMap(this),
|
||||
new InjectorSubscriptionMap(this)::inject,
|
||||
new InjectorPermissionMap(this)::inject,
|
||||
new InjectorDefaultsMap(this)::inject,
|
||||
new PermissibleMonitoringInjector(this, PermissibleMonitoringInjector.Mode.INJECT)
|
||||
};
|
||||
|
||||
@@ -203,12 +208,26 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
this.bootstrap.getServer().getScheduler().runTaskLaterAsynchronously(this.bootstrap, injector, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is an unfortunate solution to a problem which shouldn't even exist. As of Spigot 1.15,
|
||||
* the way LP establishes it's load order relative to Vault triggers a dependency warning.
|
||||
* This is a workaround to prevent that from showing, since at the moment, there is nothing I
|
||||
* can reasonably do to improve this handling in LP without breaking plugins which use/obtain
|
||||
* Vault in their onEnable without depending on us.
|
||||
*
|
||||
* Noteworthy discussion here:
|
||||
* - https://github.com/lucko/LuckPerms/issues/1959
|
||||
* - https://hub.spigotmc.org/jira/browse/SPIGOT-5546
|
||||
* - https://github.com/PaperMC/Paper/pull/3509
|
||||
*/
|
||||
PluginManagerUtil.injectDependency(this.bootstrap.getServer().getPluginManager(), this.bootstrap.getName(), "Vault");
|
||||
|
||||
// Provide vault support
|
||||
tryVaultHook(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractEventBus provideEventBus(LuckPermsApiProvider apiProvider) {
|
||||
protected AbstractEventBus<?> provideEventBus(LuckPermsApiProvider apiProvider) {
|
||||
return new BukkitEventBus(this, apiProvider);
|
||||
}
|
||||
|
||||
@@ -266,11 +285,12 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
|
||||
// register autoop listener
|
||||
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
getApiProvider().getEventBus().subscribe(UserDataRecalculateEvent.class, event -> {
|
||||
User user = ApiUser.cast(event.getUser());
|
||||
Optional<Player> player = getBootstrap().getPlayer(user.getUniqueId());
|
||||
player.ifPresent(p -> refreshAutoOp(p, false));
|
||||
});
|
||||
getApiProvider().getEventBus().subscribe(new BukkitAutoOpListener(this));
|
||||
}
|
||||
|
||||
// register bukkit command list updater
|
||||
if (getConfiguration().get(ConfigKeys.UPDATE_CLIENT_COMMAND_LIST) && BukkitCommandListUpdater.isSupported()) {
|
||||
getApiProvider().getEventBus().subscribe(new BukkitCommandListUpdater(this));
|
||||
}
|
||||
|
||||
// Load any online users (in the case of a reload)
|
||||
@@ -281,7 +301,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
if (user != null) {
|
||||
this.bootstrap.getScheduler().executeSync(() -> {
|
||||
try {
|
||||
LPPermissible lpPermissible = new LPPermissible(player, user, this);
|
||||
LuckPermsPermissible lpPermissible = new LuckPermsPermissible(player, user, this);
|
||||
PermissibleInjector.inject(player, lpPermissible);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
@@ -317,9 +337,9 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
}
|
||||
|
||||
// uninject custom maps
|
||||
InjectorSubscriptionMap.uninject();
|
||||
InjectorPermissionMap.uninject();
|
||||
InjectorDefaultsMap.uninject();
|
||||
new InjectorSubscriptionMap(this).uninject();
|
||||
new InjectorPermissionMap(this).uninject();
|
||||
new InjectorDefaultsMap(this).uninject();
|
||||
new PermissibleMonitoringInjector(this, PermissibleMonitoringInjector.Mode.UNINJECT).run();
|
||||
|
||||
// unhook vault
|
||||
@@ -328,28 +348,6 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshAutoOp(Player player, boolean callerIsSync) {
|
||||
if (!getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
return;
|
||||
}
|
||||
|
||||
User user = getUserManager().getIfLoaded(player.getUniqueId());
|
||||
boolean value;
|
||||
|
||||
if (user != null) {
|
||||
Map<String, Boolean> permData = user.getCachedData().getPermissionData(this.contextManager.getQueryOptions(player)).getPermissionMap();
|
||||
value = permData.getOrDefault("luckperms.autoop", false);
|
||||
} else {
|
||||
value = false;
|
||||
}
|
||||
|
||||
if (callerIsSync) {
|
||||
player.setOp(value);
|
||||
} else {
|
||||
this.bootstrap.getScheduler().executeSync(() -> player.setOp(value));
|
||||
}
|
||||
}
|
||||
|
||||
private File resolveConfig() {
|
||||
File configFile = new File(this.bootstrap.getDataFolder(), "config.yml");
|
||||
if (!configFile.exists()) {
|
||||
@@ -359,6 +357,23 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
return configFile;
|
||||
}
|
||||
|
||||
private static boolean classExists(String className) {
|
||||
try {
|
||||
Class.forName(className);
|
||||
return true;
|
||||
} catch (ClassNotFoundException var1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isBrigadierSupported() {
|
||||
return classExists("com.mojang.brigadier.CommandDispatcher");
|
||||
}
|
||||
|
||||
private static boolean isAsyncTabCompleteSupported() {
|
||||
return classExists("com.destroystokyo.paper.event.server.AsyncTabCompleteEvent");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<QueryOptions> getQueryOptionsForUser(User user) {
|
||||
return this.bootstrap.getPlayer(user.getUniqueId()).map(player -> this.contextManager.getQueryOptions(player));
|
||||
@@ -366,9 +381,10 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
public Stream<Sender> getOnlineSenders() {
|
||||
List<Player> players = new ArrayList<>(this.bootstrap.getServer().getOnlinePlayers());
|
||||
return Stream.concat(
|
||||
Stream.of(getConsoleSender()),
|
||||
this.bootstrap.getServer().getOnlinePlayers().stream().map(p -> getSenderFactory().wrap(p))
|
||||
players.stream().map(p -> getSenderFactory().wrap(p))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -411,27 +427,27 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
return this.contextManager;
|
||||
}
|
||||
|
||||
public LPSubscriptionMap getSubscriptionMap() {
|
||||
public LuckPermsSubscriptionMap getSubscriptionMap() {
|
||||
return this.subscriptionMap;
|
||||
}
|
||||
|
||||
public void setSubscriptionMap(LPSubscriptionMap subscriptionMap) {
|
||||
public void setSubscriptionMap(LuckPermsSubscriptionMap subscriptionMap) {
|
||||
this.subscriptionMap = subscriptionMap;
|
||||
}
|
||||
|
||||
public LPPermissionMap getPermissionMap() {
|
||||
public LuckPermsPermissionMap getPermissionMap() {
|
||||
return this.permissionMap;
|
||||
}
|
||||
|
||||
public void setPermissionMap(LPPermissionMap permissionMap) {
|
||||
public void setPermissionMap(LuckPermsPermissionMap permissionMap) {
|
||||
this.permissionMap = permissionMap;
|
||||
}
|
||||
|
||||
public LPDefaultsMap getDefaultPermissionMap() {
|
||||
public LuckPermsDefaultsMap getDefaultPermissionMap() {
|
||||
return this.defaultPermissionMap;
|
||||
}
|
||||
|
||||
public void setDefaultPermissionMap(LPDefaultsMap defaultPermissionMap) {
|
||||
public void setDefaultPermissionMap(LuckPermsDefaultsMap defaultPermissionMap) {
|
||||
this.defaultPermissionMap = defaultPermissionMap;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.brigadier;
|
||||
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
|
||||
import me.lucko.commodore.Commodore;
|
||||
import me.lucko.commodore.CommodoreProvider;
|
||||
import me.lucko.commodore.file.CommodoreFileFormat;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Registers LuckPerms command data to brigadier using {@link Commodore}.
|
||||
*/
|
||||
public final class LuckPermsBrigadier {
|
||||
private LuckPermsBrigadier() {}
|
||||
|
||||
public static void register(LPBukkitPlugin plugin, Command pluginCommand) throws Exception {
|
||||
Commodore commodore = CommodoreProvider.getCommodore(plugin.getBootstrap());
|
||||
try (InputStream is = plugin.getBootstrap().getResourceStream("luckperms.commodore")) {
|
||||
if (is == null) {
|
||||
throw new Exception("Brigadier command data missing from jar");
|
||||
}
|
||||
|
||||
LiteralCommandNode<?> commandNode = CommodoreFileFormat.parse(is);
|
||||
commodore.register(pluginCommand, commandNode, player -> {
|
||||
Sender playerAsSender = plugin.getSenderFactory().wrap(player);
|
||||
return plugin.getCommandManager().hasPermissionForAny(playerAsSender);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+12
-2
@@ -35,6 +35,7 @@ import me.lucko.luckperms.common.calculator.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculator.processor.MapProcessor;
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
import me.lucko.luckperms.common.calculator.processor.RegexProcessor;
|
||||
import me.lucko.luckperms.common.calculator.processor.SpongeWildcardProcessor;
|
||||
import me.lucko.luckperms.common.calculator.processor.WildcardProcessor;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
@@ -66,8 +67,17 @@ public class BukkitCalculatorFactory implements CalculatorFactory {
|
||||
processors.add(new WildcardProcessor());
|
||||
}
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS) && metadata.getHolderType() == HolderType.USER) {
|
||||
processors.add(new DefaultsProcessor(this.plugin, queryOptions.option(BukkitContextManager.OP_OPTION).orElse(false)));
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_WILDCARDS_SPONGE)) {
|
||||
processors.add(new SpongeWildcardProcessor());
|
||||
}
|
||||
|
||||
boolean op = queryOptions.option(BukkitContextManager.OP_OPTION).orElse(false);
|
||||
if (metadata.getHolderType() == HolderType.USER && this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS)) {
|
||||
processors.add(new DefaultsProcessor(this.plugin, op));
|
||||
}
|
||||
|
||||
if (op) {
|
||||
processors.add(new OpProcessor());
|
||||
}
|
||||
|
||||
return new PermissionCalculator(this.plugin, metadata, processors.build());
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.calculator;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
/**
|
||||
* Permission Processor which is added for opped users, to simply return true if
|
||||
* no other processors match.
|
||||
*/
|
||||
public class OpProcessor implements PermissionProcessor {
|
||||
private static final TristateResult TRUE_RESULT = new TristateResult.Factory(OpProcessor.class).result(Tristate.TRUE);
|
||||
|
||||
@Override
|
||||
public TristateResult hasPermission(String permission) {
|
||||
return TRUE_RESULT;
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.compat;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
|
||||
import me.lucko.commodore.Commodore;
|
||||
import me.lucko.commodore.CommodoreProvider;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerCommandSendEvent;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
public class LuckPermsBrigadier {
|
||||
|
||||
public static void register(LPBukkitPlugin plugin, Command pluginCommand) throws Exception {
|
||||
// register completions with commodore
|
||||
Commodore commodore = CommodoreProvider.getCommodore(plugin.getBootstrap());
|
||||
try (InputStream is = plugin.getBootstrap().getResourceStream("luckperms-brigadier.json.gz")) {
|
||||
if (is == null) {
|
||||
throw new Exception("Brigadier command data missing from jar!");
|
||||
}
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(is), StandardCharsets.UTF_8))) {
|
||||
JsonObject data = new JsonParser().parse(reader).getAsJsonObject();
|
||||
LiteralArgumentBuilder command = deserializeLiteral(data);
|
||||
commodore.register(pluginCommand, command);
|
||||
}
|
||||
}
|
||||
|
||||
// add event listener to prevent completions from being send to players without permission
|
||||
// to use any LP commands.
|
||||
PluginManager pluginManager = plugin.getBootstrap().getServer().getPluginManager();
|
||||
pluginManager.registerEvents(new PermissionListener(plugin, pluginCommand), plugin.getBootstrap());
|
||||
}
|
||||
|
||||
private static final class PermissionListener implements Listener {
|
||||
private final LPBukkitPlugin plugin;
|
||||
private final List<String> aliases;
|
||||
|
||||
private PermissionListener(LPBukkitPlugin plugin, Command pluginCommand) {
|
||||
this.plugin = plugin;
|
||||
this.aliases = Commodore.getAliases(pluginCommand).stream()
|
||||
.flatMap(alias -> Stream.of(alias, "minecraft:" + alias))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onCommandSend(PlayerCommandSendEvent e) {
|
||||
Sender playerAsSender = this.plugin.getSenderFactory().wrap(e.getPlayer());
|
||||
if (!this.plugin.getCommandManager().hasPermissionForAny(playerAsSender)) {
|
||||
e.getCommands().removeAll(this.aliases);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ArgumentBuilder deserialize(JsonObject data) {
|
||||
String type = data.get("type").getAsString();
|
||||
switch (type) {
|
||||
case "literal": {
|
||||
return deserializeLiteral(data);
|
||||
}
|
||||
case "argument": {
|
||||
return deserializeArgument(data);
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private static LiteralArgumentBuilder deserializeLiteral(JsonObject data) {
|
||||
String name = data.get("name").getAsString();
|
||||
LiteralArgumentBuilder arg = LiteralArgumentBuilder.literal(name);
|
||||
return deserializeChildren(data, arg);
|
||||
}
|
||||
|
||||
private static RequiredArgumentBuilder deserializeArgument(JsonObject data) {
|
||||
String name = data.get("name").getAsString();
|
||||
ArgumentType argumentType = deserializeArgumentType(data);
|
||||
|
||||
//noinspection unchecked
|
||||
RequiredArgumentBuilder arg = RequiredArgumentBuilder.argument(name, argumentType);
|
||||
return deserializeChildren(data, arg);
|
||||
}
|
||||
|
||||
private static ArgumentType deserializeArgumentType(JsonObject data) {
|
||||
String parser = data.get("parser").getAsString();
|
||||
String properties = null;
|
||||
if (data.has("properties")) {
|
||||
properties = data.get("properties").getAsString();
|
||||
}
|
||||
|
||||
switch (parser) {
|
||||
case "brigadier:string": {
|
||||
Objects.requireNonNull(properties, "string properties");
|
||||
switch (properties) {
|
||||
case "SINGLE_WORD":
|
||||
return StringArgumentType.word();
|
||||
case "QUOTABLE_PHRASE":
|
||||
return StringArgumentType.string();
|
||||
case "GREEDY_PHRASE":
|
||||
return StringArgumentType.greedyString();
|
||||
default:
|
||||
throw new IllegalArgumentException("string property: " + properties);
|
||||
}
|
||||
}
|
||||
case "brigadier:bool":
|
||||
return BoolArgumentType.bool();
|
||||
case "brigadier:integer":
|
||||
return IntegerArgumentType.integer();
|
||||
default:
|
||||
throw new IllegalArgumentException("parser: " + parser);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T extends ArgumentBuilder> T deserializeChildren(JsonObject data, T builder) {
|
||||
if (data.has("children")) {
|
||||
JsonArray children = data.get("children").getAsJsonArray();
|
||||
for (JsonElement child : children) {
|
||||
//noinspection unchecked
|
||||
builder.then(deserialize(child.getAsJsonObject()));
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,7 +32,6 @@ import me.lucko.luckperms.common.cache.LoadingMap;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.ContextManager;
|
||||
import me.lucko.luckperms.common.context.QueryOptionsCache;
|
||||
import me.lucko.luckperms.common.context.QueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
@@ -41,9 +40,10 @@ import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BukkitContextManager extends ContextManager<Player> {
|
||||
public class BukkitContextManager extends ContextManager<Player, Player> {
|
||||
|
||||
public static final OptionKey<Boolean> OP_OPTION = OptionKey.of("op", Boolean.class);
|
||||
|
||||
@@ -62,7 +62,7 @@ public class BukkitContextManager extends ContextManager<Player> {
|
||||
});
|
||||
|
||||
public BukkitContextManager(LPBukkitPlugin plugin) {
|
||||
super(plugin, Player.class);
|
||||
super(plugin, Player.class, Player.class);
|
||||
}
|
||||
|
||||
public void onPlayerQuit(Player player) {
|
||||
@@ -70,7 +70,12 @@ public class BukkitContextManager extends ContextManager<Player> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptionsSupplier getCacheFor(Player subject) {
|
||||
public UUID getUniqueId(Player player) {
|
||||
return player.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptionsCache<Player> getCacheFor(Player subject) {
|
||||
if (subject == null) {
|
||||
throw new NullPointerException("subject");
|
||||
}
|
||||
@@ -83,11 +88,7 @@ public class BukkitContextManager extends ContextManager<Player> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCache(Player subject) {
|
||||
if (subject == null) {
|
||||
throw new NullPointerException("subject");
|
||||
}
|
||||
|
||||
protected void invalidateCache(Player subject) {
|
||||
QueryOptionsCache<Player> cache = this.onlineSubjectCaches.getIfPresent(subject);
|
||||
if (cache != null) {
|
||||
cache.invalidate();
|
||||
@@ -101,7 +102,7 @@ public class BukkitContextManager extends ContextManager<Player> {
|
||||
|
||||
@Override
|
||||
public QueryOptions formQueryOptions(Player subject, ImmutableContextSet contextSet) {
|
||||
QueryOptions.Builder queryOptions = this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_CONTEXTS).toBuilder();
|
||||
QueryOptions.Builder queryOptions = this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS).toBuilder();
|
||||
if (subject.isOp()) {
|
||||
queryOptions.option(OP_OPTION, true);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ package me.lucko.luckperms.bukkit.context;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl;
|
||||
|
||||
import net.luckperms.api.context.Context;
|
||||
import net.luckperms.api.context.ContextCalculator;
|
||||
import net.luckperms.api.context.ContextConsumer;
|
||||
import net.luckperms.api.context.ContextSet;
|
||||
@@ -36,13 +38,17 @@ import net.luckperms.api.context.ImmutableContextSet;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class WorldCalculator implements ContextCalculator<Player> {
|
||||
public class WorldCalculator implements ContextCalculator<Player>, Listener {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public WorldCalculator(LPBukkitPlugin plugin) {
|
||||
@@ -53,7 +59,9 @@ public class WorldCalculator implements ContextCalculator<Player> {
|
||||
public void calculate(@NonNull Player subject, @NonNull ContextConsumer consumer) {
|
||||
Set<String> seen = new HashSet<>();
|
||||
String world = subject.getWorld().getName().toLowerCase();
|
||||
while (seen.add(world)) {
|
||||
// seems like world names can sometimes be the empty string
|
||||
// see: https://github.com/lucko/LuckPerms/issues/2119
|
||||
while (Context.isValidValue(world) && seen.add(world)) {
|
||||
consumer.accept(DefaultContextKeys.WORLD_KEY, world);
|
||||
world = this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(world, world).toLowerCase();
|
||||
}
|
||||
@@ -62,10 +70,18 @@ public class WorldCalculator implements ContextCalculator<Player> {
|
||||
@Override
|
||||
public ContextSet estimatePotentialContexts() {
|
||||
List<World> worlds = this.plugin.getBootstrap().getServer().getWorlds();
|
||||
ImmutableContextSet.Builder builder = ImmutableContextSet.builder();
|
||||
ImmutableContextSet.Builder builder = new ImmutableContextSetImpl.BuilderImpl();
|
||||
for (World world : worlds) {
|
||||
builder.add(DefaultContextKeys.WORLD_KEY, world.getName().toLowerCase());
|
||||
String name = world.getName().toLowerCase();
|
||||
if (Context.isValidValue(name)) {
|
||||
builder.add(DefaultContextKeys.WORLD_KEY, name);
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onWorldChange(PlayerChangedWorldEvent e) {
|
||||
this.plugin.getContextManager().signalContextUpdate(e.getPlayer());
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.inject.dummy;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginLoader;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Dummy plugin instance
|
||||
*/
|
||||
public class DummyPlugin implements Plugin {
|
||||
public static final DummyPlugin INSTANCE = new DummyPlugin();
|
||||
|
||||
private DummyPlugin() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public @NonNull File getDataFolder() { return null; }
|
||||
@Override public @NonNull PluginDescriptionFile getDescription() { return null; }
|
||||
@Override public @NonNull FileConfiguration getConfig() { return null; }
|
||||
@Override public InputStream getResource(@NonNull String s) { return null; }
|
||||
@Override public void saveConfig() {}
|
||||
@Override public void saveDefaultConfig() {}
|
||||
@Override public void saveResource(@NonNull String s, boolean b) {}
|
||||
@Override public void reloadConfig() {}
|
||||
@Override public @NonNull PluginLoader getPluginLoader() { return null; }
|
||||
@Override public @NonNull Server getServer() { return null; }
|
||||
@Override public void onDisable() {}
|
||||
@Override public void onLoad() {}
|
||||
@Override public void onEnable() {}
|
||||
@Override public boolean isNaggable() { return false; }
|
||||
@Override public void setNaggable(boolean b) {}
|
||||
@Override public ChunkGenerator getDefaultWorldGenerator(@NonNull String s, String s1) { return null; }
|
||||
@Override public @NonNull Logger getLogger() { return null; }
|
||||
@Override public @NonNull String getName() { return null; }
|
||||
@Override public boolean onCommand(@NonNull CommandSender commandSender, @NonNull Command command, @NonNull String s, @NonNull String[] strings) { return false; }
|
||||
@Override public List<String> onTabComplete(@NonNull CommandSender commandSender, @NonNull Command command, @NonNull String s, @NonNull String[] strings) { return null; }
|
||||
|
||||
}
|
||||
+8
-34
@@ -23,7 +23,9 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.inject.dummy;
|
||||
package me.lucko.luckperms.bukkit.inject.permissible;
|
||||
|
||||
import me.lucko.luckperms.common.util.EmptyCollections;
|
||||
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
import org.bukkit.permissions.Permission;
|
||||
@@ -33,14 +35,8 @@ import org.bukkit.plugin.Plugin;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class DummyPermissibleBase extends PermissibleBase {
|
||||
private static final Field ATTACHMENTS_FIELD;
|
||||
@@ -61,13 +57,9 @@ public class DummyPermissibleBase extends PermissibleBase {
|
||||
public static void copyFields(PermissibleBase from, PermissibleBase to) {
|
||||
try {
|
||||
ATTACHMENTS_FIELD.set(to, ATTACHMENTS_FIELD.get(from));
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
try {
|
||||
PERMISSIONS_FIELD.set(to, PERMISSIONS_FIELD.get(from));
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,29 +68,11 @@ public class DummyPermissibleBase extends PermissibleBase {
|
||||
private DummyPermissibleBase() {
|
||||
super(null);
|
||||
|
||||
// we want the singleton dummy attachment to be stateless
|
||||
// the behaviour of this class is to fail silently, so we can't use Collections.emptyX
|
||||
try {
|
||||
ATTACHMENTS_FIELD.set(this, new ArrayList<PermissionAttachment>(){
|
||||
@Override public boolean add(PermissionAttachment permissionAttachment) { return true; }
|
||||
@Override public void add(int index, PermissionAttachment element) { }
|
||||
@Override public boolean addAll(Collection<? extends PermissionAttachment> c) { return true; }
|
||||
@Override public boolean addAll(int index, Collection<? extends PermissionAttachment> c) { return true; }
|
||||
});
|
||||
ATTACHMENTS_FIELD.set(this, EmptyCollections.list());
|
||||
PERMISSIONS_FIELD.set(this, EmptyCollections.map());
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
try {
|
||||
PERMISSIONS_FIELD.set(this, new HashMap<String, PermissionAttachmentInfo>() {
|
||||
@Override public PermissionAttachmentInfo put(String key, PermissionAttachmentInfo value) { return null; }
|
||||
@Override public void putAll(Map<? extends String, ? extends PermissionAttachmentInfo> m) { }
|
||||
@Override public PermissionAttachmentInfo putIfAbsent(String key, PermissionAttachmentInfo value) { return null; }
|
||||
@Override public PermissionAttachmentInfo compute(String key, BiFunction<? super String, ? super PermissionAttachmentInfo, ? extends PermissionAttachmentInfo> remappingFunction) { return null; }
|
||||
@Override public PermissionAttachmentInfo computeIfPresent(String key, BiFunction<? super String, ? super PermissionAttachmentInfo, ? extends PermissionAttachmentInfo> remappingFunction) { return null; }
|
||||
@Override public PermissionAttachmentInfo computeIfAbsent(String key, Function<? super String, ? extends PermissionAttachmentInfo> mappingFunction) { return null; }
|
||||
});
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
+80
-75
@@ -26,16 +26,18 @@
|
||||
package me.lucko.luckperms.bukkit.inject.permissible;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.bukkit.calculator.DefaultsProcessor;
|
||||
import me.lucko.luckperms.bukkit.calculator.OpProcessor;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.QueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.context.QueryOptionsCache;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.util.ImmutableCollectors;
|
||||
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
|
||||
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -51,6 +53,7 @@ import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -70,7 +73,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* This class is **thread safe**. This means that when LuckPerms is installed on the server,
|
||||
* is is safe to call Player#hasPermission asynchronously.
|
||||
*/
|
||||
public class LPPermissible extends PermissibleBase {
|
||||
public class LuckPermsPermissible extends PermissibleBase {
|
||||
|
||||
private static final Field ATTACHMENTS_FIELD;
|
||||
|
||||
@@ -93,7 +96,7 @@ public class LPPermissible extends PermissibleBase {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
// caches context lookups for the player
|
||||
private final QueryOptionsSupplier queryOptionsSupplier;
|
||||
private final QueryOptionsCache<Player> queryOptionsSupplier;
|
||||
|
||||
// the players previous permissible. (the one they had before this one was injected)
|
||||
private PermissibleBase oldPermissible = null;
|
||||
@@ -103,9 +106,9 @@ public class LPPermissible extends PermissibleBase {
|
||||
|
||||
// the attachments hooked onto the permissible.
|
||||
// this collection is only modified by the attachments themselves
|
||||
final Set<LPPermissionAttachment> lpAttachments = ConcurrentHashMap.newKeySet();
|
||||
final Set<LuckPermsPermissionAttachment> hookedAttachments = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public LPPermissible(Player player, User user, LPBukkitPlugin plugin) {
|
||||
public LuckPermsPermissible(Player player, User user, LPBukkitPlugin plugin) {
|
||||
super(player);
|
||||
this.user = Objects.requireNonNull(user, "user");
|
||||
this.player = Objects.requireNonNull(player, "player");
|
||||
@@ -139,13 +142,19 @@ public class LPPermissible extends PermissibleBase {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
TristateResult result = this.user.getCachedData().getPermissionData(this.queryOptionsSupplier.getQueryOptions()).checkPermission(permission, PermissionCheckEvent.Origin.PLATFORM_LOOKUP_CHECK);
|
||||
QueryOptions queryOptions = this.queryOptionsSupplier.getQueryOptions();
|
||||
TristateResult result = this.user.getCachedData().getPermissionData(queryOptions).checkPermission(permission, PermissionCheckEvent.Origin.PLATFORM_LOOKUP_CHECK);
|
||||
if (result.result() == Tristate.UNDEFINED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ignore matches made from looking up in the permission map (replicate bukkit behaviour)
|
||||
return !(result.processorClass() == DefaultsProcessor.class && "permission map".equals(result.cause()));
|
||||
if (result.processorClass() == DefaultsProcessor.class && "permission map".equals(result.cause())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ignore the op processor
|
||||
return result.processorClass() != OpProcessor.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -163,8 +172,8 @@ public class LPPermissible extends PermissibleBase {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
Tristate ts = this.user.getCachedData().getPermissionData(this.queryOptionsSupplier.getQueryOptions()).checkPermission(permission, PermissionCheckEvent.Origin.PLATFORM_PERMISSION_CHECK).result();
|
||||
return ts != Tristate.UNDEFINED ? ts.asBoolean() : Permission.DEFAULT_PERMISSION.getValue(isOp());
|
||||
QueryOptions queryOptions = this.queryOptionsSupplier.getQueryOptions();
|
||||
return this.user.getCachedData().getPermissionData(queryOptions).checkPermission(permission, PermissionCheckEvent.Origin.PLATFORM_PERMISSION_CHECK).result().asBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -173,16 +182,16 @@ public class LPPermissible extends PermissibleBase {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
|
||||
Tristate ts = this.user.getCachedData().getPermissionData(this.queryOptionsSupplier.getQueryOptions()).checkPermission(permission.getName(), PermissionCheckEvent.Origin.PLATFORM_PERMISSION_CHECK).result();
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
return ts.asBoolean();
|
||||
QueryOptions queryOptions = this.queryOptionsSupplier.getQueryOptions();
|
||||
TristateResult result = this.user.getCachedData().getPermissionData(queryOptions).checkPermission(permission.getName(), PermissionCheckEvent.Origin.PLATFORM_PERMISSION_CHECK);
|
||||
|
||||
// override default op handling using the Permission class we have
|
||||
if (result.processorClass() == OpProcessor.class && this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS)) {
|
||||
// 'op == true' is implied by the presence of the OpProcessor class
|
||||
return permission.getDefault().getValue(true);
|
||||
}
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS)) {
|
||||
return permission.getDefault().getValue(isOp());
|
||||
} else {
|
||||
return Permission.DEFAULT_PERMISSION.getValue(isOp());
|
||||
}
|
||||
return result.result().asBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,7 +201,7 @@ public class LPPermissible extends PermissibleBase {
|
||||
*/
|
||||
void convertAndAddAttachments(Collection<PermissionAttachment> attachments) {
|
||||
for (PermissionAttachment attachment : attachments) {
|
||||
new LPPermissionAttachment(this, attachment).hook();
|
||||
new LuckPermsPermissionAttachment(this, attachment).hook();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,103 +212,99 @@ public class LPPermissible extends PermissibleBase {
|
||||
|
||||
@Override
|
||||
public @NonNull Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
return this.user.getCachedData().getPermissionData(this.queryOptionsSupplier.getQueryOptions()).getPermissionMap().entrySet().stream()
|
||||
.map(entry -> new PermissionAttachmentInfo(this.player, entry.getKey(), null, entry.getValue()))
|
||||
.collect(ImmutableCollectors.toSet());
|
||||
Map<String, Boolean> permissionMap = this.user.getCachedData().getPermissionData(this.queryOptionsSupplier.getQueryOptions()).getPermissionMap();
|
||||
|
||||
ImmutableSet.Builder<PermissionAttachmentInfo> builder = ImmutableSet.builder();
|
||||
permissionMap.forEach((key, value) -> builder.add(new PermissionAttachmentInfo(this.player, key, null, value)));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull LPPermissionAttachment addAttachment(@NonNull Plugin plugin) {
|
||||
if (plugin == null) {
|
||||
throw new NullPointerException("plugin");
|
||||
}
|
||||
public @NonNull LuckPermsPermissionAttachment addAttachment(@NonNull Plugin plugin) {
|
||||
Objects.requireNonNull(plugin, "plugin");
|
||||
|
||||
LPPermissionAttachment ret = new LPPermissionAttachment(this, plugin);
|
||||
ret.hook();
|
||||
return ret;
|
||||
LuckPermsPermissionAttachment attachment = new LuckPermsPermissionAttachment(this, plugin);
|
||||
attachment.hook();
|
||||
return attachment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull PermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String permission, boolean value) {
|
||||
if (plugin == null) {
|
||||
throw new NullPointerException("plugin");
|
||||
}
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
Objects.requireNonNull(plugin, "plugin");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
|
||||
PermissionAttachment ret = addAttachment(plugin);
|
||||
ret.setPermission(permission, value);
|
||||
return ret;
|
||||
PermissionAttachment attachment = addAttachment(plugin);
|
||||
attachment.setPermission(permission, value);
|
||||
return attachment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LPPermissionAttachment addAttachment(@NonNull Plugin plugin, int ticks) {
|
||||
if (plugin == null) {
|
||||
throw new NullPointerException("plugin");
|
||||
}
|
||||
public LuckPermsPermissionAttachment addAttachment(@NonNull Plugin plugin, int ticks) {
|
||||
Objects.requireNonNull(plugin, "plugin");
|
||||
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
|
||||
}
|
||||
|
||||
LPPermissionAttachment ret = addAttachment(plugin);
|
||||
if (getPlugin().getBootstrap().getServer().getScheduler().scheduleSyncDelayedTask(plugin, ret::remove, ticks) == -1) {
|
||||
ret.remove();
|
||||
LuckPermsPermissionAttachment attachment = addAttachment(plugin);
|
||||
if (getPlugin().getBootstrap().getServer().getScheduler().scheduleSyncDelayedTask(plugin, attachment::remove, ticks) == -1) {
|
||||
attachment.remove();
|
||||
throw new RuntimeException("Could not add PermissionAttachment to " + this.player + " for plugin " + plugin.getDescription().getFullName() + ": Scheduler returned -1");
|
||||
}
|
||||
return ret;
|
||||
return attachment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LPPermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String permission, boolean value, int ticks) {
|
||||
if (plugin == null) {
|
||||
throw new NullPointerException("plugin");
|
||||
}
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
public LuckPermsPermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String permission, boolean value, int ticks) {
|
||||
Objects.requireNonNull(plugin, "plugin");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
|
||||
LPPermissionAttachment ret = addAttachment(plugin, ticks);
|
||||
ret.setPermission(permission, value);
|
||||
return ret;
|
||||
LuckPermsPermissionAttachment attachment = addAttachment(plugin, ticks);
|
||||
attachment.setPermission(permission, value);
|
||||
return attachment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttachment(@NonNull PermissionAttachment attachment) {
|
||||
if (attachment == null) {
|
||||
throw new NullPointerException("attachment");
|
||||
}
|
||||
Objects.requireNonNull(attachment, "attachment");
|
||||
|
||||
LPPermissionAttachment a;
|
||||
LuckPermsPermissionAttachment luckPermsAttachment;
|
||||
|
||||
if (!(attachment instanceof LPPermissionAttachment)) {
|
||||
if (!(attachment instanceof LuckPermsPermissionAttachment)) {
|
||||
// try to find a match
|
||||
LPPermissionAttachment match = this.lpAttachments.stream().filter(at -> at.getSource() == attachment).findFirst().orElse(null);
|
||||
LuckPermsPermissionAttachment match = this.hookedAttachments.stream().filter(at -> at.getSource() == attachment).findFirst().orElse(null);
|
||||
if (match != null) {
|
||||
a = match;
|
||||
luckPermsAttachment = match;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Given attachment is not a LPPermissionAttachment.");
|
||||
}
|
||||
} else {
|
||||
a = (LPPermissionAttachment) attachment;
|
||||
luckPermsAttachment = (LuckPermsPermissionAttachment) attachment;
|
||||
}
|
||||
|
||||
if (a.getPermissible() != this) {
|
||||
if (luckPermsAttachment.getPermissible() != this) {
|
||||
throw new IllegalArgumentException("Attachment does not belong to this permissible.");
|
||||
}
|
||||
|
||||
a.remove();
|
||||
luckPermsAttachment.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recalculatePermissions() {
|
||||
// do nothing
|
||||
// this method is called (among other times) when op status is updated.
|
||||
// because we encapsulate op status within QueryOptions, we need to invalidate
|
||||
// the query options cache when op status changes.
|
||||
// (#invalidate is a fast call)
|
||||
if (this.queryOptionsSupplier != null) { // this method is called by the super class constructor, before this class has fully initialised
|
||||
this.queryOptionsSupplier.invalidate();
|
||||
}
|
||||
|
||||
// but we don't need to do anything else in this method, unlike the CB impl.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearPermissions() {
|
||||
this.lpAttachments.forEach(LPPermissionAttachment::remove);
|
||||
this.hookedAttachments.forEach(LuckPermsPermissionAttachment::remove);
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
@@ -339,11 +344,11 @@ public class LPPermissible extends PermissibleBase {
|
||||
|
||||
@Override
|
||||
public boolean add(PermissionAttachment attachment) {
|
||||
if (LPPermissible.this.lpAttachments.stream().anyMatch(at -> at.getSource() == attachment)) {
|
||||
if (LuckPermsPermissible.this.hookedAttachments.stream().anyMatch(at -> at.getSource() == attachment)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
new LPPermissionAttachment(LPPermissible.this, attachment).hook();
|
||||
new LuckPermsPermissionAttachment(LuckPermsPermissible.this, attachment).hook();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -372,27 +377,27 @@ public class LPPermissible extends PermissibleBase {
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
PermissionAttachment attachment = (PermissionAttachment) o;
|
||||
return LPPermissible.this.lpAttachments.stream().anyMatch(at -> at.getSource() == attachment);
|
||||
return LuckPermsPermissible.this.hookedAttachments.stream().anyMatch(at -> at.getSource() == attachment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<PermissionAttachment> iterator() {
|
||||
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).iterator();
|
||||
return ImmutableList.<PermissionAttachment>copyOf(LuckPermsPermissible.this.hookedAttachments).iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<PermissionAttachment> listIterator() {
|
||||
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).listIterator();
|
||||
return ImmutableList.<PermissionAttachment>copyOf(LuckPermsPermissible.this.hookedAttachments).listIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Object[] toArray() {
|
||||
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).toArray();
|
||||
return ImmutableList.<PermissionAttachment>copyOf(LuckPermsPermissible.this.hookedAttachments).toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull <T> T[] toArray(@NonNull T[] a) {
|
||||
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).toArray(a);
|
||||
return ImmutableList.<PermissionAttachment>copyOf(LuckPermsPermissible.this.hookedAttachments).toArray(a);
|
||||
}
|
||||
|
||||
@Override public int size() { throw new UnsupportedOperationException(); }
|
||||
+36
-32
@@ -27,14 +27,15 @@ package me.lucko.luckperms.bukkit.inject.permissible;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import me.lucko.luckperms.bukkit.inject.dummy.DummyPlugin;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.factory.NodeBuilders;
|
||||
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.NodeBuilder;
|
||||
import net.luckperms.api.node.metadata.NodeMetadataKey;
|
||||
import net.luckperms.api.query.Flag;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionRemovedExecutor;
|
||||
@@ -54,9 +55,9 @@ import java.util.Set;
|
||||
*
|
||||
* Applies all permissions directly to the backing user instance via transient nodes.
|
||||
*/
|
||||
public class LPPermissionAttachment extends PermissionAttachment {
|
||||
public class LuckPermsPermissionAttachment extends PermissionAttachment {
|
||||
|
||||
public static final NodeMetadataKey<LPPermissionAttachment> TRANSIENT_SOURCE_KEY = NodeMetadataKey.of("transientsource", LPPermissionAttachment.class);
|
||||
public static final NodeMetadataKey<LuckPermsPermissionAttachment> TRANSIENT_SOURCE_KEY = NodeMetadataKey.of("transientsource", LuckPermsPermissionAttachment.class);
|
||||
|
||||
/**
|
||||
* The field in PermissionAttachment where the attachments applied permissions
|
||||
@@ -76,7 +77,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
||||
/**
|
||||
* The parent LPPermissible
|
||||
*/
|
||||
private final LPPermissible permissible;
|
||||
private final LuckPermsPermissible permissible;
|
||||
|
||||
/**
|
||||
* The plugin which "owns" this attachment, may be null
|
||||
@@ -103,16 +104,16 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
||||
*/
|
||||
private PermissionAttachment source;
|
||||
|
||||
public LPPermissionAttachment(LPPermissible permissible, Plugin owner) {
|
||||
super(DummyPlugin.INSTANCE, null);
|
||||
public LuckPermsPermissionAttachment(LuckPermsPermissible permissible, Plugin owner) {
|
||||
super(owner, null);
|
||||
this.permissible = permissible;
|
||||
this.owner = owner;
|
||||
|
||||
injectFakeMap();
|
||||
}
|
||||
|
||||
public LPPermissionAttachment(LPPermissible permissible, PermissionAttachment source) {
|
||||
super(DummyPlugin.INSTANCE, null);
|
||||
public LuckPermsPermissionAttachment(LuckPermsPermissible permissible, PermissionAttachment source) {
|
||||
super(source.getPlugin(), null);
|
||||
this.permissible = permissible;
|
||||
this.owner = source.getPlugin();
|
||||
|
||||
@@ -144,7 +145,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull LPPermissible getPermissible() {
|
||||
public @NonNull LuckPermsPermissible getPermissible() {
|
||||
return this.permissible;
|
||||
}
|
||||
|
||||
@@ -167,7 +168,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
||||
*/
|
||||
public void hook() {
|
||||
this.hooked = true;
|
||||
this.permissible.lpAttachments.add(this);
|
||||
this.permissible.hookedAttachments.add(this);
|
||||
for (Map.Entry<String, Boolean> entry : this.perms.entrySet()) {
|
||||
if (entry.getKey() == null || entry.getKey().isEmpty()) {
|
||||
continue;
|
||||
@@ -182,16 +183,19 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
||||
}
|
||||
|
||||
// construct a node for the permission being set
|
||||
// we use the servers static context to *try* to ensure that the node will apply
|
||||
Node node = NodeBuilders.determineMostApplicable(name)
|
||||
NodeBuilder<?, ?> node = NodeBuilders.determineMostApplicable(name)
|
||||
.value(value)
|
||||
.withContext(this.permissible.getPlugin().getContextManager().getStaticContext())
|
||||
.withMetadata(TRANSIENT_SOURCE_KEY, this)
|
||||
.build();
|
||||
.withMetadata(TRANSIENT_SOURCE_KEY, this);
|
||||
|
||||
// apply with the servers static context to *try* to ensure that the node will apply if INCLUDE_NODES_WITHOUT_SERVER_CONTEXT is not set
|
||||
QueryOptions globalQueryOptions = this.permissible.getPlugin().getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS);
|
||||
if (!globalQueryOptions.flag(Flag.INCLUDE_NODES_WITHOUT_SERVER_CONTEXT)) {
|
||||
node.withContext(this.permissible.getPlugin().getContextManager().getStaticContext());
|
||||
}
|
||||
|
||||
// set the transient node
|
||||
User user = this.permissible.getUser();
|
||||
user.setNode(DataType.TRANSIENT, node, true);
|
||||
user.setNode(DataType.TRANSIENT, node.build(), true);
|
||||
}
|
||||
|
||||
private void unsetPermissionInternal(String name) {
|
||||
@@ -226,7 +230,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
||||
|
||||
// unhook from the permissible
|
||||
this.hooked = false;
|
||||
this.permissible.lpAttachments.remove(this);
|
||||
this.permissible.hookedAttachments.remove(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -311,7 +315,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
||||
@Override
|
||||
public Boolean put(String key, Boolean value) {
|
||||
// grab the previous result, so we can still satisfy the method signature of Map
|
||||
Boolean previous = LPPermissionAttachment.this.perms.get(key);
|
||||
Boolean previous = LuckPermsPermissionAttachment.this.perms.get(key);
|
||||
|
||||
// proxy the call back through the PermissionAttachment instance
|
||||
setPermission(key, value);
|
||||
@@ -330,7 +334,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
||||
String permission = ((String) key);
|
||||
|
||||
// grab the previous result, so we can still satisfy the method signature of Map
|
||||
Boolean previous = LPPermissionAttachment.this.perms.get(permission);
|
||||
Boolean previous = LuckPermsPermissionAttachment.this.perms.get(permission);
|
||||
|
||||
// proxy the call back through the PermissionAttachment instance
|
||||
unsetPermission(permission);
|
||||
@@ -349,71 +353,71 @@ public class LPPermissionAttachment extends PermissionAttachment {
|
||||
@Override
|
||||
public void clear() {
|
||||
// remove the permissions which have already been applied
|
||||
if (LPPermissionAttachment.this.hooked) {
|
||||
if (LuckPermsPermissionAttachment.this.hooked) {
|
||||
clearInternal();
|
||||
}
|
||||
|
||||
// clear the backing map
|
||||
LPPermissionAttachment.this.perms.clear();
|
||||
LuckPermsPermissionAttachment.this.perms.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
// return the size of the permissions map - probably the most accurate value we have
|
||||
return LPPermissionAttachment.this.perms.size();
|
||||
return LuckPermsPermissionAttachment.this.perms.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
// return if the permissions map is empty - again probably the most accurate thing
|
||||
// we can return
|
||||
return LPPermissionAttachment.this.perms.isEmpty();
|
||||
return LuckPermsPermissionAttachment.this.perms.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
// just proxy
|
||||
return LPPermissionAttachment.this.perms.containsKey(key);
|
||||
return LuckPermsPermissionAttachment.this.perms.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
// just proxy
|
||||
return LPPermissionAttachment.this.perms.containsValue(value);
|
||||
return LuckPermsPermissionAttachment.this.perms.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean get(Object key) {
|
||||
// just proxy
|
||||
return LPPermissionAttachment.this.perms.get(key);
|
||||
return LuckPermsPermissionAttachment.this.perms.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
// just proxy
|
||||
return Collections.unmodifiableSet(LPPermissionAttachment.this.perms.keySet());
|
||||
return Collections.unmodifiableSet(LuckPermsPermissionAttachment.this.perms.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Boolean> values() {
|
||||
// just proxy
|
||||
return Collections.unmodifiableCollection(LPPermissionAttachment.this.perms.values());
|
||||
return Collections.unmodifiableCollection(LuckPermsPermissionAttachment.this.perms.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, Boolean>> entrySet() {
|
||||
// just proxy
|
||||
return Collections.unmodifiableSet(LPPermissionAttachment.this.perms.entrySet());
|
||||
return Collections.unmodifiableSet(LuckPermsPermissionAttachment.this.perms.entrySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof Map<?, ?> && LPPermissionAttachment.this.perms.equals(obj);
|
||||
return obj instanceof Map<?, ?> && LuckPermsPermissionAttachment.this.perms.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return LPPermissionAttachment.this.perms.hashCode();
|
||||
return LuckPermsPermissionAttachment.this.perms.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -25,14 +25,13 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.inject.permissible;
|
||||
|
||||
import me.lucko.luckperms.bukkit.inject.dummy.DummyPermissibleBase;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.query.QueryOptionsImpl;
|
||||
import me.lucko.luckperms.common.verbose.VerboseHandler;
|
||||
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
import org.bukkit.permissions.Permission;
|
||||
@@ -70,7 +69,7 @@ public class MonitoredPermissibleBase extends PermissibleBase {
|
||||
}
|
||||
|
||||
private void logCheck(PermissionCheckEvent.Origin origin, String permission, boolean result) {
|
||||
this.plugin.getVerboseHandler().offerPermissionCheckEvent(origin, this.name, QueryOptions.defaultContextualOptions(), permission, TristateResult.of(Tristate.of(result)));
|
||||
this.plugin.getVerboseHandler().offerPermissionCheckEvent(origin, this.name, QueryOptionsImpl.DEFAULT_CONTEXTUAL, permission, TristateResult.of(Tristate.of(result)));
|
||||
this.plugin.getPermissionRegistry().offer(permission);
|
||||
}
|
||||
|
||||
|
||||
+9
-10
@@ -25,8 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.inject.permissible;
|
||||
|
||||
import me.lucko.luckperms.bukkit.compat.CraftBukkitUtil;
|
||||
import me.lucko.luckperms.bukkit.inject.dummy.DummyPermissibleBase;
|
||||
import me.lucko.luckperms.bukkit.util.CraftBukkitImplementation;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
@@ -36,7 +35,7 @@ import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Injects a {@link LPPermissible} into a {@link Player}.
|
||||
* Injects a {@link LuckPermsPermissible} into a {@link Player}.
|
||||
*
|
||||
* This allows LuckPerms to directly intercept permission checks and take over all handling of
|
||||
* checks made by plugins.
|
||||
@@ -63,7 +62,7 @@ public final class PermissibleInjector {
|
||||
Field humanEntityPermissibleField;
|
||||
try {
|
||||
// craftbukkit
|
||||
humanEntityPermissibleField = CraftBukkitUtil.obcClass("entity.CraftHumanEntity").getDeclaredField("perm");
|
||||
humanEntityPermissibleField = CraftBukkitImplementation.obcClass("entity.CraftHumanEntity").getDeclaredField("perm");
|
||||
humanEntityPermissibleField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
// glowstone
|
||||
@@ -81,19 +80,19 @@ public final class PermissibleInjector {
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects a {@link LPPermissible} into a {@link Player}.
|
||||
* Injects a {@link LuckPermsPermissible} into a {@link Player}.
|
||||
*
|
||||
* @param player the player to inject into
|
||||
* @param newPermissible the permissible to inject
|
||||
* @throws Exception propagates any exceptions which were thrown during injection
|
||||
*/
|
||||
public static void inject(Player player, LPPermissible newPermissible) throws Exception {
|
||||
public static void inject(Player player, LuckPermsPermissible newPermissible) throws Exception {
|
||||
|
||||
// get the existing PermissibleBase held by the player
|
||||
PermissibleBase oldPermissible = (PermissibleBase) HUMAN_ENTITY_PERMISSIBLE_FIELD.get(player);
|
||||
|
||||
// seems we have already injected into this player.
|
||||
if (oldPermissible instanceof LPPermissible) {
|
||||
if (oldPermissible instanceof LuckPermsPermissible) {
|
||||
throw new IllegalStateException("LPPermissible already injected into player " + player.toString());
|
||||
}
|
||||
|
||||
@@ -115,7 +114,7 @@ public final class PermissibleInjector {
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninjects a {@link LPPermissible} from a {@link Player}.
|
||||
* Uninjects a {@link LuckPermsPermissible} from a {@link Player}.
|
||||
*
|
||||
* @param player the player to uninject from
|
||||
* @param dummy if the replacement permissible should be a dummy.
|
||||
@@ -127,8 +126,8 @@ public final class PermissibleInjector {
|
||||
PermissibleBase permissible = (PermissibleBase) HUMAN_ENTITY_PERMISSIBLE_FIELD.get(player);
|
||||
|
||||
// only uninject if the permissible was a luckperms one.
|
||||
if (permissible instanceof LPPermissible) {
|
||||
LPPermissible lpPermissible = ((LPPermissible) permissible);
|
||||
if (permissible instanceof LuckPermsPermissible) {
|
||||
LuckPermsPermissible lpPermissible = ((LuckPermsPermissible) permissible);
|
||||
|
||||
// clear all permissions
|
||||
lpPermissible.clearPermissions();
|
||||
|
||||
+4
-4
@@ -26,7 +26,7 @@
|
||||
package me.lucko.luckperms.bukkit.inject.permissible;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.bukkit.compat.CraftBukkitUtil;
|
||||
import me.lucko.luckperms.bukkit.util.CraftBukkitImplementation;
|
||||
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
@@ -101,7 +101,7 @@ public class PermissibleMonitoringInjector implements Runnable {
|
||||
ConsoleCommandSender consoleSender = this.plugin.getBootstrap().getServer().getConsoleSender();
|
||||
|
||||
// get the ServerCommandSender class
|
||||
Class<?> serverCommandSenderClass = CraftBukkitUtil.obcClass("command.ServerCommandSender");
|
||||
Class<?> serverCommandSenderClass = CraftBukkitImplementation.obcClass("command.ServerCommandSender");
|
||||
|
||||
// get the perm field
|
||||
Field permField = serverCommandSenderClass.getDeclaredField("perm");
|
||||
@@ -122,7 +122,7 @@ public class PermissibleMonitoringInjector implements Runnable {
|
||||
|
||||
private void injectCommandBlock() throws Exception {
|
||||
// get the ServerCommandSender class
|
||||
Class<?> serverCommandSenderClass = CraftBukkitUtil.obcClass("command.ServerCommandSender");
|
||||
Class<?> serverCommandSenderClass = CraftBukkitImplementation.obcClass("command.ServerCommandSender");
|
||||
|
||||
// get the blockPermInst field
|
||||
Field permField = serverCommandSenderClass.getDeclaredField("blockPermInst");
|
||||
@@ -149,7 +149,7 @@ public class PermissibleMonitoringInjector implements Runnable {
|
||||
|
||||
private void injectEntity() throws Exception {
|
||||
// get the CraftEntity class
|
||||
Class<?> entityClass = CraftBukkitUtil.obcClass("entity.CraftEntity");
|
||||
Class<?> entityClass = CraftBukkitImplementation.obcClass("entity.CraftEntity");
|
||||
|
||||
// get the method used to obtain a PermissibleBase
|
||||
// this method will initialise a new PB instance if one doesn't yet exist
|
||||
|
||||
+13
-15
@@ -27,7 +27,6 @@ package me.lucko.luckperms.bukkit.inject.server;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
@@ -39,9 +38,9 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Injects a {@link LPDefaultsMap} info the {@link PluginManager}.
|
||||
* Injects a {@link LuckPermsDefaultsMap} info the {@link PluginManager}.
|
||||
*/
|
||||
public class InjectorDefaultsMap implements Runnable {
|
||||
public class InjectorDefaultsMap {
|
||||
private static final Field DEFAULT_PERMISSIONS_FIELD;
|
||||
|
||||
static {
|
||||
@@ -61,12 +60,11 @@ public class InjectorDefaultsMap implements Runnable {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
public void inject() {
|
||||
try {
|
||||
LPDefaultsMap ret = inject();
|
||||
if (ret != null) {
|
||||
this.plugin.setDefaultPermissionMap(ret);
|
||||
LuckPermsDefaultsMap defaultsMap = tryInject();
|
||||
if (defaultsMap != null) {
|
||||
this.plugin.setDefaultPermissionMap(defaultsMap);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.plugin.getLogger().severe("Exception occurred whilst injecting LuckPerms Default Permission map.");
|
||||
@@ -74,7 +72,7 @@ public class InjectorDefaultsMap implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private LPDefaultsMap inject() throws Exception {
|
||||
private LuckPermsDefaultsMap tryInject() throws Exception {
|
||||
Objects.requireNonNull(DEFAULT_PERMISSIONS_FIELD, "DEFAULT_PERMISSIONS_FIELD");
|
||||
PluginManager pluginManager = this.plugin.getBootstrap().getServer().getPluginManager();
|
||||
|
||||
@@ -85,7 +83,7 @@ public class InjectorDefaultsMap implements Runnable {
|
||||
}
|
||||
|
||||
Object map = DEFAULT_PERMISSIONS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPDefaultsMap && ((LPDefaultsMap) map).plugin == this.plugin) {
|
||||
if (map instanceof LuckPermsDefaultsMap && ((LuckPermsDefaultsMap) map).plugin == this.plugin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -93,23 +91,23 @@ public class InjectorDefaultsMap implements Runnable {
|
||||
Map<Boolean, Set<Permission>> castedMap = (Map<Boolean, Set<Permission>>) map;
|
||||
|
||||
// make a new map & inject it
|
||||
LPDefaultsMap newMap = new LPDefaultsMap(this.plugin, castedMap);
|
||||
LuckPermsDefaultsMap newMap = new LuckPermsDefaultsMap(this.plugin, castedMap);
|
||||
DEFAULT_PERMISSIONS_FIELD.set(pluginManager, newMap);
|
||||
return newMap;
|
||||
}
|
||||
|
||||
public static void uninject() {
|
||||
public void uninject() {
|
||||
try {
|
||||
Objects.requireNonNull(DEFAULT_PERMISSIONS_FIELD, "DEFAULT_PERMISSIONS_FIELD");
|
||||
|
||||
PluginManager pluginManager = Bukkit.getServer().getPluginManager();
|
||||
PluginManager pluginManager = this.plugin.getBootstrap().getServer().getPluginManager();
|
||||
if (!(pluginManager instanceof SimplePluginManager)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object map = DEFAULT_PERMISSIONS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPDefaultsMap) {
|
||||
LPDefaultsMap lpMap = (LPDefaultsMap) map;
|
||||
if (map instanceof LuckPermsDefaultsMap) {
|
||||
LuckPermsDefaultsMap lpMap = (LuckPermsDefaultsMap) map;
|
||||
DEFAULT_PERMISSIONS_FIELD.set(pluginManager, new HashMap<>(lpMap));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
+13
-15
@@ -27,7 +27,6 @@ package me.lucko.luckperms.bukkit.inject.server;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
@@ -38,9 +37,9 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Injects a {@link LPPermissionMap} into the {@link PluginManager}.
|
||||
* Injects a {@link LuckPermsPermissionMap} into the {@link PluginManager}.
|
||||
*/
|
||||
public class InjectorPermissionMap implements Runnable {
|
||||
public class InjectorPermissionMap {
|
||||
private static final Field PERMISSIONS_FIELD;
|
||||
|
||||
static {
|
||||
@@ -60,12 +59,11 @@ public class InjectorPermissionMap implements Runnable {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
public void inject() {
|
||||
try {
|
||||
LPPermissionMap ret = inject();
|
||||
if (ret != null) {
|
||||
this.plugin.setPermissionMap(ret);
|
||||
LuckPermsPermissionMap permissionMap = tryInject();
|
||||
if (permissionMap != null) {
|
||||
this.plugin.setPermissionMap(permissionMap);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.plugin.getLogger().severe("Exception occurred whilst injecting LuckPerms Permission map.");
|
||||
@@ -73,7 +71,7 @@ public class InjectorPermissionMap implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private LPPermissionMap inject() throws Exception {
|
||||
private LuckPermsPermissionMap tryInject() throws Exception {
|
||||
Objects.requireNonNull(PERMISSIONS_FIELD, "PERMISSIONS_FIELD");
|
||||
PluginManager pluginManager = this.plugin.getBootstrap().getServer().getPluginManager();
|
||||
|
||||
@@ -84,7 +82,7 @@ public class InjectorPermissionMap implements Runnable {
|
||||
}
|
||||
|
||||
Object map = PERMISSIONS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPPermissionMap && ((LPPermissionMap) map).plugin == this.plugin) {
|
||||
if (map instanceof LuckPermsPermissionMap && ((LuckPermsPermissionMap) map).plugin == this.plugin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -92,23 +90,23 @@ public class InjectorPermissionMap implements Runnable {
|
||||
Map<String, Permission> castedMap = (Map<String, Permission>) map;
|
||||
|
||||
// make a new map & inject it
|
||||
LPPermissionMap newMap = new LPPermissionMap(this.plugin, castedMap);
|
||||
LuckPermsPermissionMap newMap = new LuckPermsPermissionMap(this.plugin, castedMap);
|
||||
PERMISSIONS_FIELD.set(pluginManager, newMap);
|
||||
return newMap;
|
||||
}
|
||||
|
||||
public static void uninject() {
|
||||
public void uninject() {
|
||||
try {
|
||||
Objects.requireNonNull(PERMISSIONS_FIELD, "PERMISSIONS_FIELD");
|
||||
|
||||
PluginManager pluginManager = Bukkit.getServer().getPluginManager();
|
||||
PluginManager pluginManager = this.plugin.getBootstrap().getServer().getPluginManager();
|
||||
if (!(pluginManager instanceof SimplePluginManager)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object map = PERMISSIONS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPPermissionMap) {
|
||||
LPPermissionMap lpMap = (LPPermissionMap) map;
|
||||
if (map instanceof LuckPermsPermissionMap) {
|
||||
LuckPermsPermissionMap lpMap = (LuckPermsPermissionMap) map;
|
||||
PERMISSIONS_FIELD.set(pluginManager, new HashMap<>(lpMap));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
+15
-17
@@ -27,7 +27,6 @@ package me.lucko.luckperms.bukkit.inject.server;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
@@ -37,9 +36,9 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Injects a {@link LPSubscriptionMap} into the {@link PluginManager}.
|
||||
* Injects a {@link LuckPermsSubscriptionMap} into the {@link PluginManager}.
|
||||
*/
|
||||
public class InjectorSubscriptionMap implements Runnable {
|
||||
public class InjectorSubscriptionMap {
|
||||
private static final Field PERM_SUBS_FIELD;
|
||||
|
||||
static {
|
||||
@@ -59,12 +58,11 @@ public class InjectorSubscriptionMap implements Runnable {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
public void inject() {
|
||||
try {
|
||||
LPSubscriptionMap ret = inject();
|
||||
if (ret != null) {
|
||||
this.plugin.setSubscriptionMap(ret);
|
||||
LuckPermsSubscriptionMap subscriptionMap = tryInject();
|
||||
if (subscriptionMap != null) {
|
||||
this.plugin.setSubscriptionMap(subscriptionMap);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.plugin.getLogger().severe("Exception occurred whilst injecting LuckPerms Permission Subscription map.");
|
||||
@@ -72,7 +70,7 @@ public class InjectorSubscriptionMap implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private LPSubscriptionMap inject() throws Exception {
|
||||
private LuckPermsSubscriptionMap tryInject() throws Exception {
|
||||
Objects.requireNonNull(PERM_SUBS_FIELD, "PERM_SUBS_FIELD");
|
||||
PluginManager pluginManager = this.plugin.getBootstrap().getServer().getPluginManager();
|
||||
|
||||
@@ -83,35 +81,35 @@ public class InjectorSubscriptionMap implements Runnable {
|
||||
}
|
||||
|
||||
Object map = PERM_SUBS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPSubscriptionMap) {
|
||||
if (((LPSubscriptionMap) map).plugin == this.plugin) {
|
||||
if (map instanceof LuckPermsSubscriptionMap) {
|
||||
if (((LuckPermsSubscriptionMap) map).plugin == this.plugin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
map = ((LPSubscriptionMap) map).detach();
|
||||
map = ((LuckPermsSubscriptionMap) map).detach();
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
Map<String, Map<Permissible, Boolean>> castedMap = (Map<String, Map<Permissible, Boolean>>) map;
|
||||
|
||||
// make a new subscription map & inject it
|
||||
LPSubscriptionMap newMap = new LPSubscriptionMap(this.plugin, castedMap);
|
||||
LuckPermsSubscriptionMap newMap = new LuckPermsSubscriptionMap(this.plugin, castedMap);
|
||||
PERM_SUBS_FIELD.set(pluginManager, newMap);
|
||||
return newMap;
|
||||
}
|
||||
|
||||
public static void uninject() {
|
||||
public void uninject() {
|
||||
try {
|
||||
Objects.requireNonNull(PERM_SUBS_FIELD, "PERM_SUBS_FIELD");
|
||||
|
||||
PluginManager pluginManager = Bukkit.getServer().getPluginManager();
|
||||
PluginManager pluginManager = this.plugin.getBootstrap().getServer().getPluginManager();
|
||||
if (!(pluginManager instanceof SimplePluginManager)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object map = PERM_SUBS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPSubscriptionMap) {
|
||||
LPSubscriptionMap lpMap = (LPSubscriptionMap) map;
|
||||
if (map instanceof LuckPermsSubscriptionMap) {
|
||||
LuckPermsSubscriptionMap lpMap = (LuckPermsSubscriptionMap) map;
|
||||
PERM_SUBS_FIELD.set(pluginManager, lpMap.detach());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
+7
-10
@@ -56,7 +56,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*
|
||||
* Injected by {@link InjectorDefaultsMap}.
|
||||
*/
|
||||
public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
public final class LuckPermsDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
// keyset for all instances
|
||||
private static final Set<Boolean> KEY_SET = ImmutableSet.of(Boolean.TRUE, Boolean.FALSE);
|
||||
|
||||
@@ -78,7 +78,7 @@ public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
Maps.immutableEntry(Boolean.FALSE, this.nonOpSet)
|
||||
);
|
||||
|
||||
public LPDefaultsMap(LPBukkitPlugin plugin, Map<Boolean, Set<Permission>> existingData) {
|
||||
public LuckPermsDefaultsMap(LPBukkitPlugin plugin, Map<Boolean, Set<Permission>> existingData) {
|
||||
this.plugin = plugin;
|
||||
this.opSet.addAll(existingData.getOrDefault(Boolean.TRUE, Collections.emptySet()));
|
||||
this.nonOpSet.addAll(existingData.getOrDefault(Boolean.FALSE, Collections.emptySet()));
|
||||
@@ -113,12 +113,9 @@ public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
}
|
||||
|
||||
// return wrappers around this map impl
|
||||
@Override
|
||||
public @NonNull Collection<Set<Permission>> values() { return this.values; }
|
||||
@Override
|
||||
public @NonNull Set<Entry<Boolean, Set<Permission>>> entrySet() { return this.entrySet; }
|
||||
@Override
|
||||
public @NonNull Set<Boolean> keySet() { return KEY_SET; }
|
||||
@Override public @NonNull Collection<Set<Permission>> values() { return this.values; }
|
||||
@Override public @NonNull Set<Entry<Boolean, Set<Permission>>> entrySet() { return this.entrySet; }
|
||||
@Override public @NonNull Set<Boolean> keySet() { return KEY_SET; }
|
||||
|
||||
// return accurate results for the Map spec
|
||||
@Override public int size() { return 2; }
|
||||
@@ -142,10 +139,10 @@ public final class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
@Override
|
||||
protected @NonNull Map<String, Boolean> supply() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : LPDefaultsMap.this.get(this.op)) {
|
||||
for (Permission perm : LuckPermsDefaultsMap.this.get(this.op)) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : LPDefaultsMap.this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
for (Map.Entry<String, Boolean> child : LuckPermsDefaultsMap.this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
}
|
||||
}
|
||||
+21
-15
@@ -57,7 +57,7 @@ import java.util.function.Function;
|
||||
*
|
||||
* Injected by {@link InjectorPermissionMap}.
|
||||
*/
|
||||
public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
public final class LuckPermsPermissionMap extends ForwardingMap<String, Permission> {
|
||||
|
||||
private static final Field PERMISSION_CHILDREN_FIELD;
|
||||
|
||||
@@ -82,7 +82,7 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
*/
|
||||
final LuckPermsPlugin plugin;
|
||||
|
||||
public LPPermissionMap(LuckPermsPlugin plugin, Map<String, Permission> existingData) {
|
||||
public LuckPermsPermissionMap(LuckPermsPlugin plugin, Map<String, Permission> existingData) {
|
||||
this.plugin = plugin;
|
||||
putAll(existingData);
|
||||
}
|
||||
@@ -116,9 +116,11 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
|
||||
@Override
|
||||
public void putAll(@NonNull Map<? extends String, ? extends Permission> m) {
|
||||
for (Map.Entry<? extends String, ? extends Permission> ent : m.entrySet()) {
|
||||
put(ent.getKey(), ent.getValue());
|
||||
for (Map.Entry<? extends String, ? extends Permission> e : m.entrySet()) {
|
||||
this.plugin.getPermissionRegistry().insert(e.getKey());
|
||||
super.put(e.getKey(), inject(e.getValue()));
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -174,6 +176,10 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
// iterate through the current known children.
|
||||
// the first time this method is called for a given permission, the children map will contain only the permission itself.
|
||||
for (Map.Entry<String, Boolean> e : children.entrySet()) {
|
||||
if (e == null || e.getKey() == null || e.getValue() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (accumulator.containsKey(e.getKey())) {
|
||||
continue; // Prevent infinite loops
|
||||
}
|
||||
@@ -198,11 +204,11 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
try {
|
||||
//noinspection unchecked
|
||||
Map<String, Boolean> children = (Map<String, Boolean>) PERMISSION_CHILDREN_FIELD.get(permission);
|
||||
while (children instanceof PermissionNotifyingChildrenMap) {
|
||||
children = ((PermissionNotifyingChildrenMap) children).delegate;
|
||||
while (children instanceof NotifyingChildrenMap) {
|
||||
children = ((NotifyingChildrenMap) children).delegate;
|
||||
}
|
||||
|
||||
PermissionNotifyingChildrenMap notifyingChildren = new PermissionNotifyingChildrenMap(children);
|
||||
NotifyingChildrenMap notifyingChildren = new NotifyingChildrenMap(children);
|
||||
PERMISSION_CHILDREN_FIELD.set(permission, notifyingChildren);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -218,8 +224,8 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
try {
|
||||
//noinspection unchecked
|
||||
Map<String, Boolean> children = (Map<String, Boolean>) PERMISSION_CHILDREN_FIELD.get(permission);
|
||||
while (children instanceof PermissionNotifyingChildrenMap) {
|
||||
children = ((PermissionNotifyingChildrenMap) children).delegate;
|
||||
while (children instanceof NotifyingChildrenMap) {
|
||||
children = ((NotifyingChildrenMap) children).delegate;
|
||||
}
|
||||
PERMISSION_CHILDREN_FIELD.set(permission, children);
|
||||
} catch (Exception e) {
|
||||
@@ -228,10 +234,10 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
return permission;
|
||||
}
|
||||
|
||||
private final class PermissionNotifyingChildrenMap extends ForwardingMap<String, Boolean> {
|
||||
private final class NotifyingChildrenMap extends ForwardingMap<String, Boolean> {
|
||||
private final Map<String, Boolean> delegate;
|
||||
|
||||
PermissionNotifyingChildrenMap(Map<String, Boolean> delegate) {
|
||||
NotifyingChildrenMap(Map<String, Boolean> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@@ -243,27 +249,27 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
@Override
|
||||
public Boolean put(@NonNull String key, @NonNull Boolean value) {
|
||||
Boolean ret = super.put(key, value);
|
||||
LPPermissionMap.this.update();
|
||||
LuckPermsPermissionMap.this.update();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@NonNull Map<? extends String, ? extends Boolean> map) {
|
||||
super.putAll(map);
|
||||
LPPermissionMap.this.update();
|
||||
LuckPermsPermissionMap.this.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean remove(@NonNull Object object) {
|
||||
Boolean ret = super.remove(object);
|
||||
LPPermissionMap.this.update();
|
||||
LuckPermsPermissionMap.this.update();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
LPPermissionMap.this.update();
|
||||
LuckPermsPermissionMap.this.update();
|
||||
}
|
||||
}
|
||||
|
||||
+46
-31
@@ -26,7 +26,6 @@
|
||||
package me.lucko.luckperms.bukkit.inject.server;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.util.ImmutableCollectors;
|
||||
@@ -37,12 +36,14 @@ import org.bukkit.plugin.PluginManager;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A replacement map for the 'permSubs' instance in Bukkit's SimplePluginManager.
|
||||
@@ -66,14 +67,16 @@ import java.util.stream.Collectors;
|
||||
*
|
||||
* Injected by {@link InjectorSubscriptionMap}.
|
||||
*/
|
||||
public final class LPSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>> {
|
||||
public final class LuckPermsSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>> {
|
||||
|
||||
// the plugin instance
|
||||
final LPBukkitPlugin plugin;
|
||||
|
||||
public LPSubscriptionMap(LPBukkitPlugin plugin, Map<String, Map<Permissible, Boolean>> existingData) {
|
||||
super(existingData);
|
||||
public LuckPermsSubscriptionMap(LPBukkitPlugin plugin, Map<String, Map<Permissible, Boolean>> existingData) {
|
||||
this.plugin = plugin;
|
||||
for (Entry<String, Map<Permissible, Boolean>> entry : existingData.entrySet()) {
|
||||
super.put(entry.getKey(), new LPSubscriptionValueMap(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -94,17 +97,13 @@ public final class LPSubscriptionMap extends HashMap<String, Map<Permissible, Bo
|
||||
|
||||
String permission = ((String) key);
|
||||
|
||||
Map<Permissible, Boolean> result = super.get(key);
|
||||
|
||||
LPSubscriptionValueMap result = (LPSubscriptionValueMap) super.get(key);
|
||||
if (result == null) {
|
||||
// calculate a new map - always!
|
||||
result = new LPSubscriptionValueMap(permission);
|
||||
super.put(permission, result);
|
||||
} else if (!(result instanceof LPSubscriptionValueMap)) {
|
||||
// ensure return type is a LPSubscriptionMap
|
||||
result = new LPSubscriptionValueMap(permission, result);
|
||||
super.put(permission, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -121,6 +120,21 @@ public final class LPSubscriptionMap extends HashMap<String, Map<Permissible, Bo
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends Map<Permissible, Boolean>> m) {
|
||||
m.forEach(this::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Permissible, Boolean> putIfAbsent(String key, Map<Permissible, Boolean> value) {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Permissible, Boolean> computeIfAbsent(String key, Function<? super String, ? extends Map<Permissible, Boolean>> mappingFunction) {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
// if the key isn't null and is a string, #get will always return a value for it
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
@@ -133,17 +147,11 @@ public final class LPSubscriptionMap extends HashMap<String, Map<Permissible, Bo
|
||||
* @return a standard representation of this map
|
||||
*/
|
||||
public Map<String, Map<Permissible, Boolean>> detach() {
|
||||
Map<String, Map<Permissible, Boolean>> ret = new HashMap<>();
|
||||
|
||||
Map<String, Map<Permissible, Boolean>> map = new HashMap<>();
|
||||
for (Map.Entry<String, Map<Permissible, Boolean>> ent : entrySet()) {
|
||||
if (ent.getValue() instanceof LPSubscriptionValueMap) {
|
||||
ret.put(ent.getKey(), ((LPSubscriptionValueMap) ent.getValue()).backing);
|
||||
} else {
|
||||
ret.put(ent.getKey(), ent.getValue());
|
||||
}
|
||||
map.put(ent.getKey(), new WeakHashMap<>(((LPSubscriptionValueMap) ent.getValue()).backing));
|
||||
}
|
||||
|
||||
return ret;
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,7 +167,7 @@ public final class LPSubscriptionMap extends HashMap<String, Map<Permissible, Bo
|
||||
|
||||
private LPSubscriptionValueMap(String permission, Map<Permissible, Boolean> backing) {
|
||||
this.permission = permission;
|
||||
this.backing = new WeakHashMap<>(backing);
|
||||
this.backing = Collections.synchronizedMap(new WeakHashMap<>(backing));
|
||||
|
||||
// remove all players from the map
|
||||
this.backing.keySet().removeIf(p -> p instanceof Player);
|
||||
@@ -167,7 +175,7 @@ public final class LPSubscriptionMap extends HashMap<String, Map<Permissible, Bo
|
||||
|
||||
public LPSubscriptionValueMap(String permission) {
|
||||
this.permission = permission;
|
||||
this.backing = new WeakHashMap<>();
|
||||
this.backing = Collections.synchronizedMap(new WeakHashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -218,21 +226,28 @@ public final class LPSubscriptionMap extends HashMap<String, Map<Permissible, Bo
|
||||
|
||||
@Override
|
||||
public @NonNull Set<Permissible> keySet() {
|
||||
// gather players (LPPermissibles)
|
||||
Set<Permissible> players = LPSubscriptionMap.this.plugin.getBootstrap().getServer().getOnlinePlayers().stream()
|
||||
.filter(player -> player.hasPermission(this.permission) || player.isPermissionSet(this.permission))
|
||||
.collect(Collectors.toSet());
|
||||
// start with the backing set
|
||||
Set<Permissible> set;
|
||||
synchronized (this.backing) {
|
||||
set = new HashSet<>(this.backing.keySet());
|
||||
}
|
||||
|
||||
// then combine the players with the backing map
|
||||
return Sets.union(players, this.backing.keySet());
|
||||
// add any online players who meet requirements
|
||||
for (Player player : LuckPermsSubscriptionMap.this.plugin.getBootstrap().getServer().getOnlinePlayers()) {
|
||||
if (player.hasPermission(this.permission) || player.isPermissionSet(this.permission)) {
|
||||
set.add(player);
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Set<Entry<Permissible, Boolean>> entrySet() {
|
||||
return keySet().stream()
|
||||
.map(p -> {
|
||||
Boolean ret = get(p);
|
||||
return ret != null ? Maps.immutableEntry(p, ret) : null;
|
||||
.map(key -> {
|
||||
Boolean value = get(key);
|
||||
return value != null ? Maps.immutableEntry(key, value) : null;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(ImmutableCollectors.toSet());
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.listeners;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.api.implementation.ApiUser;
|
||||
import me.lucko.luckperms.common.event.LuckPermsEventListener;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
|
||||
import net.luckperms.api.event.EventBus;
|
||||
import net.luckperms.api.event.context.ContextUpdateEvent;
|
||||
import net.luckperms.api.event.user.UserDataRecalculateEvent;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implements the LuckPerms auto op feature.
|
||||
*/
|
||||
public class BukkitAutoOpListener implements LuckPermsEventListener {
|
||||
private static final String NODE = "luckperms.autoop";
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public BukkitAutoOpListener(LPBukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(EventBus bus) {
|
||||
bus.subscribe(UserDataRecalculateEvent.class, this::onUserDataRecalculate);
|
||||
bus.subscribe(ContextUpdateEvent.class, this::onContextUpdate);
|
||||
}
|
||||
|
||||
private void onUserDataRecalculate(UserDataRecalculateEvent e) {
|
||||
User user = ApiUser.cast(e.getUser());
|
||||
this.plugin.getBootstrap().getPlayer(user.getUniqueId()).ifPresent(p -> refreshAutoOp(p, false));
|
||||
}
|
||||
|
||||
private void onContextUpdate(ContextUpdateEvent e) {
|
||||
e.getSubject(Player.class).ifPresent(p -> refreshAutoOp(p, true));
|
||||
}
|
||||
|
||||
private void refreshAutoOp(Player player, boolean callerIsSync) {
|
||||
if (!callerIsSync && this.plugin.getBootstrap().isServerStopping()) {
|
||||
return;
|
||||
}
|
||||
|
||||
User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId());
|
||||
|
||||
boolean value;
|
||||
if (user != null) {
|
||||
QueryOptions queryOptions = this.plugin.getContextManager().getQueryOptions(player);
|
||||
Map<String, Boolean> permData = user.getCachedData().getPermissionData(queryOptions).getPermissionMap();
|
||||
value = permData.getOrDefault(NODE, false);
|
||||
} else {
|
||||
value = false;
|
||||
}
|
||||
|
||||
if (callerIsSync) {
|
||||
player.setOp(value);
|
||||
} else {
|
||||
this.plugin.getBootstrap().getScheduler().executeSync(() -> player.setOp(value));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.listeners;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.cache.BufferedRequest;
|
||||
import me.lucko.luckperms.common.event.LuckPermsEventListener;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
|
||||
import net.luckperms.api.event.EventBus;
|
||||
import net.luckperms.api.event.context.ContextUpdateEvent;
|
||||
import net.luckperms.api.event.user.UserDataRecalculateEvent;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Calls {@link Player#updateCommands()} when a players permissions change.
|
||||
*/
|
||||
public class BukkitCommandListUpdater implements LuckPermsEventListener {
|
||||
|
||||
public static boolean isSupported() {
|
||||
try {
|
||||
Player.class.getMethod("updateCommands");
|
||||
return true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
private final LoadingCache<UUID, SendBuffer> sendingBuffers = CaffeineFactory.newBuilder()
|
||||
.expireAfterAccess(10, TimeUnit.SECONDS)
|
||||
.build(SendBuffer::new);
|
||||
|
||||
public BukkitCommandListUpdater(LPBukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(EventBus bus) {
|
||||
bus.subscribe(UserDataRecalculateEvent.class, this::onUserDataRecalculate);
|
||||
bus.subscribe(ContextUpdateEvent.class, this::onContextUpdate);
|
||||
}
|
||||
|
||||
private void onUserDataRecalculate(UserDataRecalculateEvent e) {
|
||||
requestUpdate(e.getUser().getUniqueId());
|
||||
}
|
||||
|
||||
private void onContextUpdate(ContextUpdateEvent e) {
|
||||
e.getSubject(Player.class).ifPresent(p -> requestUpdate(p.getUniqueId()));
|
||||
}
|
||||
|
||||
private void requestUpdate(UUID uniqueId) {
|
||||
if (this.plugin.getBootstrap().isServerStopping()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.plugin.getBootstrap().isPlayerOnline(uniqueId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Buffer the request to send a commands update.
|
||||
this.sendingBuffers.get(uniqueId).request();
|
||||
}
|
||||
|
||||
// Called when the buffer times out.
|
||||
private void sendUpdate(UUID uniqueId) {
|
||||
if (this.plugin.getBootstrap().isServerStopping()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.plugin.getBootstrap().getScheduler().sync()
|
||||
.execute(() -> this.plugin.getBootstrap().getPlayer(uniqueId).ifPresent(Player::updateCommands));
|
||||
}
|
||||
|
||||
private final class SendBuffer extends BufferedRequest<Void> {
|
||||
private final UUID uniqueId;
|
||||
|
||||
SendBuffer(UUID uniqueId) {
|
||||
super(500, TimeUnit.MILLISECONDS, BukkitCommandListUpdater.this.plugin.getBootstrap().getScheduler());
|
||||
this.uniqueId = uniqueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void perform() {
|
||||
sendUpdate(this.uniqueId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
-7
@@ -26,7 +26,7 @@
|
||||
package me.lucko.luckperms.bukkit.listeners;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.bukkit.inject.permissible.LPPermissible;
|
||||
import me.lucko.luckperms.bukkit.inject.permissible.LuckPermsPermissible;
|
||||
import me.lucko.luckperms.bukkit.inject.permissible.PermissibleInjector;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.locale.message.Message;
|
||||
@@ -81,7 +81,8 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onPlayerPreLogin(AsyncPlayerPreLoginEvent e) {
|
||||
/* Called when the player first attempts a connection with the server.
|
||||
Listening on LOW priority to allow plugins to modify username / UUID data here. (auth plugins) */
|
||||
Listening on LOW priority to allow plugins to modify username / UUID data here. (auth plugins)
|
||||
Also, give other plugins a chance to cancel the event. */
|
||||
|
||||
/* wait for the plugin to enable. because these events are fired async, they can be called before
|
||||
the plugin has enabled. */
|
||||
@@ -95,6 +96,13 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
this.plugin.getLogger().info("Processing pre-login for " + e.getUniqueId() + " - " + e.getName());
|
||||
}
|
||||
|
||||
if (e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
|
||||
// another plugin has disallowed the login.
|
||||
this.plugin.getLogger().info("Another plugin has cancelled the connection for " + e.getUniqueId() + " - " + e.getName() + ". No permissions data will be loaded.");
|
||||
this.deniedAsyncLogin.add(e.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
/* Actually process the login for the connection.
|
||||
We do this here to delay the login until the data is ready.
|
||||
If the login gets cancelled later on, then this will be cleaned up.
|
||||
@@ -107,7 +115,7 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
try {
|
||||
User user = loadUser(e.getUniqueId(), e.getName());
|
||||
recordConnection(e.getUniqueId());
|
||||
this.plugin.getEventFactory().handlePlayerLoginProcess(e.getUniqueId(), e.getName(), user);
|
||||
this.plugin.getEventDispatcher().dispatchPlayerLoginProcess(e.getUniqueId(), e.getName(), user);
|
||||
} catch (Exception ex) {
|
||||
this.plugin.getLogger().severe("Exception occurred whilst loading data for " + e.getUniqueId() + " - " + e.getName());
|
||||
ex.printStackTrace();
|
||||
@@ -115,7 +123,7 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
// deny the connection
|
||||
this.deniedAsyncLogin.add(e.getUniqueId());
|
||||
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_DATABASE_ERROR.asString(this.plugin.getLocaleManager()));
|
||||
this.plugin.getEventFactory().handlePlayerLoginProcess(e.getUniqueId(), e.getName(), null);
|
||||
this.plugin.getEventDispatcher().dispatchPlayerLoginProcess(e.getUniqueId(), e.getName(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +187,7 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
// Care should be taken at this stage to ensure that async tasks which manipulate bukkit data check that the player is still online.
|
||||
try {
|
||||
// Make a new permissible for the user
|
||||
LPPermissible lpPermissible = new LPPermissible(player, user, this.plugin);
|
||||
LuckPermsPermissible lpPermissible = new LuckPermsPermissible(player, user, this.plugin);
|
||||
|
||||
// Inject into the player
|
||||
PermissibleInjector.inject(player, lpPermissible);
|
||||
@@ -193,7 +201,7 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
return;
|
||||
}
|
||||
|
||||
this.plugin.refreshAutoOp(player, true);
|
||||
this.plugin.getContextManager().signalContextUpdate(player);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
@@ -219,7 +227,7 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
|
||||
// perform unhooking from bukkit objects 1 tick later.
|
||||
// this allows plugins listening after us on MONITOR to still have intact permissions data
|
||||
this.plugin.getBootstrap().getServer().getScheduler().runTaskLaterAsynchronously(this.plugin.getBootstrap(), () -> {
|
||||
this.plugin.getBootstrap().getServer().getScheduler().runTaskLater(this.plugin.getBootstrap(), () -> {
|
||||
// Remove the custom permissible
|
||||
try {
|
||||
PermissibleInjector.uninject(player, true);
|
||||
|
||||
+10
-22
@@ -32,38 +32,40 @@ import me.lucko.luckperms.common.locale.message.Message;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.server.PluginEnableEvent;
|
||||
import org.bukkit.event.server.RemoteServerCommandEvent;
|
||||
import org.bukkit.event.server.ServerCommandEvent;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class BukkitPlatformListener implements Listener {
|
||||
private static final Pattern OP_COMMAND_PATTERN = Pattern.compile("^/?(\\w+:)?(deop|op)( .*)?$");
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public BukkitPlatformListener(LPBukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onPlayerCommand(PlayerCommandPreprocessEvent e) {
|
||||
handleCommand(e.getPlayer(), e.getMessage().toLowerCase(), e);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onServerCommand(ServerCommandEvent e) {
|
||||
handleCommand(e.getSender(), e.getCommand().toLowerCase(), e);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onRemoteServerCommand(RemoteServerCommandEvent e) {
|
||||
handleCommand(e.getSender(), e.getCommand().toLowerCase(), e);
|
||||
}
|
||||
|
||||
private void handleCommand(CommandSender sender, String s, Cancellable event) {
|
||||
if (s.isEmpty()) {
|
||||
private void handleCommand(CommandSender sender, String cmdLine, Cancellable event) {
|
||||
if (cmdLine.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -71,15 +73,7 @@ public class BukkitPlatformListener implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s.charAt(0) == '/') {
|
||||
s = s.substring(1);
|
||||
}
|
||||
|
||||
if (s.contains(":")) {
|
||||
s = s.substring(s.indexOf(':') + 1);
|
||||
}
|
||||
|
||||
if (s.equals("op") || s.startsWith("op ") || s.equals("deop") || s.startsWith("deop ")) {
|
||||
if (OP_COMMAND_PATTERN.matcher(cmdLine).matches()) {
|
||||
event.setCancelled(true);
|
||||
sender.sendMessage(Message.OP_DISABLED.asString(this.plugin.getLocaleManager()));
|
||||
}
|
||||
@@ -92,10 +86,4 @@ public class BukkitPlatformListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onWorldChange(PlayerChangedWorldEvent e) {
|
||||
this.plugin.getContextManager().invalidateCache(e.getPlayer());
|
||||
this.plugin.refreshAutoOp(e.getPlayer(), true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,8 +32,9 @@ import de.bananaco.bpermissions.api.World;
|
||||
import de.bananaco.bpermissions.api.WorldManager;
|
||||
|
||||
import me.lucko.luckperms.common.command.CommandResult;
|
||||
import me.lucko.luckperms.common.command.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentList;
|
||||
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.command.CommandSpec;
|
||||
@@ -61,13 +62,12 @@ import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class MigrationBPermissions extends SubCommand<Object> {
|
||||
public class MigrationBPermissions extends ChildCommand<Object> {
|
||||
private static final Field UCONFIG_FIELD;
|
||||
static {
|
||||
try {
|
||||
@@ -83,7 +83,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) {
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object ignored, ArgumentList args, String label) {
|
||||
ProgressLogger log = new ProgressLogger(Message.MIGRATION_LOG, Message.MIGRATION_LOG_PROGRESS, "bPermissions");
|
||||
log.addListener(plugin.getConsoleSender());
|
||||
log.addListener(sender);
|
||||
@@ -182,6 +182,8 @@ public class MigrationBPermissions extends SubCommand<Object> {
|
||||
});
|
||||
|
||||
log.log("Success! Migration complete.");
|
||||
log.log("Don't forget to remove the bPermissions jar from your plugins folder & restart the server. " +
|
||||
"LuckPerms may not take over as the server permission handler until this is done.");
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,8 +26,9 @@
|
||||
package me.lucko.luckperms.bukkit.migration;
|
||||
|
||||
import me.lucko.luckperms.common.command.CommandResult;
|
||||
import me.lucko.luckperms.common.command.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentList;
|
||||
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.command.CommandSpec;
|
||||
@@ -68,13 +69,13 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MigrationGroupManager extends SubCommand<Object> {
|
||||
public class MigrationGroupManager extends ChildCommand<Object> {
|
||||
public MigrationGroupManager(LocaleManager locale) {
|
||||
super(CommandSpec.MIGRATION_GROUPMANAGER.localize(locale), "groupmanager", CommandPermission.MIGRATION, Predicates.is(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) {
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object ignored, ArgumentList args, String label) {
|
||||
ProgressLogger log = new ProgressLogger(Message.MIGRATION_LOG, Message.MIGRATION_LOG_PROGRESS, "GroupManager");
|
||||
log.addListener(plugin.getConsoleSender());
|
||||
log.addListener(sender);
|
||||
@@ -86,7 +87,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
final boolean migrateAsGlobal = Boolean.parseBoolean(args.get(0));
|
||||
final Function<String, String> worldMappingFunc = s -> migrateAsGlobal ? null : s;
|
||||
final Function<String, String> worldMappingFunc = s -> migrateAsGlobal || s == null ? "global" : s;
|
||||
|
||||
if (!Bukkit.getPluginManager().isPluginEnabled("GroupManager")) {
|
||||
log.logError("Plugin not loaded.");
|
||||
@@ -145,7 +146,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
}
|
||||
for (String s : group.getInherits()) {
|
||||
if (s.isEmpty()) continue;
|
||||
groups.get(groupName).add(Inheritance.builder(MigrationUtils.standardizeName(s)).value(true).withContext(DefaultContextKeys.SERVER_KEY, null).withContext(DefaultContextKeys.WORLD_KEY, worldMappingFunc.apply(world)).build());
|
||||
groups.get(groupName).add(Inheritance.builder(MigrationUtils.standardizeName(s)).value(true).withContext(DefaultContextKeys.WORLD_KEY, worldMappingFunc.apply(world)).build());
|
||||
}
|
||||
|
||||
String[] metaKeys = group.getVariables().getVarKeyList();
|
||||
@@ -262,6 +263,8 @@ public class MigrationGroupManager extends SubCommand<Object> {
|
||||
|
||||
log.log("Migrated " + userCount.get() + " users.");
|
||||
log.log("Success! Migration complete.");
|
||||
log.log("Don't forget to remove the GroupManager jar from your plugins folder & restart the server. " +
|
||||
"LuckPerms may not take over as the server permission handler until this is done.");
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -28,8 +28,9 @@ package me.lucko.luckperms.bukkit.migration;
|
||||
import com.platymuus.bukkit.permissions.PermissionsPlugin;
|
||||
|
||||
import me.lucko.luckperms.common.command.CommandResult;
|
||||
import me.lucko.luckperms.common.command.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentList;
|
||||
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.command.CommandSpec;
|
||||
@@ -56,13 +57,13 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class MigrationPermissionsBukkit extends SubCommand<Object> {
|
||||
public class MigrationPermissionsBukkit extends ChildCommand<Object> {
|
||||
public MigrationPermissionsBukkit(LocaleManager locale) {
|
||||
super(CommandSpec.MIGRATION_COMMAND.localize(locale), "permissionsbukkit", CommandPermission.MIGRATION, Predicates.alwaysFalse());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) {
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object ignored, ArgumentList args, String label) {
|
||||
ProgressLogger log = new ProgressLogger(Message.MIGRATION_LOG, Message.MIGRATION_LOG_PROGRESS, "PermissionsBukkit");
|
||||
log.addListener(plugin.getConsoleSender());
|
||||
log.addListener(sender);
|
||||
@@ -123,6 +124,8 @@ public class MigrationPermissionsBukkit extends SubCommand<Object> {
|
||||
|
||||
log.log("Migrated " + userCount.get() + " users.");
|
||||
log.log("Success! Migration complete.");
|
||||
log.log("Don't forget to remove the PermissionsBukkit jar from your plugins folder & restart the server. " +
|
||||
"LuckPerms may not take over as the server permission handler until this is done.");
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
+108
-13
@@ -28,8 +28,9 @@ package me.lucko.luckperms.bukkit.migration;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import me.lucko.luckperms.common.command.CommandResult;
|
||||
import me.lucko.luckperms.common.command.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentList;
|
||||
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.command.CommandSpec;
|
||||
@@ -52,19 +53,24 @@ import me.lucko.luckperms.common.util.ProgressLogger;
|
||||
import net.luckperms.api.context.DefaultContextKeys;
|
||||
import net.luckperms.api.event.cause.CreationCause;
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.types.InheritanceNode;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import ru.tehkode.permissions.NativeInterface;
|
||||
import ru.tehkode.permissions.PermissionEntity;
|
||||
import ru.tehkode.permissions.PermissionGroup;
|
||||
import ru.tehkode.permissions.PermissionManager;
|
||||
import ru.tehkode.permissions.PermissionUser;
|
||||
import ru.tehkode.permissions.PermissionsData;
|
||||
import ru.tehkode.permissions.bukkit.PermissionsEx;
|
||||
import ru.tehkode.permissions.events.PermissionEvent;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -74,10 +80,11 @@ import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
public class MigrationPermissionsEx extends ChildCommand<Object> {
|
||||
private static final Method GET_DATA_METHOD;
|
||||
private static final Field TIMED_PERMISSIONS_FIELD;
|
||||
private static final Field TIMED_PERMISSIONS_TIME_FIELD;
|
||||
private static final Field NATIVE_INTERFACE_FIELD;
|
||||
static {
|
||||
try {
|
||||
GET_DATA_METHOD = PermissionEntity.class.getDeclaredMethod("getData");
|
||||
@@ -88,6 +95,9 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
|
||||
TIMED_PERMISSIONS_TIME_FIELD = PermissionEntity.class.getDeclaredField("timedPermissionsTime");
|
||||
TIMED_PERMISSIONS_TIME_FIELD.setAccessible(true);
|
||||
|
||||
NATIVE_INTERFACE_FIELD = PermissionManager.class.getDeclaredField("nativeI");
|
||||
NATIVE_INTERFACE_FIELD.setAccessible(true);
|
||||
} catch (NoSuchMethodException | NoSuchFieldException e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
@@ -98,7 +108,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) {
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object ignored, ArgumentList args, String label) {
|
||||
ProgressLogger log = new ProgressLogger(Message.MIGRATION_LOG, Message.MIGRATION_LOG_PROGRESS, "PermissionsEx");
|
||||
log.addListener(plugin.getConsoleSender());
|
||||
log.addListener(sender);
|
||||
@@ -113,6 +123,13 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
PermissionsEx pex = (PermissionsEx) Bukkit.getPluginManager().getPlugin("PermissionsEx");
|
||||
PermissionManager manager = pex.getPermissionsManager();
|
||||
|
||||
// hack to work around accessing pex async
|
||||
try {
|
||||
disablePexEvents(manager);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
log.log("Calculating group weightings.");
|
||||
int i = 0;
|
||||
for (PermissionGroup group : manager.getGroupList()) {
|
||||
@@ -168,8 +185,14 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
// Increment the max weight from the group migrations. All user meta should override.
|
||||
int userWeight = maxWeight + 5;
|
||||
|
||||
Iterators.tryIterate(manager.getUsers(), user -> {
|
||||
UUID u = BukkitUuids.lookupUuid(log, user.getIdentifier());
|
||||
Collection<String> userIdentifiers = manager.getBackend().getUserIdentifiers();
|
||||
Iterators.tryIterate(userIdentifiers, id -> {
|
||||
PermissionUser user = new PermissionUser(id, manager.getBackend().getUserData(id), manager);
|
||||
if (isUserEmpty(user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID u = BukkitUuids.lookupUuid(log, id);
|
||||
if (u == null) {
|
||||
return;
|
||||
}
|
||||
@@ -185,8 +208,17 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
log.logProgress("Migrated {} users so far.", userCount.incrementAndGet(), ProgressLogger.DEFAULT_NOTIFY_FREQUENCY);
|
||||
});
|
||||
|
||||
// re-enable events
|
||||
try {
|
||||
enablePexEvents(manager);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
log.log("Migrated " + userCount.get() + " users.");
|
||||
log.log("Success! Migration complete.");
|
||||
log.log("Don't forget to remove the PermissionsEx jar from your plugins folder & restart the server. " +
|
||||
"LuckPerms may not take over as the server permission handler until this is done.");
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -199,6 +231,28 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isUserEmpty(PermissionUser user) {
|
||||
for (List<String> permissions : user.getAllPermissions().values()) {
|
||||
if (!permissions.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (List<PermissionGroup> parents : user.getAllParents().values()) {
|
||||
if (!parents.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (Map<String, String> options : user.getAllOptions().values()) {
|
||||
if (!options.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void migrateEntity(PermissionEntity entity, PermissionHolder holder, int weight) {
|
||||
// migrate permanent permissions
|
||||
for (Map.Entry<String, List<String>> worldData : getPermanentPermissions(entity).entrySet()) {
|
||||
@@ -227,7 +281,10 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
for (String node : worldData.getValue()) {
|
||||
if (node.isEmpty()) continue;
|
||||
long expiry = timedPermissionsTime.getOrDefault(Strings.nullToEmpty(world) + ":" + node, 0L);
|
||||
holder.setNode(DataType.NORMAL, MigrationUtils.parseNode(node, true).withContext(DefaultContextKeys.WORLD_KEY, world).expiry(expiry).build(), true);
|
||||
Node n = MigrationUtils.parseNode(node, true).withContext(DefaultContextKeys.WORLD_KEY, world).expiry(expiry).build();
|
||||
if (!n.hasExpired()) {
|
||||
holder.setNode(DataType.NORMAL, n, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,10 +312,15 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
holder.setNode(DataType.NORMAL, Inheritance.builder(MigrationUtils.standardizeName(parentName)).withContext(DefaultContextKeys.WORLD_KEY, world).expiry(expiry).build(), true);
|
||||
InheritanceNode n = Inheritance.builder(MigrationUtils.standardizeName(parentName)).withContext(DefaultContextKeys.WORLD_KEY, world).expiry(expiry).build();
|
||||
if (n.hasExpired()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
holder.setNode(DataType.NORMAL, n, true);
|
||||
|
||||
// migrate primary groups
|
||||
if (world == null && holder instanceof User && expiry == 0) {
|
||||
if (world.equals("global") && holder instanceof User && expiry == 0) {
|
||||
if (parent.getRank() < primaryWeight) {
|
||||
primary = parent.getName();
|
||||
primaryWeight = parent.getRank();
|
||||
@@ -313,12 +375,45 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
|
||||
}
|
||||
|
||||
private static String standardizeWorld(String world) {
|
||||
if (world != null && (world.isEmpty() || world.equals("*"))) {
|
||||
world = null;
|
||||
if (world == null || world.isEmpty() || world.equals("*")) {
|
||||
world = "global";
|
||||
}
|
||||
if (world != null) {
|
||||
world = world.toLowerCase();
|
||||
return world.toLowerCase();
|
||||
}
|
||||
|
||||
/*
|
||||
* Hack to workaround issue with accessing PEX async.
|
||||
* See: https://github.com/lucko/LuckPerms/issues/2102
|
||||
*/
|
||||
|
||||
private static void disablePexEvents(PermissionManager manager) throws ReflectiveOperationException {
|
||||
NativeInterface nativeInterface = (NativeInterface) NATIVE_INTERFACE_FIELD.get(manager);
|
||||
NATIVE_INTERFACE_FIELD.set(manager, new DisabledEventsNativeInterface(nativeInterface));
|
||||
}
|
||||
|
||||
private static void enablePexEvents(PermissionManager manager) throws ReflectiveOperationException {
|
||||
NativeInterface nativeInterface = (NativeInterface) NATIVE_INTERFACE_FIELD.get(manager);
|
||||
while (nativeInterface instanceof DisabledEventsNativeInterface) {
|
||||
nativeInterface = ((DisabledEventsNativeInterface) nativeInterface).delegate;
|
||||
NATIVE_INTERFACE_FIELD.set(manager, nativeInterface);
|
||||
}
|
||||
return world;
|
||||
}
|
||||
|
||||
private static final class DisabledEventsNativeInterface implements NativeInterface {
|
||||
private final NativeInterface delegate;
|
||||
|
||||
private DisabledEventsNativeInterface(NativeInterface delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callEvent(PermissionEvent permissionEvent) {
|
||||
// do nothing!
|
||||
}
|
||||
|
||||
@Override public String UUIDToName(UUID uuid) { return this.delegate.UUIDToName(uuid); }
|
||||
@Override public UUID nameToUUID(String s) { return this.delegate.nameToUUID(s); }
|
||||
@Override public boolean isOnline(UUID uuid) { return this.delegate.isOnline(uuid); }
|
||||
@Override public UUID getServerUUID() { return this.delegate.getServerUUID(); }
|
||||
}
|
||||
}
|
||||
+10
-7
@@ -34,8 +34,9 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
|
||||
import me.lucko.luckperms.common.command.CommandResult;
|
||||
import me.lucko.luckperms.common.command.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentList;
|
||||
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
@@ -78,13 +79,13 @@ import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
// Only supports the latest versions of the PP API. (it seems to change randomly almost every release)
|
||||
public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
public class MigrationPowerfulPerms extends ChildCommand<Object> {
|
||||
public MigrationPowerfulPerms(LocaleManager locale) {
|
||||
super(CommandSpec.MIGRATION_POWERFULPERMS.localize(locale), "powerfulperms", CommandPermission.MIGRATION, Predicates.not(5));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) {
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object ignored, ArgumentList args, String label) {
|
||||
ProgressLogger log = new ProgressLogger(Message.MIGRATION_LOG, Message.MIGRATION_LOG_PROGRESS, "PowerfulPerms");
|
||||
log.addListener(plugin.getConsoleSender());
|
||||
log.addListener(sender);
|
||||
@@ -275,6 +276,8 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
|
||||
log.log("Migrated " + userCount.get() + " users.");
|
||||
log.log("Success! Migration complete.");
|
||||
log.log("Don't forget to remove the PowerfulPerms jar from your plugins folder & restart the server. " +
|
||||
"LuckPerms may not take over as the server permission handler until this is done.");
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -291,12 +294,12 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
}
|
||||
|
||||
String server = p.getServer();
|
||||
if (server != null && (server.equalsIgnoreCase("all") || server.equalsIgnoreCase("*"))) {
|
||||
if (server != null && (server.equalsIgnoreCase("all") || server.equalsIgnoreCase("*") || server.isEmpty())) {
|
||||
server = null;
|
||||
}
|
||||
|
||||
String world = p.getWorld();
|
||||
if (world != null && (world.equalsIgnoreCase("all") || world.equalsIgnoreCase("*"))) {
|
||||
if (world != null && (world.equalsIgnoreCase("all") || world.equalsIgnoreCase("*") || world.isEmpty())) {
|
||||
world = null;
|
||||
}
|
||||
|
||||
@@ -309,7 +312,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
server = "global";
|
||||
}
|
||||
|
||||
NodeBuilder nb = NodeBuilders.determineMostApplicable(node).value(value);
|
||||
NodeBuilder<?, ?> nb = NodeBuilders.determineMostApplicable(node).value(value);
|
||||
if (expireAt != 0) nb.expiry(expireAt);
|
||||
if (server != null) nb.withContext(DefaultContextKeys.SERVER_KEY, server);
|
||||
if (world != null) nb.withContext(DefaultContextKeys.WORLD_KEY, world);
|
||||
@@ -325,7 +328,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
|
||||
expireAt = g.getExpirationDate().getTime() / 1000L;
|
||||
}
|
||||
|
||||
NodeBuilder nb = Inheritance.builder(MigrationUtils.standardizeName(group.getName()));
|
||||
NodeBuilder<?, ?> nb = Inheritance.builder(MigrationUtils.standardizeName(group.getName()));
|
||||
|
||||
if (expireAt != 0) {
|
||||
nb.expiry(expireAt);
|
||||
|
||||
@@ -26,8 +26,9 @@
|
||||
package me.lucko.luckperms.bukkit.migration;
|
||||
|
||||
import me.lucko.luckperms.common.command.CommandResult;
|
||||
import me.lucko.luckperms.common.command.abstraction.SubCommand;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentList;
|
||||
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.command.CommandSpec;
|
||||
@@ -63,19 +64,18 @@ import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class MigrationZPermissions extends SubCommand<Object> {
|
||||
public class MigrationZPermissions extends ChildCommand<Object> {
|
||||
public MigrationZPermissions(LocaleManager locale) {
|
||||
super(CommandSpec.MIGRATION_COMMAND.localize(locale), "zpermissions", CommandPermission.MIGRATION, Predicates.alwaysFalse());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) {
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object ignored, ArgumentList args, String label) {
|
||||
ProgressLogger log = new ProgressLogger(Message.MIGRATION_LOG, Message.MIGRATION_LOG_PROGRESS, "zPermissions");
|
||||
log.addListener(plugin.getConsoleSender());
|
||||
log.addListener(sender);
|
||||
@@ -193,6 +193,8 @@ public class MigrationZPermissions extends SubCommand<Object> {
|
||||
|
||||
log.log("Migrated " + userCount.get() + " users.");
|
||||
log.log("Success! Migration complete.");
|
||||
log.log("Don't forget to remove the zPermissions jar from your plugins folder & restart the server. " +
|
||||
"LuckPerms may not take over as the server permission handler until this is done.");
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.util;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandMap;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public final class CommandMapUtil {
|
||||
private CommandMapUtil() {}
|
||||
|
||||
private static final Field COMMAND_MAP_FIELD;
|
||||
|
||||
static {
|
||||
try {
|
||||
COMMAND_MAP_FIELD = SimplePluginManager.class.getDeclaredField("commandMap");
|
||||
COMMAND_MAP_FIELD.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static CommandMap getCommandMap(Server server) {
|
||||
try {
|
||||
return (CommandMap) COMMAND_MAP_FIELD.get(server.getPluginManager());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not get CommandMap", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+12
-26
@@ -23,42 +23,28 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.compat;
|
||||
package me.lucko.luckperms.bukkit.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public final class CraftBukkitUtil {
|
||||
private CraftBukkitUtil() {}
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
private static final String SERVER_PACKAGE_VERSION = getServerPackageVersion();
|
||||
private static final boolean CHAT_COMPATIBLE = !SERVER_PACKAGE_VERSION.startsWith(".v1_7_");
|
||||
public final class CraftBukkitImplementation {
|
||||
private CraftBukkitImplementation() {}
|
||||
|
||||
private static String getServerPackageVersion() {
|
||||
private static final String SERVER_PACKAGE_VERSION;
|
||||
|
||||
static {
|
||||
Class<?> server = Bukkit.getServer().getClass();
|
||||
if (!server.getSimpleName().equals("CraftServer")) {
|
||||
return ".";
|
||||
}
|
||||
if (server.getName().equals("org.bukkit.craftbukkit.CraftServer")) {
|
||||
// Non versioned class
|
||||
return ".";
|
||||
Matcher matcher = Pattern.compile("^org\\.bukkit\\.craftbukkit\\.(\\w+)\\.CraftServer$").matcher(server.getName());
|
||||
if (matcher.matches()) {
|
||||
SERVER_PACKAGE_VERSION = '.' + matcher.group(1) + '.';
|
||||
} else {
|
||||
String version = server.getName().substring("org.bukkit.craftbukkit".length());
|
||||
return version.substring(0, version.length() - "CraftServer".length());
|
||||
SERVER_PACKAGE_VERSION = ".";
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isChatCompatible() {
|
||||
return CHAT_COMPATIBLE;
|
||||
}
|
||||
|
||||
public static String nms(String className) {
|
||||
return "net.minecraft.server" + SERVER_PACKAGE_VERSION + className;
|
||||
}
|
||||
|
||||
public static Class<?> nmsClass(String className) throws ClassNotFoundException {
|
||||
return Class.forName(nms(className));
|
||||
}
|
||||
|
||||
public static String obc(String className) {
|
||||
return "org.bukkit.craftbukkit" + SERVER_PACKAGE_VERSION + className;
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.compat;
|
||||
package me.lucko.luckperms.bukkit.util;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Server;
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.util;
|
||||
|
||||
import com.google.common.graph.MutableGraph;
|
||||
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public final class PluginManagerUtil {
|
||||
private PluginManagerUtil() {}
|
||||
|
||||
private static final Field DEPENDENCY_GRAPH_FIELD;
|
||||
|
||||
static {
|
||||
Field dependencyGraphField = null;
|
||||
try {
|
||||
dependencyGraphField = SimplePluginManager.class.getDeclaredField("dependencyGraph");
|
||||
dependencyGraphField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
DEPENDENCY_GRAPH_FIELD = dependencyGraphField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects a dependency relationship into the plugin manager.
|
||||
*
|
||||
* @param plugin the plugin
|
||||
* @param depend the plugin being depended on
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void injectDependency(PluginManager pluginManager, String plugin, String depend) {
|
||||
if (DEPENDENCY_GRAPH_FIELD == null || !(pluginManager instanceof SimplePluginManager)) {
|
||||
return; // fail silently
|
||||
}
|
||||
|
||||
try {
|
||||
MutableGraph<String> graph = (MutableGraph<String>) DEPENDENCY_GRAPH_FIELD.get(pluginManager);
|
||||
graph.putEdge(plugin, depend);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,7 +33,6 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* An extended abstraction of the Vault {@link Chat} API.
|
||||
@@ -45,7 +44,7 @@ import java.util.function.Function;
|
||||
* to get a result using the players username.
|
||||
*
|
||||
* Whilst this meant the old plugins would still be supported, it made the whole
|
||||
* API a total mess. This class reverses this decision, and instead upgrades
|
||||
* API a total mess. This class reverses this action, and instead upgrades
|
||||
* requests to use UUIDs. This makes implementing Vault significantly easier for modern
|
||||
* plugins, and because requests are upgraded instead of being downgraded then upgraded,
|
||||
* much faster for plugins querying data.
|
||||
@@ -53,10 +52,6 @@ import java.util.function.Function;
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class AbstractVaultChat extends Chat {
|
||||
|
||||
// when upgrading and forwarding requests, all world strings are passed through this function.
|
||||
// it lets the overriding class define some custom behaviour for world handling.
|
||||
protected Function<String, String> worldMappingFunction = Function.identity();
|
||||
|
||||
// the permission api instance
|
||||
private final AbstractVaultPermission permissionApi;
|
||||
|
||||
@@ -87,14 +82,14 @@ public abstract class AbstractVaultChat extends Chat {
|
||||
|
||||
// utility methods for parsing metadata values from strings
|
||||
|
||||
private static String strConvert(String s, String def) {
|
||||
if (s != null) {
|
||||
return s;
|
||||
private static String parseString(String s, String def) {
|
||||
if (s == null) {
|
||||
return def;
|
||||
}
|
||||
return def;
|
||||
return s;
|
||||
}
|
||||
|
||||
private static int intConvert(String s, int def) {
|
||||
private static int parseInt(String s, int def) {
|
||||
if (s == null) {
|
||||
return def;
|
||||
}
|
||||
@@ -105,7 +100,7 @@ public abstract class AbstractVaultChat extends Chat {
|
||||
}
|
||||
}
|
||||
|
||||
private static double doubleConvert(String s, double def) {
|
||||
private static double parseDouble(String s, double def) {
|
||||
if (s == null) {
|
||||
return def;
|
||||
}
|
||||
@@ -116,7 +111,7 @@ public abstract class AbstractVaultChat extends Chat {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean booleanConvert(String s, boolean def) {
|
||||
private static boolean parseBoolean(String s, boolean def) {
|
||||
if (s == null) {
|
||||
return def;
|
||||
}
|
||||
@@ -124,506 +119,508 @@ public abstract class AbstractVaultChat extends Chat {
|
||||
return true;
|
||||
} else if (s.equalsIgnoreCase("false")) {
|
||||
return false;
|
||||
} else {
|
||||
return def;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
private String world(String world) {
|
||||
return this.worldMappingFunction.apply(world);
|
||||
/* allow implementations to override and implement custom world remapping / handling rules */
|
||||
protected String convertWorld(String world) {
|
||||
return world;
|
||||
}
|
||||
|
||||
private String world(Player player) {
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
return world(player.getWorld());
|
||||
}
|
||||
|
||||
private String world(World world) {
|
||||
private String convertWorld(World world) {
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
return world(world.getName());
|
||||
return convertWorld(world.getName());
|
||||
}
|
||||
|
||||
private String convertWorld(Player player) {
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
return convertWorld(player.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerPrefix(String world, String player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return getUserChatPrefix(world(world), this.permissionApi.lookupUuid(player));
|
||||
return getUserChatPrefix(convertWorld(world), this.permissionApi.lookupUuid(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerPrefix(String world, OfflinePlayer player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return getUserChatPrefix(world(world), player.getUniqueId());
|
||||
return getUserChatPrefix(convertWorld(world), player.getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerPrefix(World world, String player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return getUserChatPrefix(world(world), this.permissionApi.lookupUuid(player));
|
||||
return getUserChatPrefix(convertWorld(world), this.permissionApi.lookupUuid(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerPrefix(Player player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return getUserChatPrefix(world(player), ((OfflinePlayer) player).getUniqueId());
|
||||
return getUserChatPrefix(convertWorld(player), ((OfflinePlayer) player).getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerPrefix(String world, String player, String prefix) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
setUserChatPrefix(world(world), this.permissionApi.lookupUuid(player), prefix);
|
||||
setUserChatPrefix(convertWorld(world), this.permissionApi.lookupUuid(player), prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerPrefix(String world, OfflinePlayer player, String prefix) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
setUserChatPrefix(world(world), player.getUniqueId(), prefix);
|
||||
setUserChatPrefix(convertWorld(world), player.getUniqueId(), prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerPrefix(World world, String player, String prefix) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
setUserChatPrefix(world(world), this.permissionApi.lookupUuid(player), prefix);
|
||||
setUserChatPrefix(convertWorld(world), this.permissionApi.lookupUuid(player), prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerPrefix(Player player, String prefix) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
setUserChatPrefix(world(player), ((OfflinePlayer) player).getUniqueId(), prefix);
|
||||
setUserChatPrefix(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerSuffix(String world, String player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return getUserChatSuffix(world(world), this.permissionApi.lookupUuid(player));
|
||||
return getUserChatSuffix(convertWorld(world), this.permissionApi.lookupUuid(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerSuffix(String world, OfflinePlayer player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return getUserChatSuffix(world(world), player.getUniqueId());
|
||||
return getUserChatSuffix(convertWorld(world), player.getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerSuffix(World world, String player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return getUserChatSuffix(world(world), this.permissionApi.lookupUuid(player));
|
||||
return getUserChatSuffix(convertWorld(world), this.permissionApi.lookupUuid(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerSuffix(Player player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return getUserChatSuffix(world(player), ((OfflinePlayer) player).getUniqueId());
|
||||
return getUserChatSuffix(convertWorld(player), ((OfflinePlayer) player).getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerSuffix(String world, String player, String suffix) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
setUserChatSuffix(world(world), this.permissionApi.lookupUuid(player), suffix);
|
||||
setUserChatSuffix(convertWorld(world), this.permissionApi.lookupUuid(player), suffix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerSuffix(String world, OfflinePlayer player, String suffix) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
setUserChatSuffix(world(world), player.getUniqueId(), suffix);
|
||||
setUserChatSuffix(convertWorld(world), player.getUniqueId(), suffix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerSuffix(World world, String player, String suffix) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
setUserChatSuffix(world(world), this.permissionApi.lookupUuid(player), suffix);
|
||||
setUserChatSuffix(convertWorld(world), this.permissionApi.lookupUuid(player), suffix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerSuffix(Player player, String suffix) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
setUserChatSuffix(world(player), ((OfflinePlayer) player).getUniqueId(), suffix);
|
||||
setUserChatSuffix(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), suffix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getGroupPrefix(String world, String group) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
return getGroupChatPrefix(world(world), group);
|
||||
return getGroupChatPrefix(convertWorld(world), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getGroupPrefix(World world, String group) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
return getGroupChatPrefix(world(world), group);
|
||||
return getGroupChatPrefix(convertWorld(world), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupPrefix(String world, String group, String prefix) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
setGroupChatPrefix(world(world), group, prefix);
|
||||
setGroupChatPrefix(convertWorld(world), group, prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupPrefix(World world, String group, String prefix) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
setGroupChatPrefix(world(world), group, prefix);
|
||||
setGroupChatPrefix(convertWorld(world), group, prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getGroupSuffix(String world, String group) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
return getGroupChatSuffix(world(world), group);
|
||||
return getGroupChatSuffix(convertWorld(world), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getGroupSuffix(World world, String group) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
return getGroupChatSuffix(world(world), group);
|
||||
return getGroupChatSuffix(convertWorld(world), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupSuffix(String world, String group, String suffix) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
setGroupChatSuffix(world(world), group, suffix);
|
||||
setGroupChatSuffix(convertWorld(world), group, suffix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupSuffix(World world, String group, String suffix) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
setGroupChatSuffix(world(world), group, suffix);
|
||||
setGroupChatSuffix(convertWorld(world), group, suffix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getPlayerInfoInteger(String world, OfflinePlayer player, String node, int defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return intConvert(getUserMeta(world(world), player.getUniqueId(), node), defaultValue);
|
||||
return parseInt(getUserMeta(convertWorld(world), player.getUniqueId(), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getPlayerInfoInteger(String world, String player, String node, int defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return intConvert(getUserMeta(world(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
return parseInt(getUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getPlayerInfoInteger(World world, String player, String node, int defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return intConvert(getUserMeta(world(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
return parseInt(getUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getPlayerInfoInteger(Player player, String node, int defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return intConvert(getUserMeta(world(player), ((OfflinePlayer) player).getUniqueId(), node), defaultValue);
|
||||
return parseInt(getUserMeta(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoInteger(String world, OfflinePlayer player, String node, int value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), player.getUniqueId(), node, value);
|
||||
setUserMeta(convertWorld(world), player.getUniqueId(), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoInteger(String world, String player, String node, int value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
setUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoInteger(World world, String player, String node, int value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
setUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoInteger(Player player, String node, int value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(player), ((OfflinePlayer) player).getUniqueId(), node, value);
|
||||
setUserMeta(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getGroupInfoInteger(String world, String group, String node, int defaultValue) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return intConvert(getGroupMeta(world(world), group, node), defaultValue);
|
||||
return parseInt(getGroupMeta(convertWorld(world), group, node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getGroupInfoInteger(World world, String group, String node, int defaultValue) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return intConvert(getGroupMeta(world(world), group, node), defaultValue);
|
||||
return parseInt(getGroupMeta(convertWorld(world), group, node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupInfoInteger(String world, String group, String node, int value) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setGroupMeta(world(world), group, node, value);
|
||||
setGroupMeta(convertWorld(world), group, node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupInfoInteger(World world, String group, String node, int value) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setGroupMeta(world(world), group, node, value);
|
||||
setGroupMeta(convertWorld(world), group, node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getPlayerInfoDouble(String world, OfflinePlayer player, String node, double defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return doubleConvert(getUserMeta(world(world), player.getUniqueId(), node), defaultValue);
|
||||
return parseDouble(getUserMeta(convertWorld(world), player.getUniqueId(), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getPlayerInfoDouble(String world, String player, String node, double defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return doubleConvert(getUserMeta(world(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
return parseDouble(getUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getPlayerInfoDouble(World world, String player, String node, double defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return doubleConvert(getUserMeta(world(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
return parseDouble(getUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getPlayerInfoDouble(Player player, String node, double defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return doubleConvert(getUserMeta(world(player), ((OfflinePlayer) player).getUniqueId(), node), defaultValue);
|
||||
return parseDouble(getUserMeta(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoDouble(String world, OfflinePlayer player, String node, double value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), player.getUniqueId(), node, value);
|
||||
setUserMeta(convertWorld(world), player.getUniqueId(), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoDouble(String world, String player, String node, double value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
setUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoDouble(World world, String player, String node, double value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
setUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoDouble(Player player, String node, double value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(player), ((OfflinePlayer) player).getUniqueId(), node, value);
|
||||
setUserMeta(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getGroupInfoDouble(String world, String group, String node, double defaultValue) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return doubleConvert(getGroupMeta(world(world), group, node), defaultValue);
|
||||
return parseDouble(getGroupMeta(convertWorld(world), group, node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getGroupInfoDouble(World world, String group, String node, double defaultValue) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return doubleConvert(getGroupMeta(world(world), group, node), defaultValue);
|
||||
return parseDouble(getGroupMeta(convertWorld(world), group, node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupInfoDouble(String world, String group, String node, double value) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setGroupMeta(world(world), group, node, value);
|
||||
setGroupMeta(convertWorld(world), group, node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupInfoDouble(World world, String group, String node, double value) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setGroupMeta(world(world), group, node, value);
|
||||
setGroupMeta(convertWorld(world), group, node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean getPlayerInfoBoolean(String world, OfflinePlayer player, String node, boolean defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return booleanConvert(getUserMeta(world(world), player.getUniqueId(), node), defaultValue);
|
||||
return parseBoolean(getUserMeta(convertWorld(world), player.getUniqueId(), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean getPlayerInfoBoolean(String world, String player, String node, boolean defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return booleanConvert(getUserMeta(world(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
return parseBoolean(getUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean getPlayerInfoBoolean(World world, String player, String node, boolean defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return booleanConvert(getUserMeta(world(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
return parseBoolean(getUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean getPlayerInfoBoolean(Player player, String node, boolean defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return booleanConvert(getUserMeta(world(player), ((OfflinePlayer) player).getUniqueId(), node), defaultValue);
|
||||
return parseBoolean(getUserMeta(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoBoolean(String world, OfflinePlayer player, String node, boolean value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), player.getUniqueId(), node, value);
|
||||
setUserMeta(convertWorld(world), player.getUniqueId(), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoBoolean(String world, String player, String node, boolean value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
setUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoBoolean(World world, String player, String node, boolean value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
setUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoBoolean(Player player, String node, boolean value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(player), ((OfflinePlayer) player).getUniqueId(), node, value);
|
||||
setUserMeta(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean getGroupInfoBoolean(String world, String group, String node, boolean defaultValue) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return booleanConvert(getGroupMeta(world(world), group, node), defaultValue);
|
||||
return parseBoolean(getGroupMeta(convertWorld(world), group, node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean getGroupInfoBoolean(World world, String group, String node, boolean defaultValue) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return booleanConvert(getGroupMeta(world(world), group, node), defaultValue);
|
||||
return parseBoolean(getGroupMeta(convertWorld(world), group, node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupInfoBoolean(String world, String group, String node, boolean value) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setGroupMeta(world(world), group, node, value);
|
||||
setGroupMeta(convertWorld(world), group, node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupInfoBoolean(World world, String group, String node, boolean value) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setGroupMeta(world(world), group, node, value);
|
||||
setGroupMeta(convertWorld(world), group, node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerInfoString(String world, OfflinePlayer player, String node, String defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return strConvert(getUserMeta(world(world), player.getUniqueId(), node), defaultValue);
|
||||
return parseString(getUserMeta(convertWorld(world), player.getUniqueId(), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerInfoString(String world, String player, String node, String defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return strConvert(getUserMeta(world(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
return parseString(getUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerInfoString(World world, String player, String node, String defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return strConvert(getUserMeta(world(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
return parseString(getUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPlayerInfoString(Player player, String node, String defaultValue) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return strConvert(getUserMeta(world(player), ((OfflinePlayer) player).getUniqueId(), node), defaultValue);
|
||||
return parseString(getUserMeta(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoString(String world, OfflinePlayer player, String node, String value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), player.getUniqueId(), node, value);
|
||||
setUserMeta(convertWorld(world), player.getUniqueId(), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoString(String world, String player, String node, String value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
setUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoString(World world, String player, String node, String value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
setUserMeta(convertWorld(world), this.permissionApi.lookupUuid(player), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPlayerInfoString(Player player, String node, String value) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setUserMeta(world(player), ((OfflinePlayer) player).getUniqueId(), node, value);
|
||||
setUserMeta(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getGroupInfoString(String world, String group, String node, String defaultValue) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return strConvert(getGroupMeta(world(world), group, node), defaultValue);
|
||||
return parseString(getGroupMeta(convertWorld(world), group, node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getGroupInfoString(World world, String group, String node, String defaultValue) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
return strConvert(getGroupMeta(world(world), group, node), defaultValue);
|
||||
return parseString(getGroupMeta(convertWorld(world), group, node), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupInfoString(String world, String group, String node, String value) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setGroupMeta(world(world), group, node, value);
|
||||
setGroupMeta(convertWorld(world), group, node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setGroupInfoString(World world, String group, String node, String value) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(node, "node");
|
||||
setGroupMeta(world(world), group, node, value);
|
||||
setGroupMeta(convertWorld(world), group, node, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,7 +34,6 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* An extended abstraction of the Vault {@link Permission} API.
|
||||
@@ -46,18 +45,13 @@ import java.util.function.Function;
|
||||
* to get a result using the players username.
|
||||
*
|
||||
* Whilst this meant the old plugins would still be supported, it made the whole
|
||||
* API a total mess. This class reverses this decision, and instead upgrades
|
||||
* API a total mess. This class reverses this action, and instead upgrades
|
||||
* requests to use UUIDs. This makes implementing Vault significantly easier for modern
|
||||
* plugins, and because requests are upgraded instead of being downgraded then upgraded,
|
||||
* much faster for plugins querying data.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class AbstractVaultPermission extends Permission {
|
||||
|
||||
// when upgrading and forwarding requests, all world strings are passed through this function.
|
||||
// it lets the overriding class define some custom behaviour for world handling.
|
||||
protected Function<String, String> worldMappingFunction = Function.identity();
|
||||
|
||||
public AbstractVaultPermission() {
|
||||
super.plugin = JavaPlugin.getProvidingPlugin(Permission.class);
|
||||
}
|
||||
@@ -94,36 +88,37 @@ public abstract class AbstractVaultPermission extends Permission {
|
||||
public abstract boolean groupAddPermission(String world, String name, String permission);
|
||||
public abstract boolean groupRemovePermission(String world, String name, String permission);
|
||||
|
||||
private String world(String world) {
|
||||
return this.worldMappingFunction.apply(world);
|
||||
/* allow implementations to override and implement custom world remapping / handling rules */
|
||||
protected String convertWorld(String world) {
|
||||
return world;
|
||||
}
|
||||
|
||||
private String world(Player player) {
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
return world(player.getWorld());
|
||||
}
|
||||
|
||||
private String world(World world) {
|
||||
private String convertWorld(World world) {
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
return world(world.getName());
|
||||
return convertWorld(world.getName());
|
||||
}
|
||||
|
||||
private String convertWorld(Player player) {
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
return convertWorld(player.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean has(String world, String player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userHasPermission(world(world), lookupUuid(player), permission);
|
||||
return userHasPermission(convertWorld(world), lookupUuid(player), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean has(World world, String player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userHasPermission(world(world), lookupUuid(player), permission);
|
||||
return userHasPermission(convertWorld(world), lookupUuid(player), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,21 +132,21 @@ public abstract class AbstractVaultPermission extends Permission {
|
||||
public final boolean playerHas(String world, String player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userHasPermission(world(world), lookupUuid(player), permission);
|
||||
return userHasPermission(convertWorld(world), lookupUuid(player), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerHas(World world, String player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userHasPermission(world(world), lookupUuid(player), permission);
|
||||
return userHasPermission(convertWorld(world), lookupUuid(player), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerHas(String world, OfflinePlayer player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userHasPermission(world(world), player.getUniqueId(), permission);
|
||||
return userHasPermission(convertWorld(world), player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -165,229 +160,229 @@ public abstract class AbstractVaultPermission extends Permission {
|
||||
public final boolean playerAdd(String world, String player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userAddPermission(world(world), lookupUuid(player), permission);
|
||||
return userAddPermission(convertWorld(world), lookupUuid(player), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerAdd(World world, String player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userAddPermission(world(world), lookupUuid(player), permission);
|
||||
return userAddPermission(convertWorld(world), lookupUuid(player), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerAdd(String world, OfflinePlayer player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userAddPermission(world(world), player.getUniqueId(), permission);
|
||||
return userAddPermission(convertWorld(world), player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerAdd(Player player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userAddPermission(world(player), ((OfflinePlayer) player).getUniqueId(), permission);
|
||||
return userAddPermission(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerRemove(String world, String player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userRemovePermission(world(world), lookupUuid(player), permission);
|
||||
return userRemovePermission(convertWorld(world), lookupUuid(player), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerRemove(String world, OfflinePlayer player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userRemovePermission(world(world), player.getUniqueId(), permission);
|
||||
return userRemovePermission(convertWorld(world), player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerRemove(World world, String player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userRemovePermission(world(world), lookupUuid(player), permission);
|
||||
return userRemovePermission(convertWorld(world), lookupUuid(player), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerRemove(Player player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userRemovePermission(world(player), ((OfflinePlayer) player).getUniqueId(), permission);
|
||||
return userRemovePermission(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean groupHas(String world, String group, String permission) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return groupHasPermission(world(world), group, permission);
|
||||
return groupHasPermission(convertWorld(world), group, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean groupHas(World world, String group, String permission) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return groupHasPermission(world(world), group, permission);
|
||||
return groupHasPermission(convertWorld(world), group, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean groupAdd(String world, String group, String permission) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return groupAddPermission(world(world), group, permission);
|
||||
return groupAddPermission(convertWorld(world), group, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean groupAdd(World world, String group, String permission) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return groupAddPermission(world(world), group, permission);
|
||||
return groupAddPermission(convertWorld(world), group, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean groupRemove(String world, String group, String permission) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return groupRemovePermission(world(world), group, permission);
|
||||
return groupRemovePermission(convertWorld(world), group, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean groupRemove(World world, String group, String permission) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return groupRemovePermission(world(world), group, permission);
|
||||
return groupRemovePermission(convertWorld(world), group, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerInGroup(String world, String player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userInGroup(world(world), lookupUuid(player), group);
|
||||
return userInGroup(convertWorld(world), lookupUuid(player), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerInGroup(World world, String player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userInGroup(world(world), lookupUuid(player), group);
|
||||
return userInGroup(convertWorld(world), lookupUuid(player), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerInGroup(String world, OfflinePlayer player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userInGroup(world(world), player.getUniqueId(), group);
|
||||
return userInGroup(convertWorld(world), player.getUniqueId(), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerInGroup(Player player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userInGroup(world(player), ((OfflinePlayer) player).getUniqueId(), group);
|
||||
return userInGroup(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerAddGroup(String world, String player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userAddGroup(world(world), lookupUuid(player), group);
|
||||
return userAddGroup(convertWorld(world), lookupUuid(player), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerAddGroup(World world, String player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userAddGroup(world(world), lookupUuid(player), group);
|
||||
return userAddGroup(convertWorld(world), lookupUuid(player), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerAddGroup(String world, OfflinePlayer player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userAddGroup(world(world), player.getUniqueId(), group);
|
||||
return userAddGroup(convertWorld(world), player.getUniqueId(), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerAddGroup(Player player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userAddGroup(world(player), ((OfflinePlayer) player).getUniqueId(), group);
|
||||
return userAddGroup(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerRemoveGroup(String world, String player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userRemoveGroup(world(world), lookupUuid(player), group);
|
||||
return userRemoveGroup(convertWorld(world), lookupUuid(player), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerRemoveGroup(World world, String player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userRemoveGroup(world(world), lookupUuid(player), group);
|
||||
return userRemoveGroup(convertWorld(world), lookupUuid(player), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerRemoveGroup(String world, OfflinePlayer player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userRemoveGroup(world(world), player.getUniqueId(), group);
|
||||
return userRemoveGroup(convertWorld(world), player.getUniqueId(), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerRemoveGroup(Player player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userRemoveGroup(world(player), ((OfflinePlayer) player).getUniqueId(), group);
|
||||
return userRemoveGroup(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String[] getPlayerGroups(String world, String player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userGetGroups(world(world), lookupUuid(player));
|
||||
return userGetGroups(convertWorld(world), lookupUuid(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String[] getPlayerGroups(World world, String player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userGetGroups(world(world), lookupUuid(player));
|
||||
return userGetGroups(convertWorld(world), lookupUuid(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String[] getPlayerGroups(String world, OfflinePlayer player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userGetGroups(world(world), player.getUniqueId());
|
||||
return userGetGroups(convertWorld(world), player.getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String[] getPlayerGroups(Player player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userGetGroups(world(player), ((OfflinePlayer) player).getUniqueId());
|
||||
return userGetGroups(convertWorld(player), ((OfflinePlayer) player).getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPrimaryGroup(String world, String player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userGetPrimaryGroup(world(world), lookupUuid(player));
|
||||
return userGetPrimaryGroup(convertWorld(world), lookupUuid(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPrimaryGroup(World world, String player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userGetPrimaryGroup(world(world), lookupUuid(player));
|
||||
return userGetPrimaryGroup(convertWorld(world), lookupUuid(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPrimaryGroup(String world, OfflinePlayer player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userGetPrimaryGroup(world(world), player.getUniqueId());
|
||||
return userGetPrimaryGroup(convertWorld(world), player.getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPrimaryGroup(Player player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userGetPrimaryGroup(world(player), ((OfflinePlayer) player).getUniqueId());
|
||||
return userGetPrimaryGroup(convertWorld(player), ((OfflinePlayer) player).getUniqueId());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,21 +30,20 @@ import com.google.common.base.Strings;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MetaAccumulator;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MetaCache;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.node.types.Meta;
|
||||
import me.lucko.luckperms.common.node.types.Prefix;
|
||||
import me.lucko.luckperms.common.node.types.Suffix;
|
||||
import me.lucko.luckperms.common.util.TextUtils;
|
||||
import me.lucko.luckperms.common.query.QueryOptionsImpl;
|
||||
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
|
||||
|
||||
import net.luckperms.api.context.DefaultContextKeys;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
import net.luckperms.api.node.NodeBuilder;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.NodeType;
|
||||
import net.luckperms.api.query.Flag;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
@@ -78,7 +77,6 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
super(vaultPermission);
|
||||
this.plugin = plugin;
|
||||
this.vaultPermission = vaultPermission;
|
||||
this.worldMappingFunction = world -> vaultPermission.isIgnoreWorld() ? null : world;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,6 +84,11 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
return "LuckPerms";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String convertWorld(String world) {
|
||||
return this.vaultPermission.isIgnoreWorld() ? null : super.convertWorld(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserChatPrefix(String world, UUID uuid) {
|
||||
Objects.requireNonNull(uuid, "uuid");
|
||||
@@ -93,11 +96,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
PermissionHolder user = this.vaultPermission.lookupUser(uuid);
|
||||
QueryOptions queryOptions = this.vaultPermission.getQueryOptions(uuid, world);
|
||||
MetaCache metaData = user.getCachedData().getMetaData(queryOptions);
|
||||
String ret = metaData.getPrefix(MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
if (log()) {
|
||||
logMsg("#getUserChatPrefix: %s - %s - %s", user.getPlainDisplayName(), queryOptions.context(), ret);
|
||||
}
|
||||
return Strings.nullToEmpty(ret);
|
||||
return Strings.nullToEmpty(metaData.getPrefix(MetaCheckEvent.Origin.THIRD_PARTY_API));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -107,11 +106,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
PermissionHolder user = this.vaultPermission.lookupUser(uuid);
|
||||
QueryOptions queryOptions = this.vaultPermission.getQueryOptions(uuid, world);
|
||||
MetaCache metaData = user.getCachedData().getMetaData(queryOptions);
|
||||
String ret = metaData.getSuffix(MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
if (log()) {
|
||||
logMsg("#getUserChatSuffix: %s - %s - %s", user.getPlainDisplayName(), queryOptions.context(), ret);
|
||||
}
|
||||
return Strings.nullToEmpty(ret);
|
||||
return Strings.nullToEmpty(metaData.getSuffix(MetaCheckEvent.Origin.THIRD_PARTY_API));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,11 +139,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
PermissionHolder user = this.vaultPermission.lookupUser(uuid);
|
||||
QueryOptions queryOptions = this.vaultPermission.getQueryOptions(uuid, world);
|
||||
MetaCache metaData = user.getCachedData().getMetaData(queryOptions);
|
||||
String ret = metaData.getMetaValue(key, MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
if (log()) {
|
||||
logMsg("#getUserMeta: %s - %s - %s - %s", user.getPlainDisplayName(), queryOptions.context(), key, ret);
|
||||
}
|
||||
return ret;
|
||||
return metaData.getMetaValue(key, MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,11 +163,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
}
|
||||
QueryOptions queryOptions = this.vaultPermission.getQueryOptions(null, world);
|
||||
MetaCache metaData = group.getCachedData().getMetaData(queryOptions);
|
||||
String ret = metaData.getPrefix(MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
if (log()) {
|
||||
logMsg("#getGroupPrefix: %s - %s - %s", group.getName(), queryOptions.context(), ret);
|
||||
}
|
||||
return Strings.nullToEmpty(ret);
|
||||
return Strings.nullToEmpty(metaData.getPrefix(MetaCheckEvent.Origin.THIRD_PARTY_API));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -188,11 +175,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
}
|
||||
QueryOptions queryOptions = this.vaultPermission.getQueryOptions(null, world);
|
||||
MetaCache metaData = group.getCachedData().getMetaData(queryOptions);
|
||||
String ret = metaData.getSuffix(MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
if (log()) {
|
||||
logMsg("#getGroupSuffix: %s - %s - %s", group.getName(), queryOptions.context(), ret);
|
||||
}
|
||||
return Strings.nullToEmpty(ret);
|
||||
return Strings.nullToEmpty(metaData.getSuffix(MetaCheckEvent.Origin.THIRD_PARTY_API));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -225,11 +208,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
}
|
||||
QueryOptions queryOptions = this.vaultPermission.getQueryOptions(null, world);
|
||||
MetaCache metaData = group.getCachedData().getMetaData(queryOptions);
|
||||
String ret = metaData.getMetaValue(key, MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
if (log()) {
|
||||
logMsg("#getGroupMeta: %s - %s - %s - %s", group.getName(), queryOptions.context(), key, ret);
|
||||
}
|
||||
return ret;
|
||||
return metaData.getMetaValue(key, MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -249,22 +228,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
return this.plugin.getGroupManager().getByDisplayName(name);
|
||||
}
|
||||
|
||||
// logging
|
||||
private boolean log() {
|
||||
return this.plugin.getConfiguration().get(ConfigKeys.VAULT_DEBUG);
|
||||
}
|
||||
private void logMsg(String format, Object... args) {
|
||||
this.plugin.getLogger().info("[VAULT-CHAT] " + String.format(format, args)
|
||||
.replace(TextUtils.SECTION_CHAR, '$')
|
||||
.replace(TextUtils.AMPERSAND_CHAR, '$')
|
||||
);
|
||||
}
|
||||
|
||||
private void setChatMeta(PermissionHolder holder, ChatMetaType type, String value, String world) {
|
||||
if (log()) {
|
||||
logMsg("#setChatMeta: %s - %s - %s - %s", holder.getPlainDisplayName(), type, value, world);
|
||||
}
|
||||
|
||||
// remove all prefixes/suffixes directly set on the user/group
|
||||
holder.removeIf(DataType.NORMAL, null, type.nodeType()::matches, false);
|
||||
|
||||
@@ -274,22 +238,21 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
}
|
||||
|
||||
// find the max inherited priority & add 10
|
||||
MetaAccumulator metaAccumulator = holder.accumulateMeta(null, createQueryOptionsForWorldSet(world));
|
||||
metaAccumulator.complete();
|
||||
MetaAccumulator metaAccumulator = holder.accumulateMeta(createQueryOptionsForWorldSet(world));
|
||||
int priority = metaAccumulator.getChatMeta(type).keySet().stream().mapToInt(e -> e).max().orElse(0) + 10;
|
||||
|
||||
NodeBuilder chatMetaNode = type == ChatMetaType.PREFIX ? Prefix.builder(value, priority) : Suffix.builder(value, priority);
|
||||
chatMetaNode.withContext(DefaultContextKeys.SERVER_KEY, this.vaultPermission.getVaultServer());
|
||||
chatMetaNode.withContext(DefaultContextKeys.WORLD_KEY, world);
|
||||
Node node = type.builder(value, priority)
|
||||
.withContext(DefaultContextKeys.SERVER_KEY, this.vaultPermission.getVaultServer())
|
||||
.withContext(DefaultContextKeys.WORLD_KEY, world == null ? "global" : world).build();
|
||||
|
||||
// assume success
|
||||
holder.setNode(DataType.NORMAL, chatMetaNode.build(), true);
|
||||
holder.setNode(DataType.NORMAL, node, true);
|
||||
this.vaultPermission.holderSave(holder);
|
||||
}
|
||||
|
||||
private void setMeta(PermissionHolder holder, String key, Object value, String world) {
|
||||
if (log()) {
|
||||
logMsg("#setMeta: %s - %s - %s - %s", holder.getPlainDisplayName(), key, value, world);
|
||||
if (key.equalsIgnoreCase(Prefix.NODE_KEY) || key.equalsIgnoreCase(Suffix.NODE_KEY)) {
|
||||
setChatMeta(holder, ChatMetaType.valueOf(key.toUpperCase()), value == null ? null : value.toString(), world);
|
||||
return;
|
||||
}
|
||||
|
||||
holder.removeIf(DataType.NORMAL, null, NodeType.META.predicate(n -> n.getMetaKey().equals(key)), false);
|
||||
@@ -299,20 +262,12 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
return;
|
||||
}
|
||||
|
||||
NodeBuilder metaNode;
|
||||
if (key.equalsIgnoreCase("prefix")) {
|
||||
metaNode = Prefix.builder(value.toString(), 100);
|
||||
} else if (key.equalsIgnoreCase("suffix")) {
|
||||
metaNode = Suffix.builder(value.toString(), 100);
|
||||
} else {
|
||||
metaNode = Meta.builder(key, value.toString());
|
||||
}
|
||||
Node node = Meta.builder(key, value.toString())
|
||||
.withContext(DefaultContextKeys.SERVER_KEY, this.vaultPermission.getVaultServer())
|
||||
.withContext(DefaultContextKeys.WORLD_KEY, world == null ? "global" : world)
|
||||
.build();
|
||||
|
||||
metaNode.withContext(DefaultContextKeys.SERVER_KEY, this.vaultPermission.getVaultServer());
|
||||
metaNode.withContext(DefaultContextKeys.WORLD_KEY, world);
|
||||
|
||||
// assume success
|
||||
holder.setNode(DataType.NORMAL, metaNode.build(), true);
|
||||
holder.setNode(DataType.NORMAL, node, true);
|
||||
this.vaultPermission.holderSave(holder);
|
||||
}
|
||||
|
||||
@@ -323,7 +278,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
}
|
||||
context.add(DefaultContextKeys.SERVER_KEY, this.vaultPermission.getVaultServer());
|
||||
|
||||
QueryOptions.Builder builder = QueryOptions.defaultContextualOptions().toBuilder();
|
||||
QueryOptions.Builder builder = QueryOptionsImpl.DEFAULT_CONTEXTUAL.toBuilder();
|
||||
builder.context(context.build());
|
||||
builder.flag(Flag.INCLUDE_NODES_WITHOUT_SERVER_CONTEXT, this.vaultPermission.isIncludeGlobal());
|
||||
return builder.build();
|
||||
|
||||
+33
-66
@@ -29,6 +29,7 @@ import com.google.common.base.Preconditions;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.bukkit.context.BukkitContextManager;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MetaCache;
|
||||
import me.lucko.luckperms.common.cacheddata.type.PermissionCache;
|
||||
import me.lucko.luckperms.common.calculator.processor.MapProcessor;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
@@ -40,26 +41,23 @@ import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.model.manager.group.GroupManager;
|
||||
import me.lucko.luckperms.common.node.factory.NodeBuilders;
|
||||
import me.lucko.luckperms.common.node.types.Inheritance;
|
||||
import me.lucko.luckperms.common.util.TextUtils;
|
||||
import me.lucko.luckperms.common.query.QueryOptionsImpl;
|
||||
import me.lucko.luckperms.common.util.Uuids;
|
||||
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
|
||||
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
|
||||
|
||||
import net.luckperms.api.context.ContextSet;
|
||||
import net.luckperms.api.context.DefaultContextKeys;
|
||||
import net.luckperms.api.context.MutableContextSet;
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.NodeType;
|
||||
import net.luckperms.api.query.Flag;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import net.luckperms.api.util.Result;
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
@@ -84,11 +82,6 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
|
||||
public LuckPermsVaultPermission(LPBukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.worldMappingFunction = world -> isIgnoreWorld() ? null : world;
|
||||
}
|
||||
|
||||
public LPBukkitPlugin getPlugin() {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,12 +89,17 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
return "LuckPerms";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String convertWorld(String world) {
|
||||
return isIgnoreWorld() ? null : super.convertWorld(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID lookupUuid(String player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
|
||||
// are they online?
|
||||
Player onlinePlayer = Bukkit.getPlayerExact(player);
|
||||
Player onlinePlayer = this.plugin.getBootstrap().getServer().getPlayerExact(player);
|
||||
if (onlinePlayer != null) {
|
||||
return onlinePlayer.getUniqueId();
|
||||
}
|
||||
@@ -113,7 +111,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
}
|
||||
|
||||
// are we on the main thread?
|
||||
if (!this.plugin.getBootstrap().isServerStarting() && Bukkit.isPrimaryThread() && !this.plugin.getConfiguration().get(ConfigKeys.VAULT_UNSAFE_LOOKUPS)) {
|
||||
if (!this.plugin.getBootstrap().isServerStarting() && this.plugin.getBootstrap().getServer().isPrimaryThread() && !this.plugin.getConfiguration().get(ConfigKeys.VAULT_UNSAFE_LOOKUPS)) {
|
||||
throw new RuntimeException(
|
||||
"The operation to lookup a UUID for '" + player + "' was cancelled by LuckPerms. This is NOT a bug. \n" +
|
||||
"The lookup request was made on the main server thread. It is not safe to execute a request to \n" +
|
||||
@@ -164,7 +162,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
}
|
||||
|
||||
// are we on the main thread?
|
||||
if (!this.plugin.getBootstrap().isServerStarting() && Bukkit.isPrimaryThread() && !this.plugin.getConfiguration().get(ConfigKeys.VAULT_UNSAFE_LOOKUPS)) {
|
||||
if (!this.plugin.getBootstrap().isServerStarting() && this.plugin.getBootstrap().getServer().isPrimaryThread() && !this.plugin.getConfiguration().get(ConfigKeys.VAULT_UNSAFE_LOOKUPS)) {
|
||||
throw new RuntimeException(
|
||||
"The operation to load user data for '" + uuid + "' was cancelled by LuckPerms. This is NOT a bug. \n" +
|
||||
"The lookup request was made on the main server thread. It is not safe to execute a request to \n" +
|
||||
@@ -194,12 +192,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
PermissionHolder user = lookupUser(uuid);
|
||||
QueryOptions queryOptions = getQueryOptions(uuid, world);
|
||||
PermissionCache permissionData = user.getCachedData().getPermissionData(queryOptions);
|
||||
|
||||
Tristate result = permissionData.checkPermission(permission, PermissionCheckEvent.Origin.THIRD_PARTY_API).result();
|
||||
if (log()) {
|
||||
logMsg("#userHasPermission: %s - %s - %s - %s", user.getPlainDisplayName(), queryOptions.context(), permission, result);
|
||||
}
|
||||
return result != Tristate.UNDEFINED ? result.asBoolean() : org.bukkit.permissions.Permission.DEFAULT_PERMISSION.getValue(queryOptions.option(BukkitContextManager.OP_OPTION).orElse(false));
|
||||
return permissionData.checkPermission(permission, PermissionCheckEvent.Origin.THIRD_PARTY_API).result().asBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -236,9 +229,6 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
PermissionCache permissionData = user.getCachedData().getPermissionData(queryOptions);
|
||||
|
||||
TristateResult result = permissionData.checkPermission(Inheritance.key(rewriteGroupName(group)), PermissionCheckEvent.Origin.THIRD_PARTY_API);
|
||||
if (log()) {
|
||||
logMsg("#userInGroup: %s - %s - %s - %s", user.getPlainDisplayName(), queryOptions.context(), group, result);
|
||||
}
|
||||
return result.processorClass() == MapProcessor.class && result.result().asBoolean();
|
||||
}
|
||||
|
||||
@@ -261,10 +251,9 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
Objects.requireNonNull(uuid, "uuid");
|
||||
|
||||
PermissionHolder user = lookupUser(uuid);
|
||||
ContextSet contexts = getQueryOptions(uuid, world).context();
|
||||
QueryOptions queryOptions = getQueryOptions(uuid, world);
|
||||
|
||||
String[] ret = user.normalData().immutableInheritance().values().stream()
|
||||
.filter(n -> n.getContexts().isSatisfiedBy(contexts))
|
||||
return user.getOwnNodes(NodeType.INHERITANCE, queryOptions).stream()
|
||||
.map(n -> {
|
||||
Group group = this.plugin.getGroupManager().getIfLoaded(n.getGroupName());
|
||||
if (group != null) {
|
||||
@@ -273,12 +262,6 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
return n.getGroupName();
|
||||
})
|
||||
.toArray(String[]::new);
|
||||
|
||||
if (log()) {
|
||||
logMsg("#userGetGroups: %s - %s - %s", user.getPlainDisplayName(), contexts, Arrays.toString(ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -289,16 +272,14 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
if (user instanceof Group) { // npc
|
||||
return this.plugin.getConfiguration().get(ConfigKeys.VAULT_NPC_GROUP);
|
||||
}
|
||||
String value = ((User) user).getPrimaryGroup().getValue();
|
||||
|
||||
QueryOptions queryOptions = getQueryOptions(uuid, world);
|
||||
MetaCache metaData = user.getCachedData().getMetaData(queryOptions);
|
||||
String value = metaData.getPrimaryGroup(MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
|
||||
Group group = getGroup(value);
|
||||
if (group != null) {
|
||||
value = group.getPlainDisplayName();
|
||||
}
|
||||
|
||||
this.plugin.getVerboseHandler().offerMetaCheckEvent(MetaCheckEvent.Origin.THIRD_PARTY_API, user.getPlainDisplayName(), QueryOptions.defaultContextualOptions(), "primarygroup", value);
|
||||
|
||||
if (log()) {
|
||||
logMsg("#userGetPrimaryGroup: %s - %s - %s", user.getPlainDisplayName(), world, value);
|
||||
return group.getPlainDisplayName();
|
||||
}
|
||||
|
||||
return value;
|
||||
@@ -316,12 +297,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
|
||||
QueryOptions queryOptions = getQueryOptions(null, world);
|
||||
PermissionCache permissionData = group.getCachedData().getPermissionData(queryOptions);
|
||||
|
||||
Tristate result = permissionData.checkPermission(permission, PermissionCheckEvent.Origin.THIRD_PARTY_API).result();
|
||||
if (log()) {
|
||||
logMsg("#groupHasPermission: %s - %s - %s - %s", group.getName(), queryOptions.context(), permission, result);
|
||||
}
|
||||
return result.asBoolean();
|
||||
return permissionData.checkPermission(permission, PermissionCheckEvent.Origin.THIRD_PARTY_API).result().asBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -368,17 +344,6 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
return name;
|
||||
}
|
||||
|
||||
// logging
|
||||
private boolean log() {
|
||||
return this.plugin.getConfiguration().get(ConfigKeys.VAULT_DEBUG);
|
||||
}
|
||||
private void logMsg(String format, Object... args) {
|
||||
this.plugin.getLogger().info("[VAULT-PERMS] " + String.format(format, args)
|
||||
.replace(TextUtils.SECTION_CHAR, '$')
|
||||
.replace(TextUtils.AMPERSAND_CHAR, '$')
|
||||
);
|
||||
}
|
||||
|
||||
// utility method for getting a contexts instance for a given vault lookup.
|
||||
QueryOptions getQueryOptions(@Nullable UUID uuid, @Nullable String world) {
|
||||
MutableContextSet context;
|
||||
@@ -419,7 +384,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
op = this.plugin.getConfiguration().get(ConfigKeys.VAULT_NPC_OP_STATUS);
|
||||
}
|
||||
|
||||
QueryOptions.Builder builder = QueryOptions.defaultContextualOptions().toBuilder();
|
||||
QueryOptions.Builder builder = QueryOptionsImpl.DEFAULT_CONTEXTUAL.toBuilder();
|
||||
builder.context(context);
|
||||
builder.flag(Flag.INCLUDE_NODES_WITHOUT_SERVER_CONTEXT, isIncludeGlobal());
|
||||
if (op) {
|
||||
@@ -434,11 +399,12 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
Objects.requireNonNull(permission, "permission is null");
|
||||
Preconditions.checkArgument(!permission.isEmpty(), "permission is an empty string");
|
||||
|
||||
if (log()) {
|
||||
logMsg("#holderAddPermission: %s - %s - %s", holder.getPlainDisplayName(), permission, world);
|
||||
}
|
||||
Node node = NodeBuilders.determineMostApplicable(permission)
|
||||
.withContext(DefaultContextKeys.SERVER_KEY, getVaultServer())
|
||||
.withContext(DefaultContextKeys.WORLD_KEY, world == null ? "global" : world)
|
||||
.build();
|
||||
|
||||
if (((Result) holder.setNode(DataType.NORMAL, NodeBuilders.determineMostApplicable(permission).value(true).withContext(DefaultContextKeys.SERVER_KEY, getVaultServer()).withContext(DefaultContextKeys.WORLD_KEY, world).build(), true)).wasSuccessful()) {
|
||||
if (holder.setNode(DataType.NORMAL, node, true).wasSuccessful()) {
|
||||
return holderSave(holder);
|
||||
}
|
||||
return false;
|
||||
@@ -448,11 +414,12 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
Objects.requireNonNull(permission, "permission is null");
|
||||
Preconditions.checkArgument(!permission.isEmpty(), "permission is an empty string");
|
||||
|
||||
if (log()) {
|
||||
logMsg("#holderRemovePermission: %s - %s - %s", holder.getPlainDisplayName(), permission, world);
|
||||
}
|
||||
Node node = NodeBuilders.determineMostApplicable(permission)
|
||||
.withContext(DefaultContextKeys.SERVER_KEY, getVaultServer())
|
||||
.withContext(DefaultContextKeys.WORLD_KEY, world == null ? "global" : world)
|
||||
.build();
|
||||
|
||||
if (holder.unsetNode(DataType.NORMAL, NodeBuilders.determineMostApplicable(permission).withContext(DefaultContextKeys.SERVER_KEY, getVaultServer()).withContext(DefaultContextKeys.WORLD_KEY, world).build()).wasSuccessful()) {
|
||||
if (holder.unsetNode(DataType.NORMAL, node).wasSuccessful()) {
|
||||
return holderSave(holder);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -57,7 +57,7 @@ use-server-uuid-cache: false
|
||||
# How the plugin should store data
|
||||
#
|
||||
# - The various options are explained in more detail on the wiki:
|
||||
# https://github.com/lucko/LuckPerms/wiki/Choosing-a-Storage-type
|
||||
# https://github.com/lucko/LuckPerms/wiki/Storage-types
|
||||
#
|
||||
# - Possible options:
|
||||
#
|
||||
@@ -133,21 +133,31 @@ data:
|
||||
connection-timeout: 5000 # 5 seconds
|
||||
|
||||
# This setting allows you to define extra properties for connections.
|
||||
#
|
||||
# By default, the following options are set to enable utf8 encoding. (you may need to remove
|
||||
# these if you are using PostgreSQL)
|
||||
# useUnicode: true
|
||||
# characterEncoding: utf8
|
||||
#
|
||||
# You can also use this section to disable SSL connections, by uncommenting the 'useSSL' and
|
||||
# 'verifyServerCertificate' options below.
|
||||
properties:
|
||||
useUnicode: true
|
||||
characterEncoding: utf8
|
||||
#useSSL: false
|
||||
#verifyServerCertificate: false
|
||||
|
||||
# The prefix for all LuckPerms SQL tables.
|
||||
# - Change this is you want to use different tables for different servers.
|
||||
table_prefix: 'luckperms_'
|
||||
# - Change this if you want to use different tables for different servers.
|
||||
table-prefix: 'luckperms_'
|
||||
|
||||
# The prefix to use for all LuckPerms collections. Change this if you want to use different
|
||||
# collections for different servers. The default is no prefix.
|
||||
mongodb_collection_prefix: ''
|
||||
mongodb-collection-prefix: ''
|
||||
|
||||
# MongoDB ClientConnectionURI for use with replica sets and custom connection options
|
||||
# - See https://docs.mongodb.com/manual/reference/connection-string/
|
||||
mongodb_connection_URI: ''
|
||||
mongodb-connection-uri: ''
|
||||
|
||||
# Define settings for a "split" storage setup.
|
||||
#
|
||||
@@ -205,7 +215,7 @@ watch-files: true
|
||||
# - Possible options:
|
||||
# => sql Uses the SQL database to form a queue system for communication. Will only work when
|
||||
# 'storage-method' is set to MySQL or MariaDB. This is chosen by default if the
|
||||
# option is set to 'none' and SQL storage is in use. Set to 'notsql' to disable this.
|
||||
# option is set to 'auto' and SQL storage is in use. Set to 'notsql' to disable this.
|
||||
# => pluginmsg Uses the plugin messaging channels to communicate with the proxy.
|
||||
# LuckPerms must be installed on your proxy & all connected servers backend servers.
|
||||
# Won't work if you have more than one proxy.
|
||||
@@ -294,6 +304,12 @@ require-sender-group-membership-to-modify: false
|
||||
# '/lp log notify <on|off>'
|
||||
log-notify: true
|
||||
|
||||
# Defines a list of log entries which should not be sent as notifications to users.
|
||||
#
|
||||
# - Each entry in the list is a RegEx expression which is matched against the log entry description.
|
||||
log-notify-filtered-descriptions:
|
||||
# - "parent add example"
|
||||
|
||||
# Defines the options for prefix and suffix stacking.
|
||||
#
|
||||
# - The feature allows you to display multiple prefixes or suffixes alongside a players username in
|
||||
@@ -332,6 +348,16 @@ log-notify: true
|
||||
# value was inherited from a group not on the given track.
|
||||
#
|
||||
# => lowest_not_on_track_<track> Same as above, except takes the value with the lowest weight.
|
||||
#
|
||||
# => highest_from_group_<group> Selects the value with the highest weight, but only if the
|
||||
# value was inherited from the given group.
|
||||
#
|
||||
# => lowest_from_group_<group> Same as above, except takes the value with the lowest weight.
|
||||
#
|
||||
# => highest_not_from_group_<group> Selects the value with the highest weight, but only if the
|
||||
# value was not inherited from the given group.
|
||||
#
|
||||
# => lowest_not_from_group_<group> Same as above, except takes the value with the lowest weight.
|
||||
meta-formatting:
|
||||
prefix:
|
||||
format:
|
||||
@@ -380,6 +406,15 @@ inheritance-traversal-algorithm: depth-first-pre-order
|
||||
# and when this setting is 'false':, the rules are just applied during each step of the traversal.
|
||||
post-traversal-inheritance-sort: false
|
||||
|
||||
# Defines the mode used to determine whether a set of contexts are satisfied.
|
||||
#
|
||||
# - Possible options:
|
||||
# => at-least-one-value-per-key Set A will be satisfied by another set B, if at least one of the
|
||||
# key-value entries per key in A are also in B.
|
||||
# => all-values-per-key Set A will be satisfied by another set B, if all key-value
|
||||
# entries in A are also in B.
|
||||
context-satisfy-mode: at-least-one-value-per-key
|
||||
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | Permission resolution settings | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
@@ -398,6 +433,22 @@ apply-global-groups: true
|
||||
# If users on this server should have global (non-world specific) groups applied
|
||||
apply-global-world-groups: true
|
||||
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | Meta lookup settings | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
|
||||
# Defines how meta values should be selected.
|
||||
#
|
||||
# - Possible options:
|
||||
# => inheritance Selects the meta value that was inherited first
|
||||
# => highest-number Selects the highest numerical meta value
|
||||
# => lowest-number Selects the lowest numerical meta value
|
||||
meta-value-selection-default: inheritance
|
||||
|
||||
# Defines how meta values should be selected per key.
|
||||
meta-value-selection:
|
||||
# max-homes: highest-number
|
||||
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | Inheritance settings | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
@@ -408,6 +459,14 @@ apply-global-world-groups: true
|
||||
# permissions matching the wildcard.
|
||||
apply-wildcards: true
|
||||
|
||||
# If LuckPerms should resolve and apply permissions according to the Sponge style implicit wildcard
|
||||
# inheritance system.
|
||||
#
|
||||
# - That being: If a user has been granted "example", then the player should have also be
|
||||
# automatically granted "example.function", "example.another", "example.deeper.nesting",
|
||||
# and so on.
|
||||
apply-sponge-implicit-wildcards: false
|
||||
|
||||
# If the plugin should parse regex permissions.
|
||||
#
|
||||
# - If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the
|
||||
@@ -544,9 +603,6 @@ vault-include-global: true
|
||||
# If Vault operations should ignore any world arguments if supplied.
|
||||
vault-ignore-world: false
|
||||
|
||||
# If LuckPerms should print debugging info to console when a plugin uses a Vault function
|
||||
vault-debug: false
|
||||
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
# | Miscellaneous (and rarely used) settings | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
@@ -566,3 +622,13 @@ allow-invalid-usernames: false
|
||||
#
|
||||
# - When this happens, the plugin will set their primary group back to default.
|
||||
prevent-primary-group-removal: false
|
||||
|
||||
# If LuckPerms should update the list of commands sent to the client when permissions are changed.
|
||||
update-client-command-list: true
|
||||
|
||||
# If LuckPerms should attempt to register "Brigadier" command list data for its commands.
|
||||
register-command-list-data: true
|
||||
|
||||
# If LuckPerms should attempt to resolve Vanilla command target selectors for LP commands.
|
||||
# See here for more info: https://minecraft.gamepedia.com/Commands#Target_selectors
|
||||
resolve-command-selectors: false
|
||||
Binary file not shown.
@@ -0,0 +1,631 @@
|
||||
luckperms {
|
||||
sync;
|
||||
info;
|
||||
editor {
|
||||
all;
|
||||
groups;
|
||||
users;
|
||||
}
|
||||
debug;
|
||||
verbose {
|
||||
off;
|
||||
on {
|
||||
filter brigadier:string greedy_phrase;
|
||||
}
|
||||
paste;
|
||||
record {
|
||||
filter brigadier:string greedy_phrase;
|
||||
}
|
||||
command {
|
||||
player brigadier:string single_word {
|
||||
command brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
tree {
|
||||
scope brigadier:string single_word {
|
||||
player brigadier:string single_word;
|
||||
}
|
||||
}
|
||||
search {
|
||||
permission brigadier:string quotable_phrase;
|
||||
}
|
||||
check {
|
||||
user brigadier:string single_word {
|
||||
permission brigadier:string quotable_phrase;
|
||||
}
|
||||
}
|
||||
networksync;
|
||||
import {
|
||||
file brigadier:string quotable_phrase;
|
||||
}
|
||||
export {
|
||||
file brigadier:string quotable_phrase;
|
||||
}
|
||||
reloadconfig;
|
||||
bulkupdate {
|
||||
datatype brigadier:string single_word {
|
||||
delete {
|
||||
constraint brigadier:string greedy_phrase;
|
||||
}
|
||||
update {
|
||||
actionfield brigadier:string single_word {
|
||||
actionvalue brigadier:string quotable_phrase {
|
||||
constraint brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
migration {
|
||||
plugin brigadier:string single_word;
|
||||
}
|
||||
creategroup {
|
||||
name brigadier:string single_word;
|
||||
}
|
||||
deletegroup {
|
||||
name brigadier:string single_word;
|
||||
}
|
||||
listgroups;
|
||||
createtrack {
|
||||
name brigadier:string single_word;
|
||||
}
|
||||
deletetrack {
|
||||
name brigadier:string single_word;
|
||||
}
|
||||
listtracks;
|
||||
|
||||
user {
|
||||
user brigadier:string single_word {
|
||||
info;
|
||||
|
||||
permission {
|
||||
info;
|
||||
set {
|
||||
node brigadier:string quotable_phrase {
|
||||
value brigadier:bool {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
unset {
|
||||
node brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
settemp {
|
||||
node brigadier:string quotable_phrase {
|
||||
value brigadier:bool {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unsettemp {
|
||||
node brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
check {
|
||||
node brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
checkinherits {
|
||||
node brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
clear {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
|
||||
parent {
|
||||
info;
|
||||
set {
|
||||
group brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
add {
|
||||
group brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
remove {
|
||||
group brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
settrack {
|
||||
track brigadier:string single_word {
|
||||
group brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
addtemp {
|
||||
group brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
removetemp {
|
||||
group brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
clear {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
cleartrack {
|
||||
track brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
switchprimarygroup {
|
||||
group brigadier:string quotable_phrase;
|
||||
}
|
||||
}
|
||||
|
||||
meta {
|
||||
info;
|
||||
set {
|
||||
key brigadier:string quotable_phrase {
|
||||
value brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
unset {
|
||||
key brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
settemp {
|
||||
key brigadier:string quotable_phrase {
|
||||
value brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unsettemp {
|
||||
key brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
addprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
addsuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
setprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
setsuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
removeprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
removesuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
addtempprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
addtempsuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
settempprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
settempsuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
removetempprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
removetempsuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
clear {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
|
||||
editor;
|
||||
promote {
|
||||
track brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
demote {
|
||||
track brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
showtracks;
|
||||
clear {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
clone {
|
||||
user brigadier:string single_word;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group {
|
||||
group brigadier:string single_word {
|
||||
info;
|
||||
|
||||
permission {
|
||||
info;
|
||||
set {
|
||||
node brigadier:string quotable_phrase {
|
||||
value brigadier:bool {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
unset {
|
||||
node brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
settemp {
|
||||
node brigadier:string quotable_phrase {
|
||||
value brigadier:bool {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unsettemp {
|
||||
node brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
check {
|
||||
node brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
checkinherits {
|
||||
node brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
clear {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
|
||||
parent {
|
||||
info;
|
||||
set {
|
||||
group brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
add {
|
||||
group brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
remove {
|
||||
group brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
settrack {
|
||||
track brigadier:string single_word {
|
||||
group brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
addtemp {
|
||||
group brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
removetemp {
|
||||
group brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
clear {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
cleartrack {
|
||||
track brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
switchprimarygroup {
|
||||
group brigadier:string quotable_phrase;
|
||||
}
|
||||
}
|
||||
|
||||
meta {
|
||||
info;
|
||||
set {
|
||||
key brigadier:string quotable_phrase {
|
||||
value brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
unset {
|
||||
key brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
settemp {
|
||||
key brigadier:string quotable_phrase {
|
||||
value brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unsettemp {
|
||||
key brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
addprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
addsuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
setprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
setsuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
removeprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
removesuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
addtempprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
addtempsuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
settempprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
settempsuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
duration brigadier:string single_word {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
removetempprefix {
|
||||
priority brigadier:integer {
|
||||
prefix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
removetempsuffix {
|
||||
priority brigadier:integer {
|
||||
suffix brigadier:string quotable_phrase {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
}
|
||||
clear {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
|
||||
editor;
|
||||
listmembers {
|
||||
page brigadier:integer;
|
||||
}
|
||||
setweight {
|
||||
weight brigadier:integer;
|
||||
}
|
||||
setdisplayname {
|
||||
name brigadier:string single_word;
|
||||
}
|
||||
showtracks;
|
||||
clear {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
rename {
|
||||
newname brigadier:string single_word;
|
||||
}
|
||||
clone {
|
||||
newname brigadier:string single_word;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
track {
|
||||
track brigadier:string single_word {
|
||||
info;
|
||||
append {
|
||||
group brigadier:string single_word;
|
||||
}
|
||||
insert {
|
||||
group brigadier:string single_word {
|
||||
position brigadier:integer;
|
||||
}
|
||||
}
|
||||
remove {
|
||||
group brigadier:string single_word;
|
||||
}
|
||||
clear;
|
||||
rename {
|
||||
newname brigadier:string single_word;
|
||||
}
|
||||
clone {
|
||||
newname brigadier:string single_word;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log {
|
||||
recent {
|
||||
user brigadier:string single_word {
|
||||
page brigadier:integer;
|
||||
}
|
||||
}
|
||||
search {
|
||||
query brigadier:string quotable_phrase {
|
||||
page brigadier:integer;
|
||||
}
|
||||
}
|
||||
notify {
|
||||
off;
|
||||
on;
|
||||
}
|
||||
userhistory {
|
||||
user brigadier:string single_word {
|
||||
page brigadier:integer;
|
||||
}
|
||||
}
|
||||
grouphistory {
|
||||
group brigadier:string single_word {
|
||||
page brigadier:integer;
|
||||
}
|
||||
}
|
||||
trackhistory {
|
||||
track brigadier:string single_word {
|
||||
page brigadier:integer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -5,8 +5,8 @@ plugins {
|
||||
dependencies {
|
||||
compile project(':common')
|
||||
|
||||
compileOnly 'net.md-5:bungeecord-api:1.14-SNAPSHOT'
|
||||
compileOnly 'net.kyori:text-adapter-bungeecord:3.0.2'
|
||||
compileOnly 'net.md-5:bungeecord-api:1.15-SNAPSHOT'
|
||||
compileOnly 'net.kyori:text-adapter-bungeecord:3.0.4'
|
||||
compileOnly 'com.imaginarycode.minecraft:RedisBungee:0.4'
|
||||
|
||||
// migration plugins
|
||||
@@ -41,6 +41,7 @@ shadowJar {
|
||||
relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine'
|
||||
relocate 'okio', 'me.lucko.luckperms.lib.okio'
|
||||
relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3'
|
||||
relocate 'net.bytebuddy', 'me.lucko.luckperms.lib.bytebuddy'
|
||||
relocate 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore'
|
||||
relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb'
|
||||
relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql'
|
||||
|
||||
@@ -25,45 +25,71 @@
|
||||
|
||||
package me.lucko.luckperms.bungee;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import me.lucko.luckperms.common.command.CommandManager;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentTokenizer;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.api.plugin.TabExecutor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class BungeeCommandExecutor extends Command implements TabExecutor {
|
||||
private static final Splitter TAB_COMPLETE_ARGUMENT_SPLITTER = Splitter.on(CommandManager.COMMAND_SEPARATOR_PATTERN);
|
||||
private static final Splitter ARGUMENT_SPLITTER = Splitter.on(CommandManager.COMMAND_SEPARATOR_PATTERN).omitEmptyStrings();
|
||||
private static final Joiner ARGUMENT_JOINER = Joiner.on(' ');
|
||||
/** The main command name */
|
||||
private static final String NAME = "luckpermsbungee";
|
||||
|
||||
/** The command aliases */
|
||||
private static final String[] ALIASES = {"lpb", "bperm", "bperms", "bpermission", "bpermissions"};
|
||||
|
||||
/** The main command name + aliases, prefixed with '/' */
|
||||
private static final String[] SLASH_ALIASES = Stream.concat(
|
||||
Stream.of(NAME),
|
||||
Arrays.stream(ALIASES)
|
||||
).map(s -> '/' + s).toArray(String[]::new);
|
||||
|
||||
/**
|
||||
* The aliases to register, {@link #ALIASES} + {@link #SLASH_ALIASES}.
|
||||
*
|
||||
* <p>SLASH_ALIASES are registered too so the console can run '/lpb'
|
||||
* in the same way as 'lpb'.</p>
|
||||
*/
|
||||
private static final String[] ALIASES_TO_REGISTER = Stream.concat(
|
||||
Arrays.stream(ALIASES),
|
||||
Arrays.stream(SLASH_ALIASES)
|
||||
).toArray(String[]::new);
|
||||
|
||||
private final LPBungeePlugin plugin;
|
||||
private final CommandManager manager;
|
||||
|
||||
public BungeeCommandExecutor(LPBungeePlugin plugin, CommandManager manager) {
|
||||
super("luckpermsbungee", null, "lpb", "bperm", "bperms", "bpermission", "bpermissions");
|
||||
super(NAME, null, ALIASES_TO_REGISTER);
|
||||
this.plugin = plugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public void register() {
|
||||
ProxyServer proxy = this.plugin.getBootstrap().getProxy();
|
||||
proxy.getPluginManager().registerCommand(this.plugin.getBootstrap(), this);
|
||||
|
||||
// don't allow players to execute the slash aliases - these are just for the console.
|
||||
proxy.getDisabledCommands().addAll(Arrays.asList(SLASH_ALIASES));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
Sender lpSender = this.plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = CommandManager.stripQuotes(ARGUMENT_SPLITTER.splitToList(ARGUMENT_JOINER.join(args)));
|
||||
|
||||
this.manager.onCommand(lpSender, "lpb", arguments);
|
||||
Sender wrapped = this.plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = ArgumentTokenizer.EXECUTE.tokenizeInput(args);
|
||||
this.manager.executeCommand(wrapped, "lpb", arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
|
||||
Sender lpSender = this.plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = CommandManager.stripQuotes(TAB_COMPLETE_ARGUMENT_SPLITTER.splitToList(ARGUMENT_JOINER.join(args)));
|
||||
|
||||
return this.manager.onTabComplete(lpSender, arguments);
|
||||
Sender wrapped = this.plugin.getSenderFactory().wrap(sender);
|
||||
List<String> arguments = ArgumentTokenizer.TAB_COMPLETE.tokenizeInput(args);
|
||||
return this.manager.tabCompleteCommand(wrapped, arguments);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.bungee;
|
||||
|
||||
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.config.generic.adapter.ConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
|
||||
@@ -73,8 +73,12 @@ public class BungeeSchedulerAdapter implements SchedulerAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
public void shutdownScheduler() {
|
||||
Iterators.tryIterate(this.tasks, ScheduledTask::cancel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdownExecutor() {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@
|
||||
package me.lucko.luckperms.bungee;
|
||||
|
||||
import me.lucko.luckperms.bungee.event.TristateCheckEvent;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.sender.SenderFactory;
|
||||
import me.lucko.luckperms.common.util.TextUtils;
|
||||
@@ -39,8 +38,8 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BungeeSenderFactory extends SenderFactory<CommandSender> {
|
||||
public BungeeSenderFactory(LuckPermsPlugin plugin) {
|
||||
public class BungeeSenderFactory extends SenderFactory<LPBungeePlugin, CommandSender> {
|
||||
public BungeeSenderFactory(LPBungeePlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@@ -79,4 +78,9 @@ public class BungeeSenderFactory extends SenderFactory<CommandSender> {
|
||||
protected boolean hasPermission(CommandSender sender, String node) {
|
||||
return sender.hasPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCommand(CommandSender sender, String command) {
|
||||
getPlugin().getBootstrap().getProxy().getPluginManager().dispatchCommand(sender, command);
|
||||
}
|
||||
}
|
||||
@@ -36,13 +36,19 @@ import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
import net.luckperms.api.platform.Platform;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.api.plugin.PluginDescription;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Bootstrap plugin for LuckPerms running on BungeeCord.
|
||||
@@ -72,12 +78,15 @@ public class LPBungeeBootstrap extends Plugin implements LuckPermsBootstrap {
|
||||
/**
|
||||
* The time when the plugin was enabled
|
||||
*/
|
||||
private long startTime;
|
||||
private Instant startTime;
|
||||
|
||||
// load/enable latches
|
||||
private final CountDownLatch loadLatch = new CountDownLatch(1);
|
||||
private final CountDownLatch enableLatch = new CountDownLatch(1);
|
||||
|
||||
// if the plugin has been loaded on an incompatible version
|
||||
private boolean incompatibleVersion = false;
|
||||
|
||||
public LPBungeeBootstrap() {
|
||||
this.schedulerAdapter = new BungeeSchedulerAdapter(this);
|
||||
this.classLoader = new ReflectionClassLoader(this);
|
||||
@@ -110,6 +119,11 @@ public class LPBungeeBootstrap extends Plugin implements LuckPermsBootstrap {
|
||||
public void onLoad() {
|
||||
this.logger = new JavaPluginLogger(getLogger());
|
||||
|
||||
if (checkIncompatibleVersion()) {
|
||||
this.incompatibleVersion = true;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.plugin.load();
|
||||
} finally {
|
||||
@@ -119,7 +133,22 @@ public class LPBungeeBootstrap extends Plugin implements LuckPermsBootstrap {
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
this.startTime = System.currentTimeMillis();
|
||||
if (this.incompatibleVersion) {
|
||||
getLogger().severe("----------------------------------------------------------------------");
|
||||
getLogger().severe("Your proxy version is not compatible with this build of LuckPerms. :(");
|
||||
getLogger().severe("");
|
||||
getLogger().severe("This is most likely because you are using an old/outdated version of BungeeCord.");
|
||||
getLogger().severe("If you need 1.7 support, replace your BungeeCord.jar file with the latest build of");
|
||||
getLogger().severe("'Travertine' from here:");
|
||||
getLogger().severe("==> https://papermc.io/downloads#Travertine");
|
||||
getLogger().severe("");
|
||||
getLogger().severe("The proxy will now shutdown.");
|
||||
getLogger().severe("----------------------------------------------------------------------");
|
||||
getProxy().stop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.startTime = Instant.now();
|
||||
try {
|
||||
this.plugin.enable();
|
||||
} finally {
|
||||
@@ -129,6 +158,10 @@ public class LPBungeeBootstrap extends Plugin implements LuckPermsBootstrap {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (this.incompatibleVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.plugin.disable();
|
||||
}
|
||||
|
||||
@@ -150,7 +183,7 @@ public class LPBungeeBootstrap extends Plugin implements LuckPermsBootstrap {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartupTime() {
|
||||
public Instant getStartupTime() {
|
||||
return this.startTime;
|
||||
}
|
||||
|
||||
@@ -218,18 +251,46 @@ public class LPBungeeBootstrap extends Plugin implements LuckPermsBootstrap {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> getPlayerList() {
|
||||
return getProxy().getPlayers().stream().map(ProxiedPlayer::getName);
|
||||
public Collection<String> getPlayerList() {
|
||||
Collection<ProxiedPlayer> players = getProxy().getPlayers();
|
||||
List<String> list = new ArrayList<>(players.size());
|
||||
for (ProxiedPlayer player : players) {
|
||||
list.add(player.getName());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<UUID> getOnlinePlayers() {
|
||||
return getProxy().getPlayers().stream().map(ProxiedPlayer::getUniqueId);
|
||||
public Collection<UUID> getOnlinePlayers() {
|
||||
Collection<ProxiedPlayer> players = getProxy().getPlayers();
|
||||
List<UUID> list = new ArrayList<>(players.size());
|
||||
for (ProxiedPlayer player : players) {
|
||||
list.add(player.getUniqueId());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayerOnline(UUID uniqueId) {
|
||||
ProxiedPlayer player = getProxy().getPlayer(uniqueId);
|
||||
return player != null && player.isConnected();
|
||||
return getProxy().getPlayer(uniqueId) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String identifyClassLoader(ClassLoader classLoader) throws Exception {
|
||||
Class<?> pluginClassLoader = Class.forName("net.md_5.bungee.api.plugin.PluginClassloader");
|
||||
if (pluginClassLoader.isInstance(classLoader)) {
|
||||
PluginDescription desc = (PluginDescription) pluginClassLoader.getDeclaredField("desc").get(classLoader);
|
||||
return desc.getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean checkIncompatibleVersion() {
|
||||
try {
|
||||
Class.forName("com.google.gson.internal.bind.TreeTypeAdapter");
|
||||
return false;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 502 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user