Compare commits

...
105 Commits
Author SHA1 Message Date
Luck 64838708ab Release version 4.2.0
blaze it
2018-05-06 17:16:36 +01:00
Luck 91b7af52ac Use the servers uuid cache in the output to /lp search if LP doesn't have data (#974) 2018-05-06 16:20:08 +01:00
Luck d3dded8791 Fix jedis shading (#930) 2018-05-06 15:58:40 +01:00
Luck 022b385c0a Fix /lp search query (#972) 2018-05-05 18:39:13 +01:00
Luck 7ee9b93365 Convert bulkupdate & search functionality to use PreparedStatements (#972) 2018-05-05 18:17:48 +01:00
Luck c4c98aaabf Improve the behaviour of the APIs (now somewhat redundant) holder refresh method 2018-05-04 23:17:06 +01:00
Luck 10c0efaa5d Fix bad caching logic resulting in super high CPU usage 2018-05-04 23:12:46 +01:00
Luck d8a7d8de4a Throw a more detailed error when database connection info is missing 2018-05-04 21:27:57 +01:00
Luck ab8b675bae Add flag to exclude users from an export (#961) 2018-05-04 18:19:52 +01:00
Luck 194b602fd6 Implement different comparison methods for /lp search (#917) 2018-05-04 18:11:11 +01:00
Luck 7da0c58b76 Improve consistency of contextual primary group caching 2018-05-04 17:24:40 +01:00
Luck 2dbbea4993 Remove the locks in NodeMap to ease thread contention when lots of processes are resolving inheritance & refactor the way LocalizedNodes are created (#734) 2018-05-04 16:16:12 +01:00
Luck 55d59bb1c4 Make auto-op changes take effect (almost) immediately (#943)
"almost immediately" is better than "after a relog" ;)
2018-05-03 20:21:52 +01:00
Luck a6facf7492 Refactor the way holder caches are invalidated in order to improve consistency (#734) 2018-05-03 19:36:10 +01:00
Luck b8a1871cf1 Fix guava being accidentally shaded 2018-05-03 13:46:17 +01:00
Luck f556c75d94 Allow display names to be set in specific contexts (#963) 2018-05-02 21:27:21 +01:00
Luck 58bd7de66a Implement equals, hashcode and toString for NodeTypes 2018-05-02 20:35:20 +01:00
Luck 4547b52748 Refactor extended node types, general cleanup 2018-05-02 20:18:57 +01:00
Luck b9acb84119 Optimize WildcardProcessor 2018-05-01 00:20:39 +01:00
Luck e3a783c546 Maybe fix problems with symlinks (#956) 2018-04-30 14:44:09 +01:00
Luck 2e136666be Remove storage buffers 2018-04-29 11:33:51 +01:00
Luck 7d089cb5f0 Refactor configurate deo serialization of permission data, add support for the TOML format 2018-04-28 21:26:59 +01:00
Luck 3784d904fb Some small fixes and changes for ContextSet implementations 2018-04-27 18:50:36 +01:00
Luck fef6ebf793 Context set values should be lowercase'd too 2018-04-26 19:51:05 +01:00
Luck 316e177c1d Exclude temporary file changes from FileWatcher (#945) 2018-04-26 18:44:53 +01:00
Luck 4cdff14c7c Apply improvements to the caches in AbstractContextManager (#929) 2018-04-25 21:14:16 +01:00
Luck 97121bc719 Add some missing null check annotations 2018-04-25 21:02:17 +01:00
Luck 1312aac349 Add promote and demote methods to the API (#938) 2018-04-25 19:58:56 +01:00
Bogdan 8a5c9ddef2 Added explicit column names in INSERT queries. (#939) 2018-04-25 18:27:28 +01:00
Luck 55382519a1 Fix sponge split-storage config section being in the wrong section of the config (#928) 2018-04-25 17:30:56 +01:00
Luck cbb562b603 Fix sponge subject storage 2018-04-25 17:30:02 +01:00
Luck ba51f803ba add more logging to the importer 2018-04-25 17:15:30 +01:00
Luck d73543408e Fix misplaced sponge config options 2018-04-23 21:31:04 +01:00
Luck 7d90dba08b Update some dependency versions 2018-04-21 23:26:34 +01:00
Luck f11ebe6166 Replace file logger with json based system 2018-04-21 18:16:35 +01:00
Luck 1b917f0901 Fix init error in SeparatedConfigurateDao (#924 & #925) 2018-04-21 17:03:59 +01:00
Luck 328353d053 Implement the option to combine yaml/json/hocon storage files into one 2018-04-20 21:59:32 +01:00
Luck 4e87489dc1 Output meta in inheritance order in the 'meta info' command (#908) 2018-04-20 15:04:29 +01:00
Luck 8e5bcdd5ea Move schema files to a namespaced package (#899) 2018-04-20 14:59:06 +01:00
Luck 882a29029e Account for Sponge permission defaults in SpongeSenderFactory#getPermissionValue (fixes #920) 2018-04-20 14:17:29 +01:00
Luck 4704c5c975 Add full diff to the log when webeditor data is applied (#922) 2018-04-20 14:06:35 +01:00
Luck 957365ab91 refactor inheritance graphs slightly 2018-04-20 14:00:50 +01:00
Luck f8d34d7f46 Fix compile 2018-04-09 20:58:52 +01:00
Luck cb185e4827 Minor misc changes 2018-04-08 22:58:15 +01:00
Luck f5c6b9e3d4 Add 'permission clear' command (#893) 2018-04-04 18:46:01 +01:00
Luck 96f0f46b3e Update readme 2018-04-04 17:10:33 +01:00
Luck 6a5b7ce3a1 derp 2018-04-04 15:29:45 +01:00
Luck f33c540efb Register Sponge PermDescriptions to the LP permission registry 2018-04-03 21:56:15 +01:00
Luck 7684ac5d3a Add extra parameter to EventBus#subscribe which allows a handler to be bound to a plugin 2018-04-02 17:26:02 +01:00
Luck c13b01da01 misc cleanup 2018-04-02 16:02:55 +01:00
Luck 3453f05aca Copy usernames in the GroupManager migration (#883) 2018-04-02 13:34:30 +01:00
Luck c8bb85a06b Don't intern strings in permission checking process 2018-03-31 22:13:10 +01:00
Luck 2aabc9902f Rename verbose paste to verbose upload 2018-03-31 22:09:58 +01:00
Luck 6dba778e60 Catch exceptions thrown in repeating tasks to avoid subsequent executions from being cancelled 2018-03-31 11:13:27 +01:00
Luck cbeaaca7af Fix shutdown hang (#881) 2018-03-31 11:11:42 +01:00
Luck 0e69c8902d Revert f63d6cf 2018-03-31 10:26:22 +01:00
Luck f63d6cfced Properly escape sql query for loadTrack (#877) 2018-03-30 21:50:03 +01:00
Luck 72f9de6cc7 Fix resolving data directory on Sponge servers with a custom config dir location (#875) 2018-03-30 21:37:33 +01:00
Luck 509e89b9cf Clarify the showtracks output (#862) 2018-03-30 11:58:32 +01:00
Luck 90cce19baf Make the world-rewrite map case insensitive (#863) 2018-03-30 11:54:17 +01:00
Luck e4e93b1af1 Improve the way player uuid data is saved/stored. Add a warning message to catch ip forwarding issues 2018-03-29 21:46:55 +01:00
funniray 8f30176edd Fixed command arguments for Nukkit (#871) 2018-03-27 16:43:49 +01:00
Luck 4923d10b86 Encode editor payload using UTF-8 (#841) 2018-03-18 20:58:33 +00:00
Luck bd3a4e1ad7 Fix Sql messenger table name & bug which meant entries were only received after a 1 min delay 2018-03-18 18:58:53 +00:00
Luck 0f99a6c5ca Fix recursive proxying in PhasedStorage
ugh
2018-03-18 18:31:30 +00:00
Luck 0150da94a8 Apply table prefix to the SQL messenger 2018-03-18 17:38:52 +00:00
Luck b8da286f64 Replace huge forwarding classes with java Proxy instances 2018-03-18 17:36:07 +00:00
Luck da797f154d Implement Messaging Service using SQL (#534) 2018-03-18 16:02:04 +00:00
Luck 926195efc4 Fix Sponge persisted subject parent serialisation 2018-03-18 11:41:13 +00:00
Luck 8c1c5c820c Fix Sponge subject inheritance 2018-03-18 10:41:27 +00:00
Luck f63f652edb Fix parentadd and parentremove sponge commands 2018-03-18 10:09:21 +00:00
Luck 174ef187e8 Rename role parameter in PermissionDescription.Builder#assign 2018-03-18 10:02:16 +00:00
Luck d1e76f401a Reorganise the default configuration 2018-03-17 21:03:50 +00:00
Luck d52983c5af Fix tristate check event on BungeeCord for console senders 2018-03-17 15:03:40 +00:00
Luck 4773934481 Fix race condition in the import process (#833) 2018-03-14 22:01:52 +00:00
Luck dbfc524180 Fix NPE in Message#asString (fixes #822, #823, #824) 2018-03-13 15:30:35 +00:00
Luck 60aa7c6104 Fix compile 2018-03-12 21:27:23 +00:00
Luck 907d716929 Reorganise commands 2018-03-12 21:25:39 +00:00
Luck 1689a8abe2 Fix adding null json values (#818) 2018-03-12 19:01:38 +00:00
Luck 5db3820df4 A few minor API javadoc changes 2018-03-12 18:58:11 +00:00
Luck f969e2e52b Strip color when sending messages to the fallback logger 2018-03-09 16:43:29 +00:00
Luck cde2306079 Compress editor/verbose/treeview data using gzip before uploading 2018-03-09 16:21:45 +00:00
Luck f6c440c172 Further improvements to the Sponge service design 2018-03-08 21:51:25 +00:00
Luck 1b98667365 Fix IsolatedClassLoader on Java 9 (#815) 2018-03-08 18:36:41 +00:00
Luck bf69d5314e Implement Sponge subject lookup queries using CachedData from LP common 2018-03-07 23:50:23 +00:00
Luck 6d2ea659a4 Fix errors relating to sponge plugin parameter being an illegal argument (#810) 2018-03-03 20:43:41 +00:00
Luck 0d89840179 Reduce the number of entries sent to the verbose viewer, cleanup old hikari try..catches 2018-03-03 20:41:46 +00:00
Luck f93e8fdccd Always fire SubjectDataUpdateEvent async 2018-03-03 16:27:43 +00:00
Luck 68e4d36f40 Extract common plugin behaviour into an abstract class 2018-03-03 16:26:37 +00:00
Luck cd5447de38 Submit users/groups to the editor in weight order 2018-03-01 18:26:32 +00:00
Luck 6c0bb61cb1 Remove sponge migration commands 2018-03-01 11:03:22 +00:00
Luck d9a45b1090 Implement SubjectDataUpdateEvent (#753) 2018-03-01 10:58:08 +00:00
Luck 7549b3eb9e Return a dummy value instead of throwing an exception when an offline player is queried via Vault (#806) 2018-03-01 10:08:09 +00:00
Luck 8f82ef7eb4 Add copyFrom method to Node.Builder 2018-03-01 09:19:26 +00:00
Luck fbe84322b5 Cleanup parts of the sponge service implementation 2018-03-01 08:48:39 +00:00
Luck 98fb9946e4 Refactor Contexts class 2018-02-28 19:13:21 +00:00
Luck 984bc5860f Set allow-invalid-usernames to true by default for Nukkit (#798) 2018-02-26 17:35:34 +00:00
Luck a42d27f056 Don't intern strings in ContextSets (#797) 2018-02-26 17:27:28 +00:00
Luck aa4833ed74 Fix NPEs caused in LPPermissionMap (#794) 2018-02-24 22:59:18 +00:00
Luck 6704ac4b46 Fully relocate the jedis driver 2018-02-24 18:20:56 +00:00
Luck 4e4ec8e608 Bump caffeine & hikari version 2018-02-24 14:15:51 +00:00
Luck 4f4a387f04 Run the permissible monitoring injector twice 2018-02-24 14:08:36 +00:00
Luck d0143f9e54 Fix issue with loading on old CraftBukkit versions 2018-02-24 14:04:22 +00:00
Luck b2175e885f Fix compat with older Gson versions (#791) 2018-02-24 13:50:38 +00:00
Luck 68dd96e563 Properly bump version 2018-02-23 22:16:52 +00:00
507 changed files with 18620 additions and 14255 deletions

No files matched your search

+9 -10
View File
@@ -5,24 +5,23 @@ LuckPerms is an advanced permissions implementation aiming to be a fast, reliabl
LuckPerms also includes an extensive API for developers, and support for a variety of Minecraft server software & data storage options.
The main features of the project are detailed on this wiki page: [Why LuckPerms?](https://github.com/lucko/LuckPerms/wiki/Why-LuckPerms)
* [Spigot Plugin Release Page](https://www.spigotmc.org/resources/luckperms-an-advanced-permissions-system.28140/ "Spigot Plugin Page")
* [Sponge Plugin Release Page](https://forums.spongepowered.org/t/luckperms-an-advanced-permissions-system/14274 "Sponge Plugin Page")
Still not convinced? More information can be found on the wiki, under: [Why LuckPerms?](https://github.com/lucko/LuckPerms/wiki/Why-LuckPerms)
## Useful Links
* **Downloads** - <https://ci.lucko.me/job/LuckPerms>
* **Wiki** - <https://github.com/lucko/LuckPerms/wiki>
The latest **downloads** can be found on the [project's homepage](https://luckperms.github.io/).
More information about the project & how to use the plugin can be found in the [wiki](https://github.com/lucko/LuckPerms/wiki).
## Building
LuckPerms uses Maven to handle dependencies.
#### Requirements
* Java 8 JDK
* Maven 3.3.x (the older versions will not work.)
* Java 8 JDK or newer
* Maven 3.3.x or newer (the older versions will not work.)
* Git
#### Then run
#### Compiling from source
```sh
git clone https://github.com/lucko/LuckPerms.git
cd LuckPerms/
@@ -42,7 +41,7 @@ The project is split up into 5 seperate modules.
* **API** - The public, semantically versioned API used by other plugins wishing to integrate with and retrieve data from LuckPerms. This module (for the most part) does not contain any implementation itself, and is provided by the plugin.
* **Common** - The common module contains most of the code which implements the respective LuckPerms plugins. This abstract module reduces duplicated code throughout the project.
* **Bukkit, BungeeCord & Sponge** - Each use the common module to implement plugins on the respective server platforms.
* **Bukkit, BungeeCord, Sponge & Nukkit** - Each use the common module to implement plugins on the respective server platforms.
## License
LuckPerms is licensed under the permissive MIT license. Please see [`LICENSE.txt`](https://github.com/lucko/LuckPerms/blob/master/LICENSE.txt) for more info.
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>4.1-SNAPSHOT</version>
<version>4.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -47,8 +47,6 @@ public interface ActionLogger {
/**
* Gets a {@link Log} instance from the plugin storage.
*
* <p>Returns the same result as {@link Storage#getLog()}.</p>
*
* @return a log instance
* @see Storage#getLog()
*/
@@ -25,16 +25,21 @@
package me.lucko.luckperms.api;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/**
* Encapsulates the options and settings for a permission or meta lookup.
* Encapsulates the {@link ContextSet contexts} and {@link LookupSetting settings} for
* a permission or meta lookup.
*
* <p>This class is immutable.</p>
*
@@ -53,12 +58,24 @@ public class Contexts {
*/
public static final String WORLD_KEY = "world";
/**
* The default {@link LookupSetting}s.
*/
private static final EnumSet<LookupSetting> DEFAULT_SETTINGS = EnumSet.of(
LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER,
LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD,
LookupSetting.RESOLVE_INHERITANCE,
LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER,
LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD
);
/**
* A 'global' or default contexts instance.
*
* Simply passes an empty context set, with all accumulation settings set to true.
* <p>Formed of an empty {@link ContextSet} and all inclusion and
* inheritance {@link LookupSetting}s applied.</p>
*/
private static final Contexts GLOBAL = new Contexts(ContextSet.empty(), true, true, true, true, true, false);
private static final Contexts GLOBAL = new Contexts(ImmutableContextSet.empty(), ImmutableSet.copyOf(DEFAULT_SETTINGS));
/**
* Gets the {@link FullySatisfiedContexts} instance.
@@ -71,7 +88,10 @@ public class Contexts {
}
/**
* A contexts instance with no defined context.
* Returns a 'global' or default contexts instance.
*
* <p>Formed of an empty {@link ContextSet} and all inclusion and
* inheritance {@link LookupSetting}s applied.</p>
*
* @return the global contexts
* @since 3.3
@@ -81,140 +101,208 @@ public class Contexts {
return GLOBAL;
}
/**
* Creates a new {@link Contexts} instance.
*
* @param contextSet the context set
* @param includeNodesSetWithoutServer the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER}
* @param includeNodesSetWithoutWorld the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD}
* @param resolveInheritance the value of {@link LookupSetting#RESOLVE_INHERITANCE}
* @param applyParentsWithoutServer the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER}
* @param applyParentsWithoutWorld the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD}
* @param isOp the value of {@link LookupSetting#IS_OP}
* @return a new instance
*/
@Nonnull
public static Contexts of(@Nonnull ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
public static Contexts of(@Nonnull ContextSet contextSet, boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
Objects.requireNonNull(contextSet, "contextSet");
EnumSet<LookupSetting> settings = formSettings(
includeNodesSetWithoutServer,
includeNodesSetWithoutWorld,
resolveInheritance,
applyParentsWithoutServer,
applyParentsWithoutWorld,
isOp
);
if (contextSet.isEmpty() && DEFAULT_SETTINGS.equals(settings)) {
return GLOBAL;
}
return new Contexts(contextSet.makeImmutable(), ImmutableSet.copyOf(settings));
}
/**
* Creates a new {@link Contexts} instance.
*
* @param contextSet the context set
* @param settings the settings
* @return a new instance
*/
public static Contexts of(@Nonnull ContextSet contextSet, @Nonnull Set<LookupSetting> settings) {
Objects.requireNonNull(contextSet, "contextSet");
Objects.requireNonNull(settings, "settings");
EnumSet<LookupSetting> settingsCopy = EnumSet.copyOf(settings);
if (contextSet.isEmpty() && DEFAULT_SETTINGS.equals(settingsCopy)) {
return GLOBAL;
}
return new Contexts(contextSet.makeImmutable(), ImmutableSet.copyOf(settingsCopy));
}
/**
* The contexts that apply for this lookup
*/
private final ImmutableContextSet context;
private final ImmutableContextSet contextSet;
/**
* If the target subject is OP. This is used to parse defaults on Bukkit,
* and is ignored on all other platforms.
*
* @since 2.12
* The settings for this lookup
*/
private final boolean op;
/**
* If global or non server specific nodes should be applied
*/
private final boolean includeGlobal;
/**
* If global or non world specific nodes should be applied
*/
private final boolean includeGlobalWorld;
/**
* If parent groups should be applied
*/
private final boolean applyGroups;
/**
* If global or non server specific group memberships should be applied
*/
private final boolean applyGlobalGroups;
/**
* If global or non world specific group memberships should be applied
*/
private final boolean applyGlobalWorldGroups;
private final ImmutableSet<LookupSetting> settings;
// cache hashcode - this class is immutable, and is used as an index in the permission cache.
private final int hashCode;
public Contexts(@Nonnull ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
this.context = Objects.requireNonNull(context, "context").makeImmutable();
this.includeGlobal = includeGlobal;
this.includeGlobalWorld = includeGlobalWorld;
this.applyGroups = applyGroups;
this.applyGlobalGroups = applyGlobalGroups;
this.applyGlobalWorldGroups = applyGlobalWorldGroups;
this.op = op;
/**
* Creates a new {@link Contexts} instance.
*
* @param contextSet the context set
* @param includeNodesSetWithoutServer the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER}
* @param includeNodesSetWithoutWorld the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD}
* @param resolveInheritance the value of {@link LookupSetting#RESOLVE_INHERITANCE}
* @param applyParentsWithoutServer the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER}
* @param applyParentsWithoutWorld the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD}
* @param isOp the value of {@link LookupSetting#IS_OP}
* @deprecated in favour of {@link #of(ContextSet, boolean, boolean, boolean, boolean, boolean, boolean)}
*/
@Deprecated
public Contexts(@Nonnull ContextSet contextSet, boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
this.contextSet = Objects.requireNonNull(contextSet, "contextSet").makeImmutable();
this.settings = ImmutableSet.copyOf(formSettings(
includeNodesSetWithoutServer,
includeNodesSetWithoutWorld,
resolveInheritance,
applyParentsWithoutServer,
applyParentsWithoutWorld,
isOp
));
this.hashCode = calculateHashCode();
}
protected Contexts(@Nonnull ImmutableContextSet contextSet, @Nonnull ImmutableSet<LookupSetting> settings) {
this.contextSet = contextSet;
this.settings = settings;
this.hashCode = calculateHashCode();
}
/**
* Gets the contexts that apply for this lookup
* Gets the {@link ContextSet} which represent these {@link Contexts}.
*
* @return an immutable set of context key value pairs
* @return an immutable context from this instance
* @since 2.13
*/
@Nonnull
public ContextSet getContexts() {
return this.context;
return this.contextSet;
}
/**
* Gets if the target subject is OP. This is used to parse defaults on Bukkit,
* and is ignored on all other platforms.
* Gets the set of {@link LookupSetting}s which represent these {@link Contexts}.
*
* @return true if op defaults should be included
* @return the settings
* @since 4.2
*/
@Nonnull
public Set<LookupSetting> getSettings() {
return this.settings;
}
/**
* Gets if the given {@link LookupSetting} is set.
*
* @param setting the setting
* @return the value
* @since 4.2
*/
public boolean hasSetting(@Nonnull LookupSetting setting) {
return this.settings.contains(setting);
}
/**
* Gets the value of {@link LookupSetting#IS_OP}.
*
* @return the value
* @see LookupSetting#IS_OP
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isOp() {
return this.op;
return hasSetting(LookupSetting.IS_OP);
}
/**
* Gets if global or non server specific nodes should be applied
* Gets the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER}.
*
* @return true if global or non server specific nodes should be applied
* @return the value
* @see LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isIncludeGlobal() {
return this.includeGlobal;
return hasSetting(LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER);
}
/**
* Gets if global or non world specific nodes should be applied
* Gets the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD}.
*
* @return true if global or non world specific nodes should be applied
* @return the value
* @see LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isIncludeGlobalWorld() {
return this.includeGlobalWorld;
return hasSetting(LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD);
}
/**
* Gets if parent groups should be applied
* Gets the value of {@link LookupSetting#RESOLVE_INHERITANCE}.
*
* @return true if parent groups should be applied
* @return the value
* @see LookupSetting#RESOLVE_INHERITANCE
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isApplyGroups() {
return this.applyGroups;
return hasSetting(LookupSetting.RESOLVE_INHERITANCE);
}
/**
* Gets if global or non server specific group memberships should be applied
* Gets the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER}.
*
* @return true if global or non server specific group memberships should be applied
* @return the value
* @see LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isApplyGlobalGroups() {
return this.applyGlobalGroups;
return hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER);
}
/**
* Gets if global or non world specific group memberships should be applied
* Gets the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD}.
*
* @return true if global or non world specific group memberships should be applied
* @return the value
* @see LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isApplyGlobalWorldGroups() {
return this.applyGlobalWorldGroups;
return hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD);
}
@Nonnull
@Override
public String toString() {
return "Contexts(" +
"context=" + this.context + ", " +
"op=" + this.op + ", " +
"includeGlobal=" + this.includeGlobal + ", " +
"includeGlobalWorld=" + this.includeGlobalWorld + ", " +
"applyGroups=" + this.applyGroups + ", " +
"applyGlobalGroups=" + this.applyGlobalGroups + ", " +
"applyGlobalWorldGroups=" + this.applyGlobalWorldGroups + ")";
return "Contexts(contextSet=" + this.contextSet + ", settings=" + this.settings + ")";
}
@Override
@@ -223,26 +311,14 @@ public class Contexts {
if (o == allowAll()) return false;
if (!(o instanceof Contexts)) return false;
final Contexts that = (Contexts) o;
return this.context.equals(that.context) &&
this.op == that.op &&
this.includeGlobal == that.includeGlobal &&
this.includeGlobalWorld == that.includeGlobalWorld &&
this.applyGroups == that.applyGroups &&
this.applyGlobalGroups == that.applyGlobalGroups &&
this.applyGlobalWorldGroups == that.applyGlobalWorldGroups;
return this.contextSet.equals(that.contextSet) && this.settings.equals(that.settings);
}
private int calculateHashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.context.hashCode();
result = result * PRIME + (this.op ? 79 : 97);
result = result * PRIME + (this.includeGlobal ? 79 : 97);
result = result * PRIME + (this.includeGlobalWorld ? 79 : 97);
result = result * PRIME + (this.applyGroups ? 79 : 97);
result = result * PRIME + (this.applyGlobalGroups ? 79 : 97);
result = result * PRIME + (this.applyGlobalWorldGroups ? 79 : 97);
result = result * PRIME + this.contextSet.hashCode();
result = result * PRIME + this.settings.hashCode();
return result;
}
@@ -250,4 +326,28 @@ public class Contexts {
public int hashCode() {
return this.hashCode;
}
private static EnumSet<LookupSetting> formSettings(boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
EnumSet<LookupSetting> settings = EnumSet.noneOf(LookupSetting.class);
if (includeNodesSetWithoutServer) {
settings.add(LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER);
}
if (includeNodesSetWithoutWorld) {
settings.add(LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD);
}
if (resolveInheritance) {
settings.add(LookupSetting.RESOLVE_INHERITANCE);
}
if (applyParentsWithoutServer) {
settings.add(LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER);
}
if (applyParentsWithoutWorld) {
settings.add(LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD);
}
if (isOp) {
settings.add(LookupSetting.IS_OP);
}
return settings;
}
}
@@ -26,9 +26,11 @@
package me.lucko.luckperms.api;
/**
* Represents the result of a mutation call.
* Represents the result of a data mutation call on a LuckPerms object.
*
* <p>Usually as the result to a call on a {@link PermissionHolder} or {@link Track}.</p>
*/
public enum DataMutateResult {
public enum DataMutateResult implements MutateResult {
/**
* Indicates the mutation was a success
@@ -50,39 +52,14 @@ public enum DataMutateResult {
*/
FAIL(false);
private final boolean value;
private final boolean success;
DataMutateResult(boolean value) {
this.value = value;
DataMutateResult(boolean success) {
this.success = success;
}
/**
* Gets a boolean representation of the result.
*
* @return a boolean representation
*/
public boolean asBoolean() {
return this.value;
}
/**
* Gets if the result indicates a success
*
* @return if the result indicates a success
* @since 3.4
*/
@Override
public boolean wasSuccess() {
return this.value;
return this.success;
}
/**
* Gets if the result indicates a failure
*
* @return if the result indicates a failure
* @since 3.4
*/
public boolean wasFailure() {
return !this.value;
}
}
@@ -0,0 +1,130 @@
/*
* 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.api;
import java.util.Optional;
import javax.annotation.Nonnull;
/**
* Encapsulates the result of {@link User}s demotion along a {@link Track}.
*
* @since 4.2
*/
public interface DemotionResult extends MutateResult {
/**
* Gets the status of the result.
*
* @return the status
*/
@Nonnull
Status getStatus();
@Override
default boolean wasSuccess() {
return getStatus().wasSuccess();
}
/**
* Gets the name of the group the user was demoted from, if applicable.
*
* <p>Will only be present for results with a {@link #getStatus() status} of
* {@link Status#SUCCESS} or {@link Status#REMOVED_FROM_FIRST_GROUP}.</p>
*
* <p>The value will also be set for results with the {@link Status#MALFORMED_TRACK} status,
* with this value marking the group which no longer exists.</p>
*
* @return the group the user was demoted from.
*/
@Nonnull
Optional<String> getGroupFrom();
/**
* Gets the name of the group the user was demoted from, if applicable.
*
* <p>Will only be present for results with a {@link #getStatus() status} of
* {@link Status#SUCCESS}.</p>
*
* @return the group the user was demoted to.
*/
@Nonnull
Optional<String> getGroupTo();
/**
* The result status
*/
enum Status implements MutateResult {
/**
* Indicates that the user was demoted normally.
*/
SUCCESS(true),
/**
* Indicates that the user was removed from the first group in the track.
*
* <p>This usually occurs when the user is currently on the first group, and was demoted
* "over the start" of the track.</p>
*/
REMOVED_FROM_FIRST_GROUP(true),
/**
* Indicates that the previous group in the track no longer exists.
*/
MALFORMED_TRACK(false),
/**
* Indicates that the user isn't a member of any of the groups on this track.
*/
NOT_ON_TRACK(false),
/**
* Indicates that the implementation was unable to determine the users current position on
* this track.
*
* <p>This usually occurs when the user is on more than one group on the track.</p>
*/
AMBIGUOUS_CALL(false),
/**
* An undefined failure occurred.
*/
UNDEFINED_FAILURE(false);
private final boolean success;
Status(boolean success) {
this.success = success;
}
@Override
public boolean wasSuccess() {
return this.success;
}
}
}
@@ -25,9 +25,11 @@
package me.lucko.luckperms.api;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.api.caching.CachedData;
import me.lucko.luckperms.api.caching.MetaContexts;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import javax.annotation.Nonnull;
@@ -58,7 +60,7 @@ public final class FullySatisfiedContexts extends Contexts {
}
private FullySatisfiedContexts() {
super(ContextSet.empty(), true, true, true, true, true, false);
super(ImmutableContextSet.empty(), ImmutableSet.copyOf(Contexts.global().getSettings()));
}
@Nonnull
@@ -0,0 +1,64 @@
/*
* 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.api;
/**
* The various lookup setting flags for {@link Contexts}.
*
* @since 4.2
*/
public enum LookupSetting {
/**
* If the target subject is OP
*/
IS_OP,
/**
* If global or non-server-specific nodes should be applied
*/
INCLUDE_NODES_SET_WITHOUT_SERVER,
/**
* If global or non-world-specific nodes should be applied
*/
INCLUDE_NODES_SET_WITHOUT_WORLD,
/**
* If parent groups should be resolved
*/
RESOLVE_INHERITANCE,
/**
* If global or non-server-specific group memberships should be applied
*/
APPLY_PARENTS_SET_WITHOUT_SERVER,
/**
* If global or non-world-specific group memberships should be applied
*/
APPLY_PARENTS_SET_WITHOUT_WORLD
}
@@ -0,0 +1,74 @@
/*
* 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.api;
/**
* Represents the result to a "mutation" on an object.
*
* @since 4.2
*/
public interface MutateResult {
/**
* Instance of {@link MutateResult} which always reports success.
*/
MutateResult GENERIC_SUCCESS = () -> true;
/**
* Instance of {@link MutateResult} which always reports failure.
*/
MutateResult GENERIC_FAILURE = () -> false;
/**
* Gets if the operation which produced this result completed successfully.
*
* @return if the result indicates a success
*/
boolean wasSuccess();
/**
* Gets if the operation which produced this result failed.
*
* @return if the result indicates a failure
*/
default boolean wasFailure() {
return !wasSuccess();
}
/**
* Gets a boolean representation of the result.
*
* <p>A value of <code>true</code> marks that the operation {@link #wasSuccess() was a success}
* and a value of <code>false</code> marks that the operation
* {@link #wasFailure() was a failure}.</p>
*
* @return a boolean representation
*/
default boolean asBoolean() {
return wasSuccess();
}
}
@@ -25,13 +25,25 @@
package me.lucko.luckperms.api;
import com.google.common.base.Preconditions;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
import me.lucko.luckperms.api.nodetype.types.DisplayNameType;
import me.lucko.luckperms.api.nodetype.types.InheritanceType;
import me.lucko.luckperms.api.nodetype.types.MetaType;
import me.lucko.luckperms.api.nodetype.types.PrefixType;
import me.lucko.luckperms.api.nodetype.types.SuffixType;
import me.lucko.luckperms.api.nodetype.types.WeightType;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
@@ -60,7 +72,7 @@ import javax.annotation.concurrent.Immutable;
* <p></p>
* <ul>
* <li>{@link #getPermission() permission} - the actual permission string</li>
* <li>{@link #getValuePrimitive() value} - the value of the node (false for negated)</li>
* <li>{@link #getValue() value} - the value of the node (false for negated)</li>
* <li>{@link #isOverride() override} - if the node is marked as having special priority over other nodes</li>
* <li>{@link #getServer() server} - the specific server where this node should apply</li>
* <li>{@link #getWorld() world} - the specific world where this node should apply</li>
@@ -68,14 +80,23 @@ import javax.annotation.concurrent.Immutable;
* <li>{@link #getExpiry() expiry} - the time when this node should expire</li>
* </ul>
*
* <p>Nodes can also fall into the following sub categories.</p>
* <p>The 'permission' property of a {@link Node} is also used in some cases to represent state
* beyond a granted permission. This state is encapsulated by extra {@link NodeType} data which
* can be obtained from this instance using {@link #getTypeData(NodeTypeKey)}.</p>
*
* <p>Type data is mapped by {@link NodeTypeKey}s, which are usually stored as static members of the
* corresponding {@link NodeType} class under the <code>KEY</code> field.</p>
*
* <p>The current types are:</p>
* <p></p>
* <ul>
* <li>normal - just a regular permission</li>
* <li>{@link #isGroupNode() group node} - a "group node" marks that the holder should inherit data from another group</li>
* <li>{@link #isPrefix() prefix} - represents an assigned prefix</li>
* <li>{@link #isSuffix() suffix} - represents an assigned suffix</li>
* <li>{@link #isMeta() meta} - represents an assigned meta option</li>
* <li>{@link InheritanceType} - an "inheritance node" marks that the holder should inherit data from another group</li>
* <li>{@link PrefixType} - represents an assigned prefix</li>
* <li>{@link SuffixType} - represents an assigned suffix</li>
* <li>{@link MetaType} - represents an assigned meta option</li>
* <li>{@link WeightType} - marks the weight of the object holding this node</li>
* <li>{@link DisplayNameType} - marks the display name of the object holding this node</li>
* </ul>
*
* <p>The core node state must be immutable in all implementations.</p>
@@ -87,7 +108,10 @@ import javax.annotation.concurrent.Immutable;
public interface Node {
/**
* Gets the permission string
* Gets the permission string this node encapsulates.
*
* <p>The exact value of this string may vary for nodes which aren't regular
* permission settings.</p>
*
* @return the actual permission node
*/
@@ -95,56 +119,47 @@ public interface Node {
String getPermission();
/**
* Gets the value.
* Gets the value of the node.
*
* <p>A negated node would return a value of <code>false</code>.</p>
* <p>A negated setting would result in a value of <code>false</code>.</p>
*
* @return the permission's value
* @return the nodes value
*/
@Nonnull
default Boolean getValue() {
return getValuePrimitive();
}
boolean getValue();
/**
* Gets the value.
*
* <p>A negated node would return a value of <code>false</code>.</p>
*
* @return the permission's value
*/
boolean getValuePrimitive();
/**
* Gets the value of this node as a {@link Tristate}
* Gets the value of this node as a {@link Tristate}.
*
* @return the value of this node as a Tristate
*/
@Nonnull
default Tristate getTristate() {
return Tristate.fromBoolean(getValuePrimitive());
return Tristate.fromBoolean(getValue());
}
/**
* Gets if the node is negated
* Gets if the node is negated.
*
* <p>This is the inverse of the {@link #getValue() value}.</p>
*
* @return true if the node is negated
*/
default boolean isNegated() {
return !getValuePrimitive();
return !getValue();
}
/**
* Gets if this node is set to override explicitly.
*
* <p>This value does not persist across saves, and is therefore only useful for transient nodes</p>
* <p>This value does not persist across saves, and is therefore only
* useful for transient nodes.</p>
*
* @return true if this node is set to override explicitly
*/
boolean isOverride();
/**
* Gets the server this node applies on, if the node is server specific
* Gets the server this node applies on, if the node is server specific.
*
* @return an {@link Optional} containing the server, if one is defined
*/
@@ -152,7 +167,7 @@ public interface Node {
Optional<String> getServer();
/**
* Gets the world this node applies on, if the node is world specific
* Gets the world this node applies on, if the node is world specific.
*
* @return an {@link Optional} containing the world, if one is defined
*/
@@ -160,21 +175,21 @@ public interface Node {
Optional<String> getWorld();
/**
* Gets if this node is server specific
* Gets if this node is server specific.
*
* @return true if this node is server specific
*/
boolean isServerSpecific();
/**
* Gets if this node is server specific
* Gets if this node is server specific.
*
* @return true if this node is server specific
*/
boolean isWorldSpecific();
/**
* Gets if this node applies globally, and therefore has no specific context
* Gets if this node applies globally, and therefore has no specific context.
*
* @return true if this node applies globally, and has no specific context
* @since 3.1
@@ -182,7 +197,7 @@ public interface Node {
boolean appliesGlobally();
/**
* Gets if this node has any specific context in order for it to apply
* Gets if this node has any specific context in order for it to apply.
*
* @return true if this node has specific context
* @since 3.1
@@ -192,14 +207,17 @@ public interface Node {
/**
* Gets if this node should apply in the given context
*
* @param context the context key value pairs
* @param contextSet the context set
* @return true if the node should apply
* @since 2.13
*/
boolean shouldApplyWithContext(@Nonnull ContextSet context);
boolean shouldApplyWithContext(@Nonnull ContextSet contextSet);
/**
* Resolves any shorthand parts of this node and returns the full list
* Resolves any shorthand parts of this node and returns the full list of
* resolved nodes.
*
* <p>The list will not contain the exact permission itself.</p>
*
* @return a list of full nodes
*/
@@ -207,14 +225,14 @@ public interface Node {
List<String> resolveShorthand();
/**
* Gets if this node will expire in the future
* Gets if this node is assigned temporarily.
*
* @return true if this node will expire in the future
*/
boolean isTemporary();
/**
* Gets if this node will not expire
* Gets if this node is permanent (will not expire).
*
* @return true if this node will not expire
*/
@@ -223,7 +241,7 @@ public interface Node {
}
/**
* Gets a unix timestamp in seconds when this node will expire
* Gets the unix timestamp (in seconds) when this node will expire.
*
* @return the time in Unix time when this node will expire
* @throws IllegalStateException if the node is not temporary
@@ -231,7 +249,7 @@ public interface Node {
long getExpiryUnixTime() throws IllegalStateException;
/**
* Gets the date when this node will expire
* Gets the date when this node will expire.
*
* @return the {@link Date} when this node will expire
* @throws IllegalStateException if the node is not temporary
@@ -240,7 +258,9 @@ public interface Node {
Date getExpiry() throws IllegalStateException;
/**
* Gets the number of seconds until this permission will expire
* Gets the number of seconds until this permission will expire.
*
* <p>Will return a negative value if the node has already expired.</p>
*
* @return the number of seconds until this permission will expire
* @throws IllegalStateException if the node is not temporary
@@ -250,14 +270,14 @@ public interface Node {
/**
* Gets if the node has expired.
*
* <p>This also returns false if the node is not temporary.</p>
* <p>This returns false if the node is not temporary.</p>
*
* @return true if this node has expired
*/
boolean hasExpired();
/**
* Gets the extra contexts required for this node to apply
* Gets the extra contexts required for this node to apply.
*
* @return the extra contexts required for this node to apply
* @since 2.13
@@ -266,39 +286,32 @@ public interface Node {
ContextSet getContexts();
/**
* The same as {@link #getContexts()}, but also includes values for "server" and "world" keys if present.
* The same as {@link #getContexts()}, but also includes context pairs for
* "server" and "world" keys if present.
*
* @return the full contexts required for this node to apply
* @since 3.1
* @see Contexts#SERVER_KEY
* @see Contexts#WORLD_KEY
*/
@Nonnull
ContextSet getFullContexts();
/**
* Gets if this is a group node
* Gets if this node is a wildcard permission.
*
* @return true if this is a group node
*/
boolean isGroupNode();
/**
* Gets the name of the group, if this is a group node.
*
* @return the name of the group
* @throws IllegalStateException if this is not a group node. See {@link #isGroupNode()}
*/
@Nonnull
String getGroupName() throws IllegalStateException;
/**
* Gets if this node is a wildcard node
*
* @return true if this node is a wildcard node
* @return true if this node is a wildcard permission
*/
boolean isWildcard();
/**
* Gets the level of this wildcard, higher is more specific
* Gets the level of this wildcard.
*
* <p>The node <code>luckperms.*</code> has a wildcard level of 1.</p>
* <p>The node <code>luckperms.user.permission.*</code> has a wildcard level of 3.</p>
*
* <p>Nodes with a higher wildcard level are more specific and have priority over
* less specific nodes (nodes with a lower wildcard level).</p>
*
* @return the wildcard level
* @throws IllegalStateException if this is not a wildcard
@@ -306,55 +319,126 @@ public interface Node {
int getWildcardLevel() throws IllegalStateException;
/**
* Gets if this node is a meta node
* Gets if this node has any extra {@link NodeType} data attached to it.
*
* @return true if this node is a meta node
* @return if this node has any type data
* @since 4.2
*/
boolean isMeta();
boolean hasTypeData();
/**
* Gets the meta value from this node
* Gets the type data corresponding to the given <code>key</code>, if present.
*
* @return the meta value
* @throws IllegalStateException if this node is not a meta node
* @param key the key
* @param <T> the {@link NodeType} type
* @return the data, if present
* @since 4.2
*/
<T extends NodeType> Optional<T> getTypeData(NodeTypeKey<T> key);
/**
* Gets the type data corresponding to the given <code>key</code>, throwing an exception
* if no data is present.
*
* @param key the key
* @param <T> the {@link NodeType} type
* @return the data
* @throws IllegalStateException if data isn't present
* @since 4.2
*/
default <T extends NodeType> T typeData(NodeTypeKey<T> key) throws IllegalStateException {
return getTypeData(key)
.orElseThrow(() ->
new IllegalStateException("Node '" + getPermission() + "' does not have the '" + key.getTypeName() + "' type.")
);
}
/**
* Gets if this node has {@link InheritanceType} type data.
*
* @return true if this is a inheritance (group) node.
*/
default boolean isGroupNode() {
return getTypeData(InheritanceType.KEY).isPresent();
}
/**
* Gets the name of the inherited group if this node has {@link InheritanceType} type data,
* throwing an exception if the data is not present.
*
* @return the name of the group
* @throws IllegalStateException if this node doesn't have {@link InheritanceType} data
*/
@Nonnull
Map.Entry<String, String> getMeta() throws IllegalStateException;
default String getGroupName() throws IllegalStateException {
return typeData(InheritanceType.KEY).getGroupName();
}
/**
* Gets if this node is a prefix node
* Gets if this node has {@link MetaType} type data.
*
* @return true if this is a meta node.
*/
default boolean isMeta() {
return getTypeData(MetaType.KEY).isPresent();
}
/**
* Gets the meta entry if this node has {@link MetaType} type data,
* throwing an exception if the data is not present.
*
* @return the meta entry
* @throws IllegalStateException if this node doesn't have {@link MetaType} data
*/
@Nonnull
default Map.Entry<String, String> getMeta() throws IllegalStateException {
return typeData(MetaType.KEY);
}
/**
* Gets if this node has {@link PrefixType} type data.
*
* @return true if this node is a prefix node
*/
boolean isPrefix();
default boolean isPrefix() {
return getTypeData(PrefixType.KEY).isPresent();
}
/**
* Gets the prefix value from this node
* Gets the prefix entry if this node has {@link PrefixType} type data,
* throwing an exception if the data is not present.
*
* @return the prefix value
* @throws IllegalStateException if this node is a not a prefix node
* @return the meta entry
* @throws IllegalStateException if this node doesn't have {@link PrefixType} data
*/
@Nonnull
Map.Entry<Integer, String> getPrefix() throws IllegalStateException;
default Map.Entry<Integer, String> getPrefix() throws IllegalStateException {
return typeData(PrefixType.KEY).getAsEntry();
}
/**
* Gets if this node is a suffix node
* Gets if this node has {@link SuffixType} type data.
*
* @return true if this node is a suffix node
*/
boolean isSuffix();
default boolean isSuffix() {
return getTypeData(SuffixType.KEY).isPresent();
}
/**
* Gets the suffix value from this node
* Gets the suffix entry if this node has {@link SuffixType} type data,
* throwing an exception if the data is not present.
*
* @return the suffix value
* @throws IllegalStateException if this node is a not a suffix node
* @return the meta entry
* @throws IllegalStateException if this node doesn't have {@link SuffixType} data
*/
@Nonnull
Map.Entry<Integer, String> getSuffix() throws IllegalStateException;
default Map.Entry<Integer, String> getSuffix() throws IllegalStateException {
return typeData(SuffixType.KEY).getAsEntry();
}
/**
* Returns if this Node is equal to another node
* Gets if this Node is equal to another node.
*
* @param obj the other node
* @return true if this node is equal to the other provided
@@ -364,7 +448,7 @@ public interface Node {
boolean equals(Object obj);
/**
* Returns if this Node is equal to another node as defined by the given
* Gets if this Node is equal to another node as defined by the given
* {@link StandardNodeEquality} predicate.
*
* @param other the other node
@@ -375,7 +459,7 @@ public interface Node {
boolean standardEquals(Node other, StandardNodeEquality equalityPredicate);
/**
* Returns if this Node is equal to another node as defined by the given
* Gets if this Node is equal to another node as defined by the given
* {@link NodeEqualityPredicate}.
*
* @param other the other node
@@ -444,6 +528,19 @@ public interface Node {
*/
interface Builder {
/**
* Copies the attributes from the given node and applies them to this
* builder.
*
* <p>Note that this copies all attributes <strong>except</strong> the
* permission itself.</p>
*
* @param node the node to copy from
* @return the builder
* @since 4.2
*/
Builder copyFrom(@Nonnull Node node);
/**
* Sets the value of negated for the node.
*
@@ -459,7 +556,7 @@ public interface Node {
*
* @param value the value
* @return the builder
* @see Node#getValuePrimitive()
* @see Node#getValue()
*/
@Nonnull
Builder setValue(boolean value);
@@ -478,14 +575,45 @@ public interface Node {
Builder setOverride(boolean override);
/**
* Sets the nodes expiry as a unix timestamp in seconds.
* Sets the time when the node should expire.
*
* @param expireAt the expiry time
* <p>The parameter passed to this method must be the unix timestamp
* (in seconds) when the node should expire.</p>
*
* @param expiryUnixTimestamp the expiry timestamp (unix seconds)
* @return the builder
* @see Node#getExpiryUnixTime()
*/
@Nonnull
Builder setExpiry(long expireAt);
Builder setExpiry(long expiryUnixTimestamp);
/**
* Sets the time when the node should expire.
*
* <p>The expiry timestamp is calculated relative to the current
* system time.</p>
*
* @param duration how long the node should be added for
* @param unit the unit <code>duration</code> is measured in
* @return the builder
* @since 4.2
*/
@Nonnull
default Builder setExpiry(long duration, TimeUnit unit) {
Preconditions.checkArgument(duration > 0, "duration must be positive");
long seconds = Objects.requireNonNull(unit, "unit").toSeconds(duration);
long timeNow = System.currentTimeMillis() / 1000L;
return setExpiry(timeNow + seconds);
}
/**
* Marks that the node being built should never expire.
*
* @return the builder
* @since 4.2
*/
@Nonnull
Builder clearExpiry();
/**
* Sets the world value for the node.
@@ -555,13 +683,25 @@ public interface Node {
/**
* Appends extra contexts onto the node.
*
* @param set a contextset
* @param contextSet a context set
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@Nonnull
Builder withExtraContext(@Nonnull ContextSet set);
Builder withExtraContext(@Nonnull ContextSet contextSet);
/**
* Sets the extra contexts for the node.
*
* @param contextSet a context set
* @return the builder
* @see ContextSet
* @see Node#getContexts()
* @since 4.2
*/
@Nonnull
Builder setExtraContext(@Nonnull ContextSet contextSet);
/**
* Creates a {@link Node} instance from the builder.
@@ -84,6 +84,9 @@ public interface PermissionHolder {
/**
* Refreshes and applies any changes to the cached holder data.
*
* <p>Calling this method is unnecessary in most cases. Cache updates are handled
* behind the scenes by the implementation.</p>
*
* @return the task future
* @since 4.0
*/
@@ -0,0 +1,112 @@
/*
* 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.api;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Encapsulates the result of an operation to save uuid data about a player.
*
* @since 4.2
*/
public interface PlayerSaveResult {
/**
* Gets the status returned by the operation
*
* @return the status
*/
@Nonnull
Set<Status> getStatus();
/**
* Gets if the result includes a certain status code.
*
* @param status the status to check for
* @return if the result includes the status
*/
boolean includes(@Nonnull Status status);
/**
* Gets the old username involved in the result
*
* @return the old username
* @see Status#USERNAME_UPDATED
*/
@Nullable
String getOldUsername();
/**
* Gets the other uuids involved in the result
*
* @return the other uuids
* @see Status#OTHER_UUIDS_PRESENT_FOR_USERNAME
*/
@Nullable
Set<UUID> getOtherUuids();
/**
* The various states the result can take
*/
enum Status {
/**
* There was no existing data saved for either the uuid or username
*/
CLEAN_INSERT,
/**
* There was existing data for the player, no change was needed.
*/
NO_CHANGE,
/**
* There was already a record for the UUID saved, but it was for a different username.
*
* <p>This is normal, players are able to change their usernames.</p>
*/
USERNAME_UPDATED,
/**
* There was already a record for the username saved, but it was under a different uuid.
*
* <p>This is a bit of a cause for concern. It's possible that "player1" has changed
* their username to "player2", and "player3" has changed their username to "player1".
* If the original "player1" doesn't join after changing their name, this conflict could
* occur.</p>
*
* <p>However, what's more likely is that the server is not setup to authenticate
* correctly. Usually this is a problem with BungeeCord "ip-forwarding", but could be
* that the user of the plugin is running a network off a shared database with one
* server in online mode and another in offline mode.</p>
*/
OTHER_UUIDS_PRESENT_FOR_USERNAME,
}
}
@@ -0,0 +1,130 @@
/*
* 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.api;
import java.util.Optional;
import javax.annotation.Nonnull;
/**
* Encapsulates the result of {@link User}s promotion along a {@link Track}.
*
* @since 4.2
*/
public interface PromotionResult extends MutateResult {
/**
* Gets the status of the result.
*
* @return the status
*/
@Nonnull
Status getStatus();
@Override
default boolean wasSuccess() {
return getStatus().wasSuccess();
}
/**
* Gets the name of the group the user was promoted from, if applicable.
*
* <p>Will only be present for results with a {@link #getStatus() status} of
* {@link Status#SUCCESS}.</p>
*
* @return the group the user was promoted from.
*/
@Nonnull
Optional<String> getGroupFrom();
/**
* Gets the name of the group the user was promoted from, if applicable.
*
* <p>Will only be present for results with a {@link #getStatus() status} of
* {@link Status#SUCCESS} or {@link Status#ADDED_TO_FIRST_GROUP}.</p>
*
* <p>The value will also be set for results with the {@link Status#MALFORMED_TRACK} status,
* with this value marking the group which no longer exists.</p>
*
* @return the group the user was promoted to.
*/
@Nonnull
Optional<String> getGroupTo();
/**
* The result status
*/
enum Status implements MutateResult {
/**
* Indicates that the user was promoted normally.
*/
SUCCESS(true),
/**
* Indicates that the user was added to the first group in the track.
*
* <p>This usually occurs when the user isn't already on any of the groups in the track.</p>
*/
ADDED_TO_FIRST_GROUP(true),
/**
* Indicates that the next group in the track no longer exists.
*/
MALFORMED_TRACK(false),
/**
* Indicates that the user is already a member of the group at the end of the track,
* and as such cannot be promoted any further.
*/
END_OF_TRACK(false),
/**
* Indicates that the implementation was unable to determine the users current position on
* this track.
*
* <p>This usually occurs when the user is on more than one group on the track.</p>
*/
AMBIGUOUS_CALL(false),
/**
* An undefined failure occurred.
*/
UNDEFINED_FAILURE(false);
private final boolean success;
Status(boolean success) {
this.success = success;
}
@Override
public boolean wasSuccess() {
return this.success;
}
}
}
@@ -44,7 +44,7 @@ public enum StandardNodeEquality implements NodeEqualityPredicate {
/**
* All attributes must match, except for
* {@link Node#getValuePrimitive() value}, which is ignored.
* {@link Node#getValue() value}, which is ignored.
*/
IGNORE_VALUE,
@@ -59,14 +59,14 @@ public enum StandardNodeEquality implements NodeEqualityPredicate {
/**
* All attributes must match, except for
* {@link Node#getValuePrimitive() value} and the
* {@link Node#getValue() value} and the
* {@link Node#getExpiry() expiry time}, which are ignored.
*/
IGNORE_EXPIRY_TIME_AND_VALUE,
/**
* All attributes must match, except for
* {@link Node#getValuePrimitive() value} and the if the node is
* {@link Node#getValue() value} and the if the node is
* {@link Node#isTemporary() temporary}, which are ignored.
*/
IGNORE_VALUE_OR_IF_TEMPORARY;
@@ -34,7 +34,6 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -42,16 +41,6 @@ import javax.annotation.Nullable;
/**
* A means of loading and saving permission data to/from the backend.
*
* <p>All blocking methods return {@link CompletableFuture}s, which will be
* populated with the result once the data has been loaded/saved asynchronously.
* Care should be taken when using such methods to ensure that the main server
* thread is not blocked.</p>
*
* <p>Methods such as {@link CompletableFuture#get()} and equivalent should
* <strong>not</strong> be called on the main server thread. If you need to use
* the result of these operations on the main server thread, register a
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)}.</p>
*
* @since 2.14
*/
public interface Storage {
@@ -64,80 +53,6 @@ public interface Storage {
@Nonnull
String getName();
/**
* Loads and returns the entire log from storage
*
* @return a log instance, could be null if loading failed
*/
@Nonnull
CompletableFuture<Log> getLog();
/**
* Gets a set all "unique" user UUIDs.
*
* <p>"Unique" meaning the user isn't just a member of the "default" group.</p>
*
* @return a set of uuids, or null if the operation failed.
*/
@Nonnull
CompletableFuture<Set<UUID>> getUniqueUsers();
/**
* Searches for a list of users 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
* @since 2.17
*/
@Nonnull
CompletableFuture<List<HeldPermission<UUID>>> getUsersWithPermission(@Nonnull String permission);
/**
* 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
* @since 2.17
*/
@Nonnull
CompletableFuture<List<HeldPermission<String>>> getGroupsWithPermission(@Nonnull String permission);
/**
* Saves UUID caching data to the global cache
*
* @param username the users username
* @param uuid the users mojang unique id
* @return true if the operation completed successfully.
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
*/
@Nonnull
CompletableFuture<Boolean> saveUUIDData(@Nonnull String username, @Nonnull UUID uuid);
/**
* Gets a UUID from a username
*
* @param username the corresponding username
* @return a uuid object, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
*/
@Nonnull
CompletableFuture<UUID> getUUID(@Nonnull String username);
/**
* Gets a username from a UUID
*
* @param uuid the corresponding uuid
* @return a name string, could be null
* @throws NullPointerException if either parameters are null
* @since 2.17
*/
@Nonnull
CompletableFuture<String> getName(@Nonnull UUID uuid);
/**
* Gets whether the storage instance is allowing logins on the platform.
*
@@ -147,34 +62,6 @@ public interface Storage {
@Deprecated
boolean isAcceptingLogins();
/**
* Returns an executor which will run all passed runnables on the
* main server thread.
*
* <p>This method is deprecated as plugins should create and use their own
* executor instances.</p>
*
* @return an executor instance
* @deprecated as plugins should create their own executors
*/
@Nonnull
@Deprecated
Executor getSyncExecutor();
/**
* Returns an executor which will run all passed runnables asynchronously
* using the platforms scheduler and thread pools.
*
* <p>This method is deprecated as plugins should create and use their own
* executor instances.</p>
*
* @return an executor instance
* @deprecated as plugins should create their own executors
*/
@Nonnull
@Deprecated
Executor getAsyncExecutor();
/**
* Saves an action to storage
*
@@ -187,6 +74,16 @@ public interface Storage {
@Deprecated
CompletableFuture<Boolean> logAction(@Nonnull LogEntry entry);
/**
* Loads and returns the entire log from storage
*
* @return a log instance, could be null if loading failed
* @deprecated in favour of {@link ActionLogger#getLog()}
*/
@Nonnull
@Deprecated
CompletableFuture<Log> getLog();
/**
* Loads a user's data from the main storage into the plugins local storage.
*
@@ -229,6 +126,31 @@ public interface Storage {
@Deprecated
CompletableFuture<Boolean> saveUser(@Nonnull User user);
/**
* Gets a set all "unique" user UUIDs.
*
* <p>"Unique" meaning the user isn't just a member of the "default" group.</p>
*
* @return a set of uuids, or null if the operation failed.
* @deprecated in favour of {@link UserManager#getUniqueUsers()}
*/
@Nonnull
@Deprecated
CompletableFuture<Set<UUID>> getUniqueUsers();
/**
* Searches for a list of users 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
* @since 2.17
* @deprecated in favour of {@link UserManager#getWithPermission(String)}
*/
@Nonnull
@Deprecated
CompletableFuture<List<HeldPermission<UUID>>> getUsersWithPermission(@Nonnull String permission);
/**
* Creates and loads a group into the plugins local storage
*
@@ -293,6 +215,19 @@ public interface Storage {
@Deprecated
CompletableFuture<Boolean> deleteGroup(@Nonnull Group group);
/**
* 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
* @since 2.17
* @deprecated in favour of {@link GroupManager#getWithPermission(String)}
*/
@Nonnull
@Deprecated
CompletableFuture<List<HeldPermission<String>>> getGroupsWithPermission(@Nonnull String permission);
/**
* Creates and loads a track into the plugins local storage
*
@@ -355,4 +290,70 @@ public interface Storage {
@Deprecated
CompletableFuture<Boolean> deleteTrack(@Nonnull Track track);
/**
* Saves UUID caching data to the global cache
*
* @param username the users username
* @param uuid the users mojang unique id
* @return true if the operation completed successfully.
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @deprecated in favour of {@link UserManager#savePlayerData(UUID, String)}
*/
@Nonnull
CompletableFuture<Boolean> saveUUIDData(@Nonnull String username, @Nonnull UUID uuid);
/**
* Gets a UUID from a username
*
* @param username the corresponding username
* @return a uuid object, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @deprecated in favour of {@link UserManager#lookupUuid(String)}
*/
@Nonnull
CompletableFuture<UUID> getUUID(@Nonnull String username);
/**
* Gets a username from a UUID
*
* @param uuid the corresponding uuid
* @return a name string, could be null
* @throws NullPointerException if either parameters are null
* @since 2.17
* @deprecated in favour of {@link UserManager#lookupUsername(UUID)}
*/
@Nonnull
@Deprecated
CompletableFuture<String> getName(@Nonnull UUID uuid);
/**
* Returns an executor which will run all passed runnables on the
* main server thread.
*
* <p>This method is deprecated as plugins should create and use their own
* executor instances.</p>
*
* @return an executor instance
* @deprecated as plugins should create their own executors
*/
@Nonnull
@Deprecated
Executor getSyncExecutor();
/**
* Returns an executor which will run all passed runnables asynchronously
* using the platforms scheduler and thread pools.
*
* <p>This method is deprecated as plugins should create and use their own
* executor instances.</p>
*
* @return an executor instance
* @deprecated as plugins should create their own executors
*/
@Nonnull
@Deprecated
Executor getAsyncExecutor();
}
@@ -25,6 +25,8 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.context.ContextSet;
import java.util.List;
import javax.annotation.Nonnull;
@@ -88,6 +90,28 @@ public interface Track {
@Nullable
String getPrevious(@Nonnull Group current);
/**
* Promotes the given user along this track.
*
* @param user the user to promote
* @param contextSet the contexts to promote the user in
* @return the result of the action
* @since 4.2
*/
@Nonnull
PromotionResult promote(@Nonnull User user, @Nonnull ContextSet contextSet);
/**
* Demotes the given user along this track.
*
* @param user the user to demote
* @param contextSet the contexts to demote the user in
* @return the result of the action
* @since 4.2
*/
@Nonnull
DemotionResult demote(@Nonnull User user, @Nonnull ContextSet contextSet);
/**
* Appends a group to the end of this track
*
@@ -96,6 +120,7 @@ public interface Track {
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
*/
@Nonnull
DataMutateResult appendGroup(@Nonnull Group group);
/**
@@ -108,6 +133,7 @@ public interface Track {
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
*/
@Nonnull
DataMutateResult insertGroup(@Nonnull Group group, int position) throws IndexOutOfBoundsException;
/**
@@ -118,6 +144,7 @@ public interface Track {
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
*/
@Nonnull
DataMutateResult removeGroup(@Nonnull Group group);
/**
@@ -127,6 +154,7 @@ public interface Track {
* @return the result of the operation
* @throws NullPointerException if the group is null
*/
@Nonnull
DataMutateResult removeGroup(@Nonnull String group);
/**
@@ -74,6 +74,7 @@ public interface User extends PermissionHolder {
* @throws IllegalStateException if the user is not a member of that group
* @throws NullPointerException if the group is null
*/
@Nonnull
DataMutateResult setPrimaryGroup(@Nonnull String group);
/**
@@ -36,12 +36,14 @@ import javax.annotation.Nonnull;
/**
* Holds cached permission and meta lookup data for a {@link PermissionHolder}.
*
* <p>All calls will account for inheritance, as well as any default data provided by
* the platform. This calls are heavily cached and are therefore fast.</p>
* <p>All calls will account for inheritance, as well as any default data
* provided by the platform. This calls are heavily cached and are therefore
* fast.</p>
*
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts} are provided. The only difference is that
* the latter allows you to define how the meta stack should be structured internally. Where {@link Contexts} are passed, the
* values from the configuration are used.</p>
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts}
* are provided. The only difference is that the latter allows you to define
* how the meta stack should be structured internally. Where {@link Contexts}
* are passed, the values from the configuration are used.</p>
*
* @since 4.0
*/
@@ -399,6 +401,20 @@ public interface CachedData {
*/
void invalidateMeta(@Nonnull Contexts contexts);
/**
* Invalidates all cached {@link PermissionData} instances.
*
* @since 4.2
*/
void invalidatePermissions();
/**
* Invalidates all cached {@link MetaData} instances.
*
* @since 4.2
*/
void invalidateMeta();
/**
* Invalidates all of the underlying Permission calculators.
*
@@ -25,12 +25,11 @@
package me.lucko.luckperms.api.context;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -38,18 +37,9 @@ import javax.annotation.Nonnull;
abstract class AbstractContextSet implements ContextSet {
protected abstract Multimap<String, String> backing();
protected abstract SetMultimap<String, String> backing();
@Nonnull
@Override
@Deprecated
public Map<String, String> toMap() {
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
for (Map.Entry<String, String> e : backing().entries()) {
m.put(e.getKey(), e.getValue());
}
return m.build();
}
protected abstract void copyTo(SetMultimap<String, String> other);
@Override
public boolean containsKey(@Nonnull String key) {
@@ -68,27 +58,6 @@ abstract class AbstractContextSet implements ContextSet {
return backing().containsEntry(sanitizeKey(key), sanitizeValue(value));
}
@Override
public boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value) {
String v = sanitizeValue(value);
Collection<String> values = backing().asMap().get(sanitizeKey(key));
if (values == null || values.isEmpty()) {
return false;
}
if (values.contains(v)) {
return true;
}
for (String val : values) {
if (val.equalsIgnoreCase(v)) {
return true;
}
}
return false;
}
@Override
public boolean isEmpty() {
return backing().isEmpty();
@@ -126,8 +95,7 @@ abstract class AbstractContextSet implements ContextSet {
if (stringIsEmpty(key)) {
throw new IllegalArgumentException("key is (effectively) empty");
}
return key.toLowerCase().intern();
return key.toLowerCase();
}
static String sanitizeValue(String value) {
@@ -135,8 +103,7 @@ abstract class AbstractContextSet implements ContextSet {
if (stringIsEmpty(value)) {
throw new IllegalArgumentException("value is (effectively) empty");
}
return value.intern();
return value.toLowerCase();
}
private static boolean stringIsEmpty(String s) {
@@ -28,7 +28,7 @@ package me.lucko.luckperms.api.context;
import javax.annotation.Nonnull;
/**
* Calculates whether contexts are applicable to {@link T}
* Calculates whether contexts are applicable to a {@link T subject}.
*
* @param <T> the subject type. Is ALWAYS the player class of the platform.
* @since 2.13
@@ -27,6 +27,7 @@ package me.lucko.luckperms.api.context;
import com.google.common.collect.Multimap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -47,9 +48,8 @@ import javax.annotation.Nonnull;
* <p>Contexts can be combined with each other to form so called
* "context sets" - simply a collection of context pairs.</p>
*
* <p>Context keys are case-insensitive, and will be converted to
* {@link String#toLowerCase() lowercase} by all implementations.
* Values however are case-sensitive.</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
@@ -61,7 +61,7 @@ import javax.annotation.Nonnull;
*
* @since 2.13
*/
public interface ContextSet {
public interface ContextSet extends Iterable<Map.Entry<String, String>> {
/**
* Creates an {@link ImmutableContextSet} from a context pair.
@@ -231,6 +231,20 @@ public interface ContextSet {
@Nonnull
Multimap<String, String> toMultimap();
/**
* Returns an {@link Iterator} over each of the context pairs in this set.
*
* <p>The returned iterator represents the state of the set at the time of creation. It is not
* updated as the set changes.</p>
*
* <p>The iterator does not support {@link Iterator#remove()} calls.</p>
*
* @return an iterator
*/
@Nonnull
@Override
Iterator<Map.Entry<String, String>> iterator();
/**
* Returns if the {@link ContextSet} contains at least one value for the
* given key.
@@ -272,33 +286,16 @@ public interface ContextSet {
/**
* Returns if the {@link ContextSet} contains a given context pairing.
*
* <p>This lookup is case-sensitive on the value.</p>
*
* @param key the key to look for
* @param value the value to look for (case sensitive)
* @param value the value to look for
* @return true if the set contains the context pair
* @throws NullPointerException if the key or value is null
*/
boolean has(@Nonnull String key, @Nonnull String value);
/**
* Returns if the {@link ContextSet} contains a given context pairing,
* ignoring the case of values.
*
* <p>This lookup is case-insensitive on the value.</p>
*
* @param key the key to look for
* @param value the value to look for
* @return true if the set contains the context pair
* @throws NullPointerException if the key or value is null
*/
boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value);
/**
* Returns if the {@link ContextSet} contains a given context pairing.
*
* <p>This lookup is case-sensitive on the value.</p>
*
* @param entry the entry to look for
* @return true if the set contains the context pair
* @throws NullPointerException if the key or value is null
@@ -308,21 +305,6 @@ public interface ContextSet {
return has(entry.getKey(), entry.getValue());
}
/**
* Returns if the {@link ContextSet} contains a given context pairing,
* ignoring the case of values.
*
* <p>This lookup is case-insensitive on the value.</p>
*
* @param entry the entry to look for
* @return true if the set contains the context pair
* @throws NullPointerException if the key or value is null
*/
default boolean hasIgnoreCase(@Nonnull Map.Entry<String, String> entry) {
Objects.requireNonNull(entry, "entry");
return hasIgnoreCase(entry.getKey(), entry.getValue());
}
/**
* Returns if this {@link ContextSet} is fully "satisfied" by another set.
*
@@ -331,31 +313,11 @@ public interface ContextSet {
*
* <p>Mathematically, this method returns true if this set is a <b>subset</b> of the other.</p>
*
* <p>This check is case-sensitive. For a case-insensitive check,
* use {@link #isSatisfiedBy(ContextSet, boolean)}.</p>
*
* @param other the other set to check
* @return true if all entries in this set are also in the other set
* @since 3.1
*/
default boolean isSatisfiedBy(@Nonnull ContextSet other) {
return isSatisfiedBy(other, true);
}
/**
* Returns if this {@link ContextSet} is fully "satisfied" by another set.
*
* <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
* @param caseSensitive if the check should be case sensitive
* @return true if all entries in this set are also in the other set
* @since 3.4
*/
default boolean isSatisfiedBy(@Nonnull ContextSet other, boolean caseSensitive) {
if (this == other) {
return true;
}
@@ -373,14 +335,8 @@ public interface ContextSet {
} else {
// neither are empty, we need to compare the individual entries
for (Map.Entry<String, String> context : toSet()) {
if (caseSensitive) {
if (!other.has(context)) {
return false;
}
} else {
if (!other.hasIgnoreCase(context)) {
return false;
}
if (!other.has(context)) {
return false;
}
}
return true;
@@ -25,12 +25,16 @@
package me.lucko.luckperms.api.context;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Spliterator;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
@@ -164,10 +168,15 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
}
@Override
protected Multimap<String, String> backing() {
protected SetMultimap<String, String> backing() {
return this.map;
}
@Override
protected void copyTo(SetMultimap<String, String> other) {
other.putAll(this.map);
}
@Override
public boolean isImmutable() {
return true;
@@ -192,12 +201,34 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
return this.map.entries();
}
@Nonnull
@Override
@Deprecated
public Map<String, String> toMap() {
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
for (Map.Entry<String, String> e : this.map.entries()) {
m.put(e.getKey(), e.getValue());
}
return m.build();
}
@Nonnull
@Override
public Multimap<String, String> toMultimap() {
return this.map;
}
@Nonnull
@Override
public Iterator<Map.Entry<String, String>> iterator() {
return this.map.entries().iterator();
}
@Override
public Spliterator<Map.Entry<String, String>> spliterator() {
return this.map.entries().spliterator();
}
@Override
public int hashCode() {
return this.hashCode;
@@ -26,16 +26,18 @@
package me.lucko.luckperms.api.context;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Spliterator;
import javax.annotation.Nonnull;
@@ -144,9 +146,17 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
@Nonnull
public static MutableContextSet fromSet(@Nonnull ContextSet contextSet) {
Objects.requireNonNull(contextSet, "contextSet");
MutableContextSet set = create();
set.addAll(contextSet);
return set;
if (contextSet instanceof ImmutableContextSet) {
SetMultimap<String, String> map = ((ImmutableContextSet) contextSet).backing();
return new MutableContextSet(map);
} else if (contextSet instanceof MutableContextSet) {
return contextSet.mutableCopy();
} else {
MutableContextSet set = create();
set.addAll(contextSet);
return set;
}
}
/**
@@ -165,15 +175,22 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create());
}
private MutableContextSet(MutableContextSet other) {
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create(other.map));
private MutableContextSet(SetMultimap<String, String> other) {
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create(other));
}
@Override
protected Multimap<String, String> backing() {
protected SetMultimap<String, String> backing() {
return this.map;
}
@Override
protected void copyTo(SetMultimap<String, String> other) {
synchronized (this.map) {
other.putAll(this.map);
}
}
@Override
public boolean isImmutable() {
return false;
@@ -186,25 +203,58 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
if (this.map.isEmpty()) {
return ImmutableContextSet.empty();
}
return new ImmutableContextSet(ImmutableSetMultimap.copyOf(this.map));
synchronized (this.map) {
return new ImmutableContextSet(ImmutableSetMultimap.copyOf(this.map));
}
}
@Nonnull
@Override
public MutableContextSet mutableCopy() {
return new MutableContextSet(this);
synchronized (this.map) {
return new MutableContextSet(this.map);
}
}
@Nonnull
@Override
public Set<Map.Entry<String, String>> toSet() {
return ImmutableSet.copyOf(this.map.entries());
synchronized (this.map) {
// map.entries() returns immutable Map.Entry instances, so we can just call copyOf
return ImmutableSet.copyOf(this.map.entries());
}
}
@Nonnull
@Override
@Deprecated
public Map<String, String> toMap() {
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
synchronized (this.map) {
for (Map.Entry<String, String> e : this.map.entries()) {
m.put(e.getKey(), e.getValue());
}
}
return m.build();
}
@Nonnull
@Override
public Multimap<String, String> toMultimap() {
return ImmutableSetMultimap.copyOf(this.map);
synchronized (this.map) {
return ImmutableSetMultimap.copyOf(this.map);
}
}
@Nonnull
@Override
public Iterator<Map.Entry<String, String>> iterator() {
return toSet().iterator();
}
@Override
public Spliterator<Map.Entry<String, String>> spliterator() {
return toSet().spliterator();
}
/**
@@ -272,7 +322,9 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
Objects.requireNonNull(contextSet, "contextSet");
if (contextSet instanceof AbstractContextSet) {
AbstractContextSet other = ((AbstractContextSet) contextSet);
this.map.putAll(other.backing());
synchronized (this.map) {
other.copyTo(this.map);
}
} else {
addAll(contextSet.toMultimap());
}
@@ -282,28 +334,13 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
* Removes a context from this set.
*
* @param key the key to remove
* @param value the value to remove (case sensitive)
* @param value the value to remove
* @throws NullPointerException if the key or value is null
*/
public void remove(@Nonnull String key, @Nonnull String value) {
this.map.remove(sanitizeKey(key), sanitizeValue(value));
}
/**
* Removes a context from this set. (case-insensitive)
*
* @param key the key to remove
* @param value the value to remove
* @throws NullPointerException if the key or value is null
*/
public void removeIgnoreCase(@Nonnull String key, @Nonnull String value) {
String v = sanitizeValue(value);
Collection<String> strings = this.map.asMap().get(sanitizeKey(key));
if (strings != null) {
strings.removeIf(e -> e.equalsIgnoreCase(v));
}
}
/**
* Removes all contexts from this set with the given key.
*
@@ -31,16 +31,20 @@ import java.util.function.Consumer;
import javax.annotation.Nonnull;
/**
* The internal LuckPerms event bus.
* The LuckPerms event bus.
*
* <p>LuckPerms events are posted to any listeners registered with the bus.</p>
* <p>Used to subscribe (or "listen") to LuckPerms events.</p>
*
* @since 3.0
*/
public interface EventBus {
/**
* Subscribes to an event.
* Registers a new subscription to the given event.
*
* <p>The returned {@link EventHandler} instance encapsulates the subscription state. It has
* methods which can be used to terminate the subscription, or view stats about the nature of
* the subscription.</p>
*
* @param eventClass the event class
* @param handler the event handler
@@ -48,7 +52,28 @@ public interface EventBus {
* @return an event handler instance representing this subscription
*/
@Nonnull
<T extends LuckPermsEvent> EventHandler<T> subscribe(@Nonnull Class<T> eventClass, @Nonnull Consumer<T> handler);
<T extends LuckPermsEvent> EventHandler<T> subscribe(@Nonnull Class<T> eventClass, @Nonnull Consumer<? super T> handler);
/**
* Registers a new subscription to the given event.
*
* <p>The returned {@link EventHandler} instance encapsulates the subscription state. It has
* methods which can be used to terminate the subscription, or view stats about the nature of
* the subscription.</p>
*
* <p>Unlike {@link #subscribe(Class, Consumer)}, this method accepts an additional parameter
* for {@code plugin}. This object must be a "plugin" instance on the platform, and is used to
* automatically {@link EventHandler#unregister() unregister} the subscription when the
* corresponding plugin is disabled.</p>
*
* @param <T> the event class
* @param plugin a plugin instance to bind the subscription to.
* @param eventClass the event class
* @param handler the event handler
* @return an event handler instance representing this subscription
*/
@Nonnull
<T extends LuckPermsEvent> EventHandler<T> subscribe(Object plugin, @Nonnull Class<T> eventClass, @Nonnull Consumer<? super T> handler);
/**
* Gets a set of all registered handlers for a given event.
@@ -30,7 +30,7 @@ import java.util.function.Consumer;
import javax.annotation.Nonnull;
/**
* Represents a handler for a LuckPerms event
* Represents a subscription to a {@link LuckPermsEvent}.
*
* @param <T> the event class
*/
@@ -64,7 +64,7 @@ public interface EventHandler<T extends LuckPermsEvent> extends AutoCloseable {
* @return the event consumer
*/
@Nonnull
Consumer<T> getConsumer();
Consumer<? super T> getConsumer();
/**
* Gets the number of times this handler has been called
@@ -26,11 +26,15 @@
package me.lucko.luckperms.api.manager;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.HeldPermission;
import me.lucko.luckperms.api.Storage;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -38,6 +42,16 @@ import javax.annotation.Nullable;
/**
* Represents the object responsible for managing {@link Group} instances.
*
* <p>All blocking methods return {@link CompletableFuture}s, which will be
* populated with the result once the data has been loaded/saved asynchronously.
* Care should be taken when using such methods to ensure that the main server
* thread is not blocked.</p>
*
* <p>Methods such as {@link CompletableFuture#get()} and equivalent should
* <strong>not</strong> be called on the main server thread. If you need to use
* the result of these operations on the main server thread, register a
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)}.</p>
*
* @since 4.0
*/
public interface GroupManager {
@@ -138,6 +152,17 @@ public interface GroupManager {
@Nonnull
CompletableFuture<Void> loadAllGroups();
/**
* 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
* @since 4.2
*/
@Nonnull
CompletableFuture<List<HeldPermission<String>>> getWithPermission(@Nonnull String permission);
/**
* Gets a loaded group.
*
@@ -31,6 +31,8 @@ import me.lucko.luckperms.api.Track;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -38,6 +40,16 @@ import javax.annotation.Nullable;
/**
* Represents the object responsible for managing {@link Track} instances.
*
* <p>All blocking methods return {@link CompletableFuture}s, which will be
* populated with the result once the data has been loaded/saved asynchronously.
* Care should be taken when using such methods to ensure that the main server
* thread is not blocked.</p>
*
* <p>Methods such as {@link CompletableFuture#get()} and equivalent should
* <strong>not</strong> be called on the main server thread. If you need to use
* the result of these operations on the main server thread, register a
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)}.</p>
*
* @since 4.0
*/
public interface TrackManager {
@@ -25,13 +25,18 @@
package me.lucko.luckperms.api.manager;
import me.lucko.luckperms.api.HeldPermission;
import me.lucko.luckperms.api.PlayerSaveResult;
import me.lucko.luckperms.api.Storage;
import me.lucko.luckperms.api.User;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -42,6 +47,16 @@ import javax.annotation.Nullable;
* <p>Note that User instances are automatically loaded for online players.
* It's likely that offline players will not have an instance pre-loaded.</p>
*
* <p>All blocking methods return {@link CompletableFuture}s, which will be
* populated with the result once the data has been loaded/saved asynchronously.
* Care should be taken when using such methods to ensure that the main server
* thread is not blocked.</p>
*
* <p>Methods such as {@link CompletableFuture#get()} and equivalent should
* <strong>not</strong> be called on the main server thread. If you need to use
* the result of these operations on the main server thread, register a
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)}.</p>
*
* @since 4.0
*/
public interface UserManager {
@@ -85,6 +100,32 @@ public interface UserManager {
return loadUser(uuid, null);
}
/**
* Uses the LuckPerms cache to find a uuid for the given username.
*
* <p>This lookup is case insensitive.</p>
*
* @param username the username
* @return a uuid, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @since 4.2
*/
@Nonnull
CompletableFuture<UUID> lookupUuid(@Nonnull String username);
/**
* Uses the LuckPerms cache to find a username for the given uuid.
*
* @param uuid the uuid
* @return a username, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @since 4.2
*/
@Nonnull
CompletableFuture<String> lookupUsername(@Nonnull UUID uuid);
/**
* Saves a user's data back to the plugin's storage provider.
*
@@ -105,6 +146,41 @@ public interface UserManager {
@Nonnull
CompletableFuture<Void> saveUser(@Nonnull User user);
/**
* Saves data about a player to the uuid caching system.
*
* @param uuid the users mojang unique id
* @param username the users username
* @return the result of the operation.
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @since 4.2
*/
@Nonnull
CompletableFuture<PlayerSaveResult> savePlayerData(@Nonnull UUID uuid, @Nonnull String username);
/**
* Gets a set all "unique" user UUIDs.
*
* <p>"Unique" meaning the user isn't just a member of the "default" group.</p>
*
* @return a set of uuids
* @since 4.2
*/
@Nonnull
CompletableFuture<Set<UUID>> getUniqueUsers();
/**
* 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
* @since 4.2
*/
@Nonnull
CompletableFuture<List<HeldPermission<UUID>>> getWithPermission(@Nonnull String permission);
/**
* Gets a loaded user.
*
@@ -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.api.nodetype;
import me.lucko.luckperms.api.Node;
/**
* Superinterface for extended {@link Node} types.
*
* <p>The 'permission' property of a {@link Node} is also used in some cases to represent state
* beyond a granted permission. This state is encapsulated by extra {@link NodeType} data which
* can be obtained from this instance using {@link Node#getTypeData(NodeTypeKey)}.</p>
*
* <p>Type data is mapped by {@link NodeTypeKey}s, which are usually stored as static members of the
* corresponding {@link NodeType} class under the <code>KEY</code> field.</p>
*
* @since 4.2
*/
public interface NodeType {
}
@@ -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.api.nodetype;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import javax.annotation.Nonnull;
/**
* Marks an instance used as a key for a {@link NodeType}.
*
* <p>A single instance of this interface is created and stored statically for
* each sub-interface of {@link NodeType}.</p>
*
* @param <N> the type of the {@link NodeType} being indexed by this key
* @since 4.2
*/
public interface NodeTypeKey<N extends NodeType> {
/**
* Gets the {@link Class#getSimpleName() class name} of the represented type.
*
* @return the name of the represented type
*/
@Nonnull
default String getTypeName() {
ParameterizedType thisType = (ParameterizedType) getClass().getGenericSuperclass();
Type nodeType = thisType.getActualTypeArguments()[0];
return ((Class) nodeType).getSimpleName();
}
}
@@ -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 me.lucko.luckperms.api.nodetype.types;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
import javax.annotation.Nonnull;
/**
* A sub-type of {@link Node} used to mark the display name of the node's holder.
*
* @since 4.2
*/
public interface DisplayNameType extends NodeType {
/**
* The key for this type.
*/
NodeTypeKey<DisplayNameType> KEY = new NodeTypeKey<DisplayNameType>(){};
/**
* Gets the display name.
*
* @return the display name
*/
@Nonnull
String getDisplayName();
}
@@ -23,34 +23,35 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.references;
package me.lucko.luckperms.api.nodetype.types;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
/**
* A reference to a specific {@link PermissionHolder}.
* A sub-type of {@link Node} used to mark that the holder of the node should inherit
* from another group.
*
* @param <S> the holder type
* @param <I> the holder identifier type
* @since 4.2
*/
public interface HolderReference<S, I> extends Identifiable<I> {
public interface InheritanceType extends NodeType {
/**
* Gets the holder type
*
* @return the holder type
* The key for this type.
*/
HolderType getType();
NodeTypeKey<InheritanceType> KEY = new NodeTypeKey<InheritanceType>(){};
/**
* Applies an action to this reference, if it is present and exists.
* Gets the name of the group to be inherited.
*
* @param plugin the plugin
* @param consumer the action
* <p>This is no guarantee that this group exists.</p>
*
* @return the name of the group
*/
void apply(LuckPermsPlugin plugin, Consumer<S> consumer);
@Nonnull
String getGroupName();
}
@@ -0,0 +1,69 @@
/*
* 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.api.nodetype.types;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
import java.util.Map;
import javax.annotation.Nonnull;
/**
* A sub-type of {@link Node} used to store meta assignments.
*
* @since 4.2
*/
public interface MetaType extends NodeType, Map.Entry<String, String> {
/**
* The key for this type.
*/
NodeTypeKey<MetaType> KEY = new NodeTypeKey<MetaType>(){};
/**
* Gets the meta key.
*
* @return the meta key
*/
@Nonnull
String getKey();
/**
* Gets the meta value.
*
* @return the meta value
*/
@Nonnull
String getValue();
@Override
@Deprecated
default String setValue(String value) {
throw new UnsupportedOperationException();
}
}
@@ -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.api.nodetype.types;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
import java.util.Map;
import javax.annotation.Nonnull;
/**
* A sub-type of {@link Node} used to store prefix assignments.
*
* @since 4.2
*/
public interface PrefixType extends NodeType {
/**
* The key for this type.
*/
NodeTypeKey<PrefixType> KEY = new NodeTypeKey<PrefixType>(){};
/**
* Gets the priority of the prefix assignment.
*
* @return the priority
*/
int getPriority();
/**
* Gets the actual prefix string.
*
* @return the prefix
*/
@Nonnull
String getPrefix();
/**
* Gets a representation of this instance as a {@link Map.Entry}.
*
* @return a map entry representation of the priority and prefix string
*/
@Nonnull
Map.Entry<Integer, String> getAsEntry();
}
@@ -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.api.nodetype.types;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
import java.util.Map;
import javax.annotation.Nonnull;
/**
* A sub-type of {@link Node} used to store suffix assignments.
*
* @since 4.2
*/
public interface SuffixType extends NodeType {
/**
* The key for this type.
*/
NodeTypeKey<SuffixType> KEY = new NodeTypeKey<SuffixType>(){};
/**
* Gets the priority of the suffix assignment.
*
* @return the priority
*/
int getPriority();
/**
* Gets the actual suffix string.
*
* @return the suffix
*/
@Nonnull
String getSuffix();
/**
* Gets a representation of this instance as a {@link Map.Entry}.
*
* @return a map entry representation of the priority and suffix string
*/
@Nonnull
Map.Entry<Integer, String> getAsEntry();
}
@@ -0,0 +1,51 @@
/*
* 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.api.nodetype.types;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
/**
* A sub-type of {@link Node} used to mark the weight of the node's holder.
*
* @since 4.2
*/
public interface WeightType extends NodeType {
/**
* The key for this type.
*/
NodeTypeKey<WeightType> KEY = new NodeTypeKey<WeightType>(){};
/**
* Gets the weight value.
*
* @return the weight
*/
int getWeight();
}
+3 -7
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>4.1-SNAPSHOT</version>
<version>4.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -100,10 +100,6 @@
<pattern>ninja.leaping.configurate</pattern>
<shadedPattern>me.lucko.luckperms.lib.configurate</shadedPattern>
</relocation>
<relocation>
<pattern>com.typesafe.config</pattern>
<shadedPattern>me.lucko.luckperms.lib.hocon</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
@@ -133,14 +129,14 @@
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.6.1</version>
<version>2.6.2</version>
<scope>provided</scope>
</dependency>
<!-- HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>2.7.6</version>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
@@ -28,8 +28,8 @@ package me.lucko.luckperms.bukkit;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.sender.Sender;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@@ -45,7 +45,7 @@ public class BukkitCommandExecutor extends CommandManager implements CommandExec
private final LPBukkitPlugin plugin;
BukkitCommandExecutor(LPBukkitPlugin plugin) {
public BukkitCommandExecutor(LPBukkitPlugin plugin) {
super(plugin);
this.plugin = plugin;
}
@@ -55,11 +55,6 @@ public class BukkitConfigAdapter extends AbstractConfigurationAdapter implements
this.configuration = YamlConfiguration.loadConfiguration(this.file);
}
@Override
public boolean contains(String path) {
return this.configuration.contains(path);
}
@Override
public String getString(String path, String def) {
return this.configuration.getString(path, def);
@@ -0,0 +1,60 @@
/*
* 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 me.lucko.luckperms.common.api.LuckPermsApiProvider;
import me.lucko.luckperms.common.event.AbstractEventBus;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.plugin.Plugin;
public class BukkitEventBus extends AbstractEventBus<Plugin> implements Listener {
public BukkitEventBus(LPBukkitPlugin plugin, LuckPermsApiProvider apiProvider) {
super(plugin, apiProvider);
// register listener
LPBukkitBootstrap bootstrap = plugin.getBootstrap();
bootstrap.getServer().getPluginManager().registerEvents(this, bootstrap);
}
@Override
protected Plugin checkPlugin(Object plugin) throws IllegalArgumentException {
if (plugin instanceof Plugin) {
return (Plugin) plugin;
}
throw new IllegalArgumentException("Object " + plugin + " (" + plugin.getClass().getName() + ") is not a plugin.");
}
@EventHandler
public void onPluginDisable(PluginDisableEvent e) {
Plugin plugin = e.getPlugin();
unregisterHandlers(plugin);
}
}
@@ -29,7 +29,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
import me.lucko.luckperms.common.plugin.SchedulerTask;
import me.lucko.luckperms.common.utils.SafeIteration;
import me.lucko.luckperms.common.utils.Iterators;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
@@ -45,7 +45,7 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
public class BukkitSchedulerAdapter implements SchedulerAdapter {
private final LPBukkitPlugin plugin;
private final LPBukkitBootstrap bootstrap;
private final ExecutorService asyncFallback;
private final Executor asyncBukkit;
@@ -56,8 +56,8 @@ public class BukkitSchedulerAdapter implements SchedulerAdapter {
private final Set<SchedulerTask> tasks = ConcurrentHashMap.newKeySet();
public BukkitSchedulerAdapter(LPBukkitPlugin plugin) {
this.plugin = plugin;
public BukkitSchedulerAdapter(LPBukkitBootstrap bootstrap) {
this.bootstrap = bootstrap;
this.sync = new SyncExecutor();
this.asyncFallback = new FallbackAsyncExecutor();
@@ -66,7 +66,7 @@ public class BukkitSchedulerAdapter implements SchedulerAdapter {
}
private BukkitScheduler scheduler() {
return this.plugin.getServer().getScheduler();
return this.bootstrap.getServer().getScheduler();
}
@Override
@@ -81,31 +81,31 @@ public class BukkitSchedulerAdapter implements SchedulerAdapter {
@Override
public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) {
SchedulerTask task = new BukkitSchedulerTask(scheduler().runTaskTimerAsynchronously(this.plugin, runnable, intervalTicks, intervalTicks));
SchedulerTask task = new BukkitSchedulerTask(scheduler().runTaskTimerAsynchronously(this.bootstrap, runnable, intervalTicks, intervalTicks));
this.tasks.add(task);
return task;
}
@Override
public SchedulerTask syncRepeating(Runnable runnable, long intervalTicks) {
SchedulerTask task = new BukkitSchedulerTask(scheduler().runTaskTimer(this.plugin, runnable, intervalTicks, intervalTicks));
SchedulerTask task = new BukkitSchedulerTask(scheduler().runTaskTimer(this.bootstrap, runnable, intervalTicks, intervalTicks));
this.tasks.add(task);
return task;
}
@Override
public SchedulerTask asyncLater(Runnable runnable, long delayTicks) {
return new BukkitSchedulerTask(scheduler().runTaskLaterAsynchronously(this.plugin, runnable, delayTicks));
return new BukkitSchedulerTask(scheduler().runTaskLaterAsynchronously(this.bootstrap, runnable, delayTicks));
}
@Override
public SchedulerTask syncLater(Runnable runnable, long delayTicks) {
return new BukkitSchedulerTask(scheduler().runTaskLater(this.plugin, runnable, delayTicks));
return new BukkitSchedulerTask(scheduler().runTaskLater(this.bootstrap, runnable, delayTicks));
}
@Override
public void shutdown() {
SafeIteration.iterate(this.tasks, SchedulerTask::cancel);
Iterators.iterate(this.tasks, SchedulerTask::cancel);
// wait for executor
this.asyncFallback.shutdown();
@@ -116,15 +116,6 @@ public class BukkitSchedulerAdapter implements SchedulerAdapter {
}
}
public ExecutorService asyncFallback() {
return this.asyncFallback;
}
public Executor asyncBukkit() {
return this.asyncBukkit;
}
@Override
public Executor sync() {
return this.sync;
@@ -135,6 +126,11 @@ public class BukkitSchedulerAdapter implements SchedulerAdapter {
return this.async;
}
@Override
public Executor platformAsync() {
return this.asyncBukkit;
}
public void setUseFallback(boolean useFallback) {
this.useFallback = useFallback;
}
@@ -142,14 +138,14 @@ public class BukkitSchedulerAdapter implements SchedulerAdapter {
private final class SyncExecutor implements Executor {
@Override
public void execute(@Nonnull Runnable runnable) {
BukkitSchedulerAdapter.this.plugin.getServer().getScheduler().scheduleSyncDelayedTask(BukkitSchedulerAdapter.this.plugin, runnable);
BukkitSchedulerAdapter.this.bootstrap.getServer().getScheduler().scheduleSyncDelayedTask(BukkitSchedulerAdapter.this.bootstrap, runnable);
}
}
private final class AsyncExecutor implements Executor {
@Override
public void execute(@Nonnull Runnable runnable) {
if (BukkitSchedulerAdapter.this.useFallback || !BukkitSchedulerAdapter.this.plugin.isEnabled()) {
if (BukkitSchedulerAdapter.this.useFallback || !BukkitSchedulerAdapter.this.bootstrap.isEnabled()) {
BukkitSchedulerAdapter.this.asyncFallback.execute(runnable);
} else {
BukkitSchedulerAdapter.this.asyncBukkit.execute(runnable);
@@ -160,7 +156,7 @@ public class BukkitSchedulerAdapter implements SchedulerAdapter {
private final class BukkitAsyncExecutor implements Executor {
@Override
public void execute(@Nonnull Runnable runnable) {
BukkitSchedulerAdapter.this.plugin.getServer().getScheduler().runTaskAsynchronously(BukkitSchedulerAdapter.this.plugin, runnable);
BukkitSchedulerAdapter.this.bootstrap.getServer().getScheduler().runTaskAsynchronously(BukkitSchedulerAdapter.this.bootstrap, runnable);
}
}
@@ -29,9 +29,9 @@ import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.bukkit.compat.BukkitJsonMessageHandler;
import me.lucko.luckperms.bukkit.compat.ReflectionUtil;
import me.lucko.luckperms.bukkit.compat.SpigotJsonMessageHandler;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.commands.sender.SenderFactory;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.SenderFactory;
import me.lucko.luckperms.common.utils.TextUtils;
import net.kyori.text.Component;
@@ -79,7 +79,7 @@ public class BukkitSenderFactory extends SenderFactory<CommandSender> {
}
// otherwise, send the message sync
getPlugin().getScheduler().doSync(new SyncMessengerAgent(sender, s));
getPlugin().getBootstrap().getScheduler().doSync(new SyncMessengerAgent(sender, s));
}
@Override
@@ -0,0 +1,253 @@
/*
* 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 me.lucko.luckperms.api.platform.PlatformType;
import me.lucko.luckperms.bukkit.compat.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;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.InputStream;
import java.nio.file.Path;
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.
*/
public class LPBukkitBootstrap extends JavaPlugin implements LuckPermsBootstrap {
/**
* A scheduler adapter for the platform
*/
private final BukkitSchedulerAdapter schedulerAdapter;
/**
* The plugin classloader
*/
private final PluginClassLoader classLoader;
/**
* A null-safe console instance which delegates to the server logger
* if {@link Server#getConsoleSender()} returns null.
*/
private final ConsoleCommandSender console;
/**
* The plugin instance
*/
private final LPBukkitPlugin plugin;
/**
* The time when the plugin was enabled
*/
private long 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 LPBukkitBootstrap() {
this.schedulerAdapter = new BukkitSchedulerAdapter(this);
this.classLoader = new ReflectionClassLoader(this);
this.console = new NullSafeConsoleCommandSender(getServer());
this.plugin = new LPBukkitPlugin(this);
}
// provide adapters
@Override
public BukkitSchedulerAdapter getScheduler() {
return this.schedulerAdapter;
}
@Override
public PluginClassLoader getPluginClassLoader() {
return this.classLoader;
}
public ConsoleCommandSender getConsole() {
return this.console;
}
// lifecycle
@Override
public void onLoad() {
if (checkIncompatibleVersion()) {
this.incompatibleVersion = true;
return;
}
try {
this.plugin.load();
} finally {
this.loadLatch.countDown();
}
}
@Override
public void onEnable() {
if (this.incompatibleVersion) {
getLogger().severe("----------------------------------------------------------------------");
getLogger().severe("Your server version is not compatible with this build of LuckPerms. :(");
getLogger().severe("");
getLogger().severe("If your server is running 1.8, please update to 1.8.8 or higher.");
getLogger().severe("If your server is running 1.7.10, please download the Bukkit-Legacy version of LuckPerms from here:");
getLogger().severe("==> https://ci.lucko.me/job/LuckPermsLegacy/");
getLogger().severe("----------------------------------------------------------------------");
getServer().getPluginManager().disablePlugin(this);
return;
}
this.startTime = System.currentTimeMillis();
try {
this.plugin.enable();
} finally {
this.enableLatch.countDown();
}
}
@Override
public void onDisable() {
if (this.incompatibleVersion) {
return;
}
this.plugin.disable();
}
@Override
public CountDownLatch getEnableLatch() {
return this.enableLatch;
}
@Override
public CountDownLatch getLoadLatch() {
return this.loadLatch;
}
// provide information about the plugin
@Override
public String getVersion() {
return getDescription().getVersion();
}
@Override
public long getStartupTime() {
return this.startTime;
}
// provide information about the platform
@Override
public PlatformType getType() {
return PlatformType.BUKKIT;
}
@Override
public String getServerBrand() {
return getServer().getName();
}
@Override
public String getServerVersion() {
return getServer().getVersion() + " - " + getServer().getBukkitVersion();
}
@Override
public String getServerName() {
return getServer().getServerName();
}
@Override
public Path getDataDirectory() {
return getDataFolder().toPath().toAbsolutePath();
}
@Override
public InputStream getResourceStream(String path) {
return getResource(path);
}
@Override
public Optional<Player> getPlayer(UUID uuid) {
return Optional.ofNullable(getServer().getPlayer(uuid));
}
@Override
public Optional<UUID> lookupUuid(String username) {
//noinspection deprecation
return Optional.ofNullable(getServer().getOfflinePlayer(username)).map(OfflinePlayer::getUniqueId);
}
@Override
public Optional<String> lookupUsername(UUID uuid) {
return Optional.ofNullable(getServer().getOfflinePlayer(uuid)).map(OfflinePlayer::getName);
}
@Override
public int getPlayerCount() {
return getServer().getOnlinePlayers().size();
}
@Override
public Stream<String> getPlayerList() {
return getServer().getOnlinePlayers().stream().map(Player::getName);
}
@Override
public Stream<UUID> getOnlinePlayers() {
return getServer().getOnlinePlayers().stream().map(Player::getUniqueId);
}
@Override
public boolean isPlayerOnline(UUID uuid) {
Player player = getServer().getPlayer(uuid);
return player != null && player.isOnline();
}
private static boolean checkIncompatibleVersion() {
try {
Class.forName("com.google.gson.JsonElement");
return false;
} catch (ClassNotFoundException e) {
return true;
}
}
}
@@ -27,7 +27,7 @@ package me.lucko.luckperms.bukkit;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.api.platform.PlatformType;
import me.lucko.luckperms.api.event.user.UserDataRecalculateEvent;
import me.lucko.luckperms.bukkit.calculators.BukkitCalculatorFactory;
import me.lucko.luckperms.bukkit.contexts.BukkitContextManager;
import me.lucko.luckperms.bukkit.contexts.WorldCalculator;
@@ -44,212 +44,132 @@ import me.lucko.luckperms.bukkit.model.server.LPDefaultsMap;
import me.lucko.luckperms.bukkit.model.server.LPPermissionMap;
import me.lucko.luckperms.bukkit.model.server.LPSubscriptionMap;
import me.lucko.luckperms.bukkit.vault.VaultHookManager;
import me.lucko.luckperms.common.actionlog.LogDispatcher;
import me.lucko.luckperms.common.api.ApiRegistrationUtil;
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
import me.lucko.luckperms.common.buffers.BufferedRequest;
import me.lucko.luckperms.common.buffers.UpdateTaskBuffer;
import me.lucko.luckperms.common.caching.handlers.CachedStateManager;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.commands.CommandPermission;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.config.AbstractConfiguration;
import me.lucko.luckperms.common.api.delegates.model.ApiUser;
import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
import me.lucko.luckperms.common.contexts.ContextManager;
import me.lucko.luckperms.common.contexts.LuckPermsCalculator;
import me.lucko.luckperms.common.dependencies.DependencyManager;
import me.lucko.luckperms.common.dependencies.DependencyRegistry;
import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader;
import me.lucko.luckperms.common.dependencies.classloader.ReflectionClassLoader;
import me.lucko.luckperms.common.event.EventFactory;
import me.lucko.luckperms.common.inheritance.InheritanceHandler;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.NoopLocaleManager;
import me.lucko.luckperms.common.locale.SimpleLocaleManager;
import me.lucko.luckperms.common.logging.Logger;
import me.lucko.luckperms.common.logging.SenderLogger;
import me.lucko.luckperms.common.dependencies.Dependency;
import me.lucko.luckperms.common.event.AbstractEventBus;
import me.lucko.luckperms.common.listener.ConnectionListener;
import me.lucko.luckperms.common.managers.group.StandardGroupManager;
import me.lucko.luckperms.common.managers.track.StandardTrackManager;
import me.lucko.luckperms.common.managers.user.StandardUserManager;
import me.lucko.luckperms.common.messaging.InternalMessagingService;
import me.lucko.luckperms.common.messaging.MessagingFactory;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.storage.StorageFactory;
import me.lucko.luckperms.common.storage.StorageType;
import me.lucko.luckperms.common.storage.dao.file.FileWatcher;
import me.lucko.luckperms.common.plugin.AbstractLuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.tasks.CacheHousekeepingTask;
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
import me.lucko.luckperms.common.tasks.UpdateTask;
import me.lucko.luckperms.common.treeview.PermissionVault;
import me.lucko.luckperms.common.verbose.VerboseHandler;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Stream;
/**
* LuckPerms implementation for the Bukkit API.
*/
public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
private final LPBukkitBootstrap bootstrap;
private long startTime;
private BukkitSchedulerAdapter scheduler;
private BukkitSenderFactory senderFactory;
private BukkitConnectionListener connectionListener;
private BukkitCommandExecutor commandManager;
private VaultHookManager vaultHookManager = null;
private LuckPermsConfiguration configuration;
private StandardUserManager userManager;
private StandardGroupManager groupManager;
private StandardTrackManager trackManager;
private Storage storage;
private FileWatcher fileWatcher = null;
private InternalMessagingService messagingService = null;
private LuckPermsApiProvider apiProvider;
private EventFactory eventFactory;
private Logger log;
private ContextManager<Player> contextManager;
private LPSubscriptionMap subscriptionMap;
private LPPermissionMap permissionMap;
private LPDefaultsMap defaultPermissionMap;
private LocaleManager localeManager;
private PluginClassLoader pluginClassLoader;
private DependencyManager dependencyManager;
private InheritanceHandler inheritanceHandler;
private CachedStateManager cachedStateManager;
private ContextManager<Player> contextManager;
private CalculatorFactory calculatorFactory;
private BufferedRequest<Void> updateTaskBuffer;
private CountDownLatch enableLatch = new CountDownLatch(1);
private VerboseHandler verboseHandler;
private BukkitSenderFactory senderFactory;
private PermissionVault permissionVault;
private LogDispatcher logDispatcher;
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
private boolean invalidVersion = false;
private VaultHookManager vaultHookManager = null;
public LPBukkitPlugin(LPBukkitBootstrap bootstrap) {
this.bootstrap = bootstrap;
}
@Override
public void onLoad() {
if (checkInvalidVersion()) {
this.invalidVersion = true;
return;
}
public LPBukkitBootstrap getBootstrap() {
return this.bootstrap;
}
// setup minimal functionality in order to load initial dependencies
this.scheduler = new BukkitSchedulerAdapter(this);
this.localeManager = new NoopLocaleManager();
@Override
protected void setupSenderFactory() {
this.senderFactory = new BukkitSenderFactory(this);
this.log = new SenderLogger(this, getConsoleSender());
this.pluginClassLoader = new ReflectionClassLoader(this);
this.dependencyManager = new DependencyManager(this);
this.dependencyManager.loadDependencies(DependencyRegistry.GLOBAL_DEPENDENCIES);
}
@Override
public void onEnable() {
if (this.invalidVersion) {
getLogger().severe("----------------------------------------------------------------------");
getLogger().severe("Your server version is not compatible with this build of LuckPerms. :(");
getLogger().severe("");
getLogger().severe("If your server is running 1.8, please update to 1.8.8 or higher.");
getLogger().severe("If your server is running 1.7.10, please download the Bukkit-Legacy version of LuckPerms from here:");
getLogger().severe("==> https://ci.lucko.me/job/LuckPermsLegacy/");
getLogger().severe("----------------------------------------------------------------------");
getServer().getPluginManager().disablePlugin(this);
return;
}
try {
enable();
} finally {
// count down the latch when onEnable has been called
// we don't care about the result here
this.enableLatch.countDown();
}
protected Set<Dependency> getGlobalDependencies() {
return EnumSet.of(Dependency.CAFFEINE, Dependency.OKIO, Dependency.OKHTTP);
}
private void enable() {
this.startTime = System.currentTimeMillis();
sendStartupBanner(getConsoleSender());
this.verboseHandler = new VerboseHandler(this.scheduler.asyncBukkit());
this.permissionVault = new PermissionVault(this.scheduler.asyncBukkit());
this.logDispatcher = new LogDispatcher(this);
@Override
protected ConfigurationAdapter provideConfigurationAdapter() {
return new BukkitConfigAdapter(this, resolveConfig());
}
getLog().info("Loading configuration...");
this.configuration = new AbstractConfiguration(this, new BukkitConfigAdapter(this, resolveConfig("config.yml")));
this.configuration.loadAll();
@Override
protected void registerPlatformListeners() {
this.connectionListener = new BukkitConnectionListener(this);
this.bootstrap.getServer().getPluginManager().registerEvents(this.connectionListener, this.bootstrap);
this.bootstrap.getServer().getPluginManager().registerEvents(new BukkitPlatformListener(this), this.bootstrap);
}
StorageFactory storageFactory = new StorageFactory(this);
Set<StorageType> storageTypes = storageFactory.getRequiredTypes(StorageType.H2);
this.dependencyManager.loadStorageDependencies(storageTypes);
@Override
protected MessagingFactory<?> provideMessagingFactory() {
return new BukkitMessagingFactory(this);
}
// register events
BukkitConnectionListener connectionListener = new BukkitConnectionListener(this);
getServer().getPluginManager().registerEvents(connectionListener, this);
getServer().getPluginManager().registerEvents(new BukkitPlatformListener(this), this);
if (getConfiguration().get(ConfigKeys.WATCH_FILES)) {
this.fileWatcher = new FileWatcher(this);
getScheduler().asyncRepeating(this.fileWatcher, 30L);
}
// initialise datastore
this.storage = storageFactory.getInstance(StorageType.H2);
// initialise messaging
this.messagingService = new BukkitMessagingFactory(this).getInstance();
// setup the update task buffer
this.updateTaskBuffer = new UpdateTaskBuffer(this);
// load locale
this.localeManager = new SimpleLocaleManager();
this.localeManager.tryLoad(this, new File(getDataFolder(), "lang.yml"));
// register commands
@Override
protected void registerCommands() {
this.commandManager = new BukkitCommandExecutor(this);
PluginCommand main = getServer().getPluginCommand("luckperms");
PluginCommand main = this.bootstrap.getServer().getPluginCommand("luckperms");
main.setExecutor(this.commandManager);
main.setTabCompleter(this.commandManager);
main.setDescription("Manage permissions");
main.setAliases(Arrays.asList("lp", "perm", "perms", "permission", "permissions"));
}
// load internal managers
getLog().info("Loading internal permission managers...");
this.inheritanceHandler = new InheritanceHandler(this);
@Override
protected void setupManagers() {
this.userManager = new StandardUserManager(this);
this.groupManager = new StandardGroupManager(this);
this.trackManager = new StandardTrackManager(this);
this.calculatorFactory = new BukkitCalculatorFactory(this);
this.cachedStateManager = new CachedStateManager();
}
// setup context manager
@Override
protected PlatformCalculatorFactory provideCalculatorFactory() {
return new BukkitCalculatorFactory(this);
}
@Override
protected void setupContextManager() {
this.contextManager = new BukkitContextManager(this);
this.contextManager.registerCalculator(new WorldCalculator(this));
this.contextManager.registerStaticCalculator(new LuckPermsCalculator(getConfiguration()));
}
@Override
protected void setupPlatformHooks() {
// inject our own custom permission maps
Runnable[] injectors = new Runnable[]{
new InjectorSubscriptionMap(this),
new InjectorPermissionMap(this),
new InjectorDefaultsMap(this)
new InjectorDefaultsMap(this),
new PermissibleMonitoringInjector(this)
};
for (Runnable injector : injectors) {
@@ -257,49 +177,52 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
// schedule another injection after all plugins have loaded
// the entire pluginmanager instance is replaced by some plugins :(
this.scheduler.asyncLater(injector, 1L);
this.bootstrap.getScheduler().asyncLater(injector, 1L);
}
// inject verbose handlers into internal bukkit objects
new PermissibleMonitoringInjector(this).run();
// Provide vault support
tryVaultHook(false);
}
// register with the LP API
this.apiProvider = new LuckPermsApiProvider(this);
@Override
protected AbstractEventBus provideEventBus(LuckPermsApiProvider apiProvider) {
return new BukkitEventBus(this, apiProvider);
}
// setup event factory
this.eventFactory = new EventFactory(this, this.apiProvider);
ApiRegistrationUtil.registerProvider(this.apiProvider);
getServer().getServicesManager().register(LuckPermsApi.class, this.apiProvider, this, ServicePriority.Normal);
// schedule update tasks
int mins = getConfiguration().get(ConfigKeys.SYNC_TIME);
if (mins > 0) {
long ticks = mins * 60 * 20;
this.scheduler.asyncRepeating(() -> this.updateTaskBuffer.request(), ticks);
public void tryVaultHook(boolean force) {
if (this.vaultHookManager != null) {
return; // already hooked
}
this.scheduler.asyncLater(() -> this.updateTaskBuffer.request(), 40L);
// run an update instantly.
getLog().info("Performing initial data load...");
try {
new UpdateTask(this, true).run();
if (force || this.bootstrap.getServer().getPluginManager().isPluginEnabled("Vault")) {
this.vaultHookManager = new VaultHookManager();
this.vaultHookManager.hook(this);
getLogger().info("Registered Vault permission & chat hook.");
}
} catch (Exception e) {
this.vaultHookManager = null;
getLogger().severe("Error occurred whilst hooking into Vault.");
e.printStackTrace();
}
}
@Override
protected void registerApiOnPlatform(LuckPermsApi api) {
this.bootstrap.getServer().getServicesManager().register(LuckPermsApi.class, api, this.bootstrap, ServicePriority.Normal);
}
// register tasks
this.scheduler.asyncRepeating(new ExpireTemporaryTask(this), 60L);
this.scheduler.asyncRepeating(new CacheHousekeepingTask(this), 2400L);
@Override
protected void registerHousekeepingTasks() {
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 60L);
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2400L);
}
@Override
protected void performFinalSetup() {
// register permissions
try {
PluginManager pm = getServer().getPluginManager();
PluginManager pm = this.bootstrap.getServer().getPluginManager();
PermissionDefault permDefault = getConfiguration().get(ConfigKeys.COMMANDS_ALLOW_OP) ? PermissionDefault.OP : PermissionDefault.FALSE;
for (CommandPermission p : CommandPermission.values()) {
@@ -309,20 +232,34 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
// this throws an exception if the plugin is /reloaded, grr
}
// remove all operators on startup if they're disabled
if (!getConfiguration().get(ConfigKeys.OPS_ENABLED)) {
this.scheduler.doSync(() -> getServer().getOperators().forEach(o -> o.setOp(false)));
this.bootstrap.getScheduler().platformAsync().execute(() -> {
for (OfflinePlayer player : this.bootstrap.getServer().getOperators()) {
player.setOp(false);
}
});
}
// 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.getUuid());
player.ifPresent(this::refreshAutoOp);
});
}
// replace the temporary executor when the Bukkit one starts
getServer().getScheduler().runTaskAsynchronously(this, () -> this.scheduler.setUseFallback(false));
this.bootstrap.getServer().getScheduler().runTaskAsynchronously(this.bootstrap, () -> this.bootstrap.getScheduler().setUseFallback(false));
// Load any online users (in the case of a reload)
for (Player player : getServer().getOnlinePlayers()) {
this.scheduler.doAsync(() -> {
for (Player player : this.bootstrap.getServer().getOnlinePlayers()) {
this.bootstrap.getScheduler().doAsync(() -> {
try {
User user = connectionListener.loadUser(player.getUniqueId(), player.getName());
User user = this.connectionListener.loadUser(player.getUniqueId(), player.getName());
if (user != null) {
this.scheduler.doSync(() -> {
this.bootstrap.getScheduler().doSync(() -> {
try {
LPPermissible lpPermissible = new LPPermissible(player, user, this);
PermissibleInjector.inject(player, lpPermissible);
@@ -336,24 +273,18 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
});
}
getLog().info("Successfully enabled. (took " + (System.currentTimeMillis() - this.startTime) + "ms)");
}
@Override
public void onDisable() {
if (this.invalidVersion) {
return;
}
protected void performEarlyDisableTasks() {
// Switch back to the fallback executor, the bukkit one won't allow new tasks
this.scheduler.setUseFallback(true);
this.permissionVault.shutdown();
this.verboseHandler.shutdown();
this.bootstrap.getScheduler().setUseFallback(true);
}
@Override
protected void removePlatformHooks() {
// uninject from players
for (Player player : getServer().getOnlinePlayers()) {
for (Player player : this.bootstrap.getServer().getOnlinePlayers()) {
try {
PermissibleInjector.unInject(player, false);
} catch (Exception e) {
@@ -366,7 +297,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
final User user = getUserManager().getIfLoaded(player.getUniqueId());
if (user != null) {
user.getCachedData().invalidateCaches();
user.getCachedData().invalidate();
getUserManager().unload(user);
}
}
@@ -376,75 +307,86 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
InjectorPermissionMap.uninject();
InjectorDefaultsMap.uninject();
getLog().info("Closing storage...");
this.storage.shutdown();
if (this.fileWatcher != null) {
this.fileWatcher.close();
}
if (this.messagingService != null) {
getLog().info("Closing messaging service...");
this.messagingService.close();
}
ApiRegistrationUtil.unregisterProvider();
getServer().getServicesManager().unregisterAll(this);
// unhook vault
if (this.vaultHookManager != null) {
this.vaultHookManager.unhook(this);
}
getLog().info("Shutting down internal scheduler...");
this.scheduler.shutdown();
// Bukkit will do this again when #onDisable completes, but we do it early to prevent NPEs elsewhere.
getServer().getScheduler().cancelTasks(this);
HandlerList.unregisterAll(this);
getLog().info("Goodbye!");
}
public void tryVaultHook(boolean force) {
if (this.vaultHookManager != null) {
return; // already hooked
}
try {
if (force || getServer().getPluginManager().isPluginEnabled("Vault")) {
this.vaultHookManager = new VaultHookManager();
this.vaultHookManager.hook(this);
getLog().info("Registered Vault permission & chat hook.");
}
} catch (Exception e) {
this.vaultHookManager = null;
getLog().severe("Error occurred whilst hooking into Vault.");
e.printStackTrace();
}
}
public void refreshAutoOp(User user, Player player) {
if (user == null) {
return;
}
public void refreshAutoOp(Player player) {
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
Map<String, Boolean> backing = user.getCachedData().getPermissionData(this.contextManager.getApplicableContexts(player)).getImmutableBacking();
boolean op = Optional.ofNullable(backing.get("luckperms.autoop")).orElse(false);
player.setOp(op);
User user = getUserManager().getIfLoaded(player.getUniqueId());
if (user == null) {
player.setOp(false);
return;
}
Map<String, Boolean> permData = user.getCachedData().getPermissionData(this.contextManager.getApplicableContexts(player)).getImmutableBacking();
player.setOp(permData.getOrDefault("luckperms.autoop", false));
}
}
private File resolveConfig(String file) {
File configFile = new File(getDataFolder(), file);
private File resolveConfig() {
File configFile = new File(this.bootstrap.getDataFolder(), "config.yml");
if (!configFile.exists()) {
getDataFolder().mkdirs();
saveResource("config.yml", false);
this.bootstrap.getDataFolder().mkdirs();
this.bootstrap.saveResource("config.yml", false);
}
return configFile;
}
@Override
public Optional<Contexts> getContextForUser(User user) {
return this.bootstrap.getPlayer(user.getUuid()).map(player -> this.contextManager.getApplicableContexts(player));
}
@Override
public Stream<Sender> getOnlineSenders() {
return Stream.concat(
Stream.of(getConsoleSender()),
this.bootstrap.getServer().getOnlinePlayers().stream().map(p -> getSenderFactory().wrap(p))
);
}
@Override
public Sender getConsoleSender() {
return getSenderFactory().wrap(this.bootstrap.getConsole());
}
public BukkitSenderFactory getSenderFactory() {
return this.senderFactory;
}
@Override
public ConnectionListener getConnectionListener() {
return this.connectionListener;
}
@Override
public BukkitCommandExecutor getCommandManager() {
return this.commandManager;
}
@Override
public StandardUserManager getUserManager() {
return this.userManager;
}
@Override
public StandardGroupManager getGroupManager() {
return this.groupManager;
}
@Override
public StandardTrackManager getTrackManager() {
return this.trackManager;
}
@Override
public ContextManager<Player> getContextManager() {
return this.contextManager;
}
public LPSubscriptionMap getSubscriptionMap() {
return this.subscriptionMap;
}
@@ -469,250 +411,4 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
this.defaultPermissionMap = defaultPermissionMap;
}
@Override
public Optional<InternalMessagingService> getMessagingService() {
return Optional.ofNullable(this.messagingService);
}
@Override
public void setMessagingService(InternalMessagingService messagingService) {
if (this.messagingService == null) {
this.messagingService = messagingService;
}
}
@Override
public Optional<FileWatcher> getFileWatcher() {
return Optional.ofNullable(this.fileWatcher);
}
@Override
public String getVersion() {
return getDescription().getVersion();
}
@Override
public PlatformType getServerType() {
return PlatformType.BUKKIT;
}
@Override
public String getServerBrand() {
return getServer().getName();
}
@Override
public String getServerVersion() {
return getServer().getVersion() + " - " + getServer().getBukkitVersion();
}
@Override
public String getServerName() {
return getServer().getServerName();
}
@Override
public File getDataDirectory() {
return super.getDataFolder();
}
@Override
public InputStream getResourceStream(String path) {
return getResource(path);
}
@Override
public Player getPlayer(User user) {
return getServer().getPlayer(user.getUuid());
}
@Override
public Optional<UUID> lookupUuid(String username) {
try {
//noinspection deprecation
return Optional.ofNullable(getServer().getOfflinePlayer(username)).flatMap(p -> Optional.ofNullable(p.getUniqueId()));
} catch (Exception e) {
e.printStackTrace();
return Optional.empty();
}
}
@Override
public Optional<Contexts> getContextForUser(User user) {
Player player = getPlayer(user);
if (player == null) {
return Optional.empty();
}
return Optional.of(this.contextManager.getApplicableContexts(player));
}
@Override
public int getPlayerCount() {
return getServer().getOnlinePlayers().size();
}
@Override
public Stream<String> getPlayerList() {
return getServer().getOnlinePlayers().stream().map(Player::getName);
}
@Override
public Stream<UUID> getOnlinePlayers() {
return getServer().getOnlinePlayers().stream().map(Player::getUniqueId);
}
@Override
public boolean isPlayerOnline(UUID external) {
Player player = getServer().getPlayer(external);
return player != null && player.isOnline();
}
@Override
public Stream<Sender> getOnlineSenders() {
return Stream.concat(
Stream.of(getConsoleSender()),
getServer().getOnlinePlayers().stream().map(p -> getSenderFactory().wrap(p))
);
}
@Override
public Sender getConsoleSender() {
return getSenderFactory().wrap(getServer().getConsoleSender());
}
private static boolean checkInvalidVersion() {
try {
Class.forName("com.google.gson.JsonElement");
return false;
} catch (ClassNotFoundException e) {
return true;
}
}
@Override
public long getStartTime() {
return this.startTime;
}
@Override
public BukkitSchedulerAdapter getScheduler() {
return this.scheduler;
}
@Override
public BukkitCommandExecutor getCommandManager() {
return this.commandManager;
}
public VaultHookManager getVaultHookManager() {
return this.vaultHookManager;
}
@Override
public LuckPermsConfiguration getConfiguration() {
return this.configuration;
}
@Override
public StandardUserManager getUserManager() {
return this.userManager;
}
@Override
public StandardGroupManager getGroupManager() {
return this.groupManager;
}
@Override
public StandardTrackManager getTrackManager() {
return this.trackManager;
}
@Override
public Storage getStorage() {
return this.storage;
}
@Override
public LuckPermsApiProvider getApiProvider() {
return this.apiProvider;
}
@Override
public EventFactory getEventFactory() {
return this.eventFactory;
}
@Override
public Logger getLog() {
return this.log;
}
@Override
public LocaleManager getLocaleManager() {
return this.localeManager;
}
@Override
public PluginClassLoader getPluginClassLoader() {
return this.pluginClassLoader;
}
@Override
public DependencyManager getDependencyManager() {
return this.dependencyManager;
}
@Override
public CachedStateManager getCachedStateManager() {
return this.cachedStateManager;
}
@Override
public ContextManager<Player> getContextManager() {
return this.contextManager;
}
@Override
public InheritanceHandler getInheritanceHandler() {
return this.inheritanceHandler;
}
@Override
public CalculatorFactory getCalculatorFactory() {
return this.calculatorFactory;
}
@Override
public BufferedRequest<Void> getUpdateTaskBuffer() {
return this.updateTaskBuffer;
}
public CountDownLatch getEnableLatch() {
return this.enableLatch;
}
@Override
public VerboseHandler getVerboseHandler() {
return this.verboseHandler;
}
public BukkitSenderFactory getSenderFactory() {
return this.senderFactory;
}
@Override
public PermissionVault getPermissionVault() {
return this.permissionVault;
}
@Override
public LogDispatcher getLogDispatcher() {
return this.logDispatcher;
}
@Override
public Set<UUID> getUniqueConnections() {
return this.uniqueConnections;
}
}
@@ -28,6 +28,7 @@ package me.lucko.luckperms.bukkit.calculators;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.LookupSetting;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.bukkit.processors.ChildProcessor;
import me.lucko.luckperms.bukkit.processors.DefaultsProcessor;
@@ -35,11 +36,11 @@ import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
import me.lucko.luckperms.common.calculators.PermissionCalculator;
import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.HolderType;
import me.lucko.luckperms.common.processors.MapProcessor;
import me.lucko.luckperms.common.processors.PermissionProcessor;
import me.lucko.luckperms.common.processors.RegexProcessor;
import me.lucko.luckperms.common.processors.WildcardProcessor;
import me.lucko.luckperms.common.references.HolderType;
public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
private final LPBukkitPlugin plugin;
@@ -67,7 +68,7 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
}
if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS) && metadata.getHolderType() == HolderType.USER) {
processors.add(new DefaultsProcessor(this.plugin, contexts.isOp()));
processors.add(new DefaultsProcessor(this.plugin, contexts.hasSetting(LookupSetting.IS_OP)));
}
return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build()));
@@ -0,0 +1,124 @@
/*
* 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 org.bukkit.ChatColor;
import org.bukkit.Server;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationAbandonedEvent;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
import java.util.Optional;
import java.util.Set;
/**
* The {@link Server#getConsoleSender()} method returns null during onEnable
* in older CraftBukkit builds. This prevents LuckPerms from loading correctly.
*/
public class NullSafeConsoleCommandSender implements ConsoleCommandSender {
private final Server server;
public NullSafeConsoleCommandSender(Server server) {
this.server = server;
}
private Optional<ConsoleCommandSender> get() {
return Optional.ofNullable(this.server.getConsoleSender());
}
@Override
public Server getServer() {
return this.server;
}
@Override
public String getName() {
return "CONSOLE";
}
@Override
public void sendMessage(String message) {
Optional<ConsoleCommandSender> console = get();
if (console.isPresent()) {
console.get().sendMessage(message);
} else {
this.server.getLogger().info(ChatColor.stripColor(message));
}
}
@Override
public void sendMessage(String[] messages) {
for (String msg : messages) {
sendMessage(msg);
}
}
@Override
public boolean isPermissionSet(String s) {
return get().map(c -> c.isPermissionSet(s)).orElse(true);
}
@Override
public boolean isPermissionSet(Permission permission) {
return get().map(c -> c.isPermissionSet(permission)).orElse(true);
}
@Override
public boolean hasPermission(String s) {
return get().map(c -> c.hasPermission(s)).orElse(true);
}
@Override
public boolean hasPermission(Permission permission) {
return get().map(c -> c.hasPermission(permission)).orElse(true);
}
@Override
public boolean isOp() {
return true;
}
// just throw UnsupportedOperationException - we never use any of these methods
@Override public Spigot spigot() { throw new UnsupportedOperationException(); }
@Override public boolean isConversing() { throw new UnsupportedOperationException(); }
@Override public void acceptConversationInput(String s) { throw new UnsupportedOperationException(); }
@Override public boolean beginConversation(Conversation conversation) { throw new UnsupportedOperationException(); }
@Override public void abandonConversation(Conversation conversation) { throw new UnsupportedOperationException(); }
@Override public void abandonConversation(Conversation conversation, ConversationAbandonedEvent conversationAbandonedEvent) { throw new UnsupportedOperationException(); }
@Override public void sendRawMessage(String s) { throw new UnsupportedOperationException(); }
@Override public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b) { throw new UnsupportedOperationException(); }
@Override public PermissionAttachment addAttachment(Plugin plugin) { throw new UnsupportedOperationException(); }
@Override public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b, int i) { throw new UnsupportedOperationException(); }
@Override public PermissionAttachment addAttachment(Plugin plugin, int i) { throw new UnsupportedOperationException(); }
@Override public void removeAttachment(PermissionAttachment permissionAttachment) { throw new UnsupportedOperationException(); }
@Override public void recalculatePermissions() { throw new UnsupportedOperationException(); }
@Override public Set<PermissionAttachmentInfo> getEffectivePermissions() { throw new UnsupportedOperationException(); }
@Override public void setOp(boolean b) { throw new UnsupportedOperationException(); }
}
@@ -28,10 +28,10 @@ package me.lucko.luckperms.bukkit.compat;
import org.bukkit.Bukkit;
public final class ReflectionUtil {
private static final String SERVER_VERSION = _getServerVersion();
private static final String SERVER_VERSION = getServerVersion();
private static final boolean CHAT_COMPATIBLE = !SERVER_VERSION.startsWith(".v1_7_");
private static String _getServerVersion() {
private static String getServerVersion() {
Class<?> server = Bukkit.getServer().getClass();
if (!server.getSimpleName().equals("CraftServer")) {
return ".";
@@ -45,16 +45,12 @@ public final class ReflectionUtil {
}
}
private static String getServerVersion() {
return SERVER_VERSION;
}
public static boolean isChatCompatible() {
return CHAT_COMPATIBLE;
}
public static String nms(String className) {
return "net.minecraft.server" + getServerVersion() + className;
return "net.minecraft.server" + SERVER_VERSION + className;
}
public static Class<?> nmsClass(String className) throws ClassNotFoundException {
@@ -62,7 +58,7 @@ public final class ReflectionUtil {
}
public static String obc(String className) {
return "org.bukkit.craftbukkit" + getServerVersion() + className;
return "org.bukkit.craftbukkit" + SERVER_VERSION + className;
}
public static Class<?> obcClass(String className) throws ClassNotFoundException {
@@ -40,7 +40,7 @@ public class BukkitContextManager extends AbstractContextManager<Player> {
@Override
public Contexts formContexts(Player subject, ImmutableContextSet contextSet) {
return new Contexts(
return Contexts.of(
contextSet,
this.plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
this.plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
@@ -29,9 +29,9 @@ import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.bukkit.model.permissible.LPPermissible;
import me.lucko.luckperms.bukkit.model.permissible.PermissibleInjector;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.listener.AbstractConnectionListener;
import me.lucko.luckperms.common.locale.message.Message;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.utils.AbstractLoginListener;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -47,7 +47,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class BukkitConnectionListener extends AbstractLoginListener implements Listener {
public class BukkitConnectionListener extends AbstractConnectionListener implements Listener {
private final LPBukkitPlugin plugin;
private final Set<UUID> deniedAsyncLogin = Collections.synchronizedSet(new HashSet<>());
@@ -66,16 +66,16 @@ public class BukkitConnectionListener extends AbstractLoginListener implements L
/* wait for the plugin to enable. because these events are fired async, they can be called before
the plugin has enabled. */
try {
this.plugin.getEnableLatch().await(60, TimeUnit.SECONDS);
this.plugin.getBootstrap().getEnableLatch().await(60, TimeUnit.SECONDS);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
if (this.plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
this.plugin.getLog().info("Processing pre-login for " + e.getUniqueId() + " - " + e.getName());
this.plugin.getLogger().info("Processing pre-login for " + e.getUniqueId() + " - " + e.getName());
}
this.plugin.getUniqueConnections().add(e.getUniqueId());
recordConnection(e.getUniqueId());
/* Actually process the login for the connection.
We do this here to delay the login until the data is ready.
@@ -90,7 +90,7 @@ public class BukkitConnectionListener extends AbstractLoginListener implements L
User user = loadUser(e.getUniqueId(), e.getName());
this.plugin.getEventFactory().handleUserLoginProcess(e.getUniqueId(), e.getName(), user);
} catch (Exception ex) {
this.plugin.getLog().severe("Exception occurred whilst loading data for " + e.getUniqueId() + " - " + e.getName());
this.plugin.getLogger().severe("Exception occurred whilst loading data for " + e.getUniqueId() + " - " + e.getName());
ex.printStackTrace();
// deny the connection
@@ -110,7 +110,7 @@ public class BukkitConnectionListener extends AbstractLoginListener implements L
// This is a problem, as they were denied at low priority, but are now being allowed.
if (e.getLoginResult() == AsyncPlayerPreLoginEvent.Result.ALLOWED) {
this.plugin.getLog().severe("Player connection was re-allowed for " + e.getUniqueId());
this.plugin.getLogger().severe("Player connection was re-allowed for " + e.getUniqueId());
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, "");
}
}
@@ -124,7 +124,7 @@ public class BukkitConnectionListener extends AbstractLoginListener implements L
final Player player = e.getPlayer();
if (this.plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
this.plugin.getLog().info("Processing login for " + player.getUniqueId() + " - " + player.getName());
this.plugin.getLogger().info("Processing login for " + player.getUniqueId() + " - " + player.getName());
}
final User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId());
@@ -133,7 +133,7 @@ public class BukkitConnectionListener extends AbstractLoginListener implements L
if (user == null) {
this.deniedLogin.add(e.getPlayer().getUniqueId());
this.plugin.getLog().warn("User " + player.getUniqueId() + " - " + player.getName() + " doesn't have data pre-loaded. - denying login.");
this.plugin.getLogger().warn("User " + player.getUniqueId() + " - " + player.getName() + " doesn't have data pre-loaded. - denying login.");
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.asString(this.plugin.getLocaleManager()));
return;
}
@@ -151,7 +151,7 @@ public class BukkitConnectionListener extends AbstractLoginListener implements L
t.printStackTrace();
}
this.plugin.refreshAutoOp(user, player);
this.plugin.refreshAutoOp(player);
}
@EventHandler(priority = EventPriority.MONITOR)
@@ -160,24 +160,13 @@ public class BukkitConnectionListener extends AbstractLoginListener implements L
If the connection was cancelled here, we need to do something to clean up the data that was loaded. */
// Check to see if this connection was denied at LOW. Even if it was denied at LOW, their data will still be present.
boolean denied = false;
if (this.deniedLogin.remove(e.getPlayer().getUniqueId())) {
denied = true;
// This is a problem, as they were denied at low priority, but are now being allowed.
if (e.getResult() == PlayerLoginEvent.Result.ALLOWED) {
this.plugin.getLog().severe("Player connection was re-allowed for " + e.getPlayer().getUniqueId());
this.plugin.getLogger().severe("Player connection was re-allowed for " + e.getPlayer().getUniqueId());
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, "");
}
}
// Login event was cancelled by another plugin since we first loaded their data
if (denied || e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
return;
}
// everything is going well. login was processed ok, this is just to refresh auto-op status.
this.plugin.refreshAutoOp(this.plugin.getUserManager().getIfLoaded(e.getPlayer().getUniqueId()), e.getPlayer());
}
// Wait until the last priority to unload, so plugins can still perform permission checks on this event
@@ -202,7 +191,7 @@ public class BukkitConnectionListener extends AbstractLoginListener implements L
this.plugin.getUserManager().getHouseKeeper().registerUsage(player.getUniqueId());
// force a clear of transient nodes
this.plugin.getScheduler().doAsync(() -> {
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId());
if (user != null) {
user.clearTransientNodes();
@@ -27,7 +27,7 @@ package me.lucko.luckperms.bukkit.listeners;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.locale.message.Message;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Cancellable;
@@ -95,7 +95,7 @@ public class BukkitPlatformListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onWorldChange(PlayerChangedWorldEvent e) {
this.plugin.getContextManager().invalidateCache(e.getPlayer());
this.plugin.refreshAutoOp(this.plugin.getUserManager().getIfLoaded(e.getPlayer().getUniqueId()), e.getPlayer());
this.plugin.refreshAutoOp(e.getPlayer());
}
}
@@ -49,8 +49,8 @@ public class BukkitMessagingFactory extends MessagingFactory<LPBukkitPlugin> {
e.printStackTrace();
}
} else if (messagingType.equals("lilypad")) {
if (getPlugin().getServer().getPluginManager().getPlugin("LilyPad-Connect") == null) {
getPlugin().getLog().warn("LilyPad-Connect plugin not present.");
if (getPlugin().getBootstrap().getServer().getPluginManager().getPlugin("LilyPad-Connect") == null) {
getPlugin().getLogger().warn("LilyPad-Connect plugin not present.");
} else {
try {
return new LuckPermsMessagingService(getPlugin(), new LilyPadMessengerProvider());
@@ -58,14 +58,14 @@ public class BungeeMessenger implements Messenger, PluginMessageListener {
}
public void init() {
this.plugin.getServer().getMessenger().registerOutgoingPluginChannel(this.plugin, CHANNEL);
this.plugin.getServer().getMessenger().registerIncomingPluginChannel(this.plugin, CHANNEL, this);
this.plugin.getBootstrap().getServer().getMessenger().registerOutgoingPluginChannel(this.plugin.getBootstrap(), CHANNEL);
this.plugin.getBootstrap().getServer().getMessenger().registerIncomingPluginChannel(this.plugin.getBootstrap(), CHANNEL, this);
}
@Override
public void close() {
this.plugin.getServer().getMessenger().unregisterIncomingPluginChannel(this.plugin, CHANNEL);
this.plugin.getServer().getMessenger().unregisterOutgoingPluginChannel(this.plugin, CHANNEL);
this.plugin.getBootstrap().getServer().getMessenger().unregisterIncomingPluginChannel(this.plugin.getBootstrap(), CHANNEL);
this.plugin.getBootstrap().getServer().getMessenger().unregisterOutgoingPluginChannel(this.plugin.getBootstrap(), CHANNEL);
}
@Override
@@ -73,7 +73,7 @@ public class BungeeMessenger implements Messenger, PluginMessageListener {
new BukkitRunnable() {
@Override
public void run() {
Collection<? extends Player> players = BungeeMessenger.this.plugin.getServer().getOnlinePlayers();
Collection<? extends Player> players = BungeeMessenger.this.plugin.getBootstrap().getServer().getOnlinePlayers();
Player p = Iterables.getFirst(players, null);
if (p == null) {
return;
@@ -84,10 +84,10 @@ public class BungeeMessenger implements Messenger, PluginMessageListener {
byte[] data = out.toByteArray();
p.sendPluginMessage(BungeeMessenger.this.plugin, CHANNEL, data);
p.sendPluginMessage(BungeeMessenger.this.plugin.getBootstrap(), CHANNEL, data);
cancel();
}
}.runTaskTimer(this.plugin, 1L, 100L);
}.runTaskTimer(this.plugin.getBootstrap(), 1L, 100L);
}
@Override
@@ -58,7 +58,7 @@ public class LilyPadMessenger implements Messenger {
}
public void init() {
this.connect = this.plugin.getServer().getServicesManager().getRegistration(Connect.class).getProvider();
this.connect = this.plugin.getBootstrap().getServer().getServicesManager().getRegistration(Connect.class).getProvider();
this.connect.registerEvents(this);
}
@@ -87,7 +87,7 @@ public class LilyPadMessenger implements Messenger {
@EventListener
public void onMessage(MessageEvent event) {
this.plugin.getScheduler().doAsync(() -> {
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
try {
String channel = event.getChannel();
@@ -32,24 +32,24 @@ import org.bukkit.Bukkit;
import java.util.UUID;
public final class BukkitMigrationUtils {
public final class BukkitUuids {
@SuppressWarnings("deprecation")
public static UUID lookupUuid(ProgressLogger log, String s) {
UUID uuid = Uuids.parseNullable(s);
if (uuid == null) {
try {
//noinspection deprecation
uuid = Bukkit.getOfflinePlayer(s).getUniqueId();
} catch (Exception ex) {
ex.printStackTrace();
}
}
if (uuid == null) {
log.logErr("Unable to get a UUID for user identifier: " + s);
log.logError("Unable to get a UUID for user identifier: " + s);
}
return uuid;
}
private BukkitMigrationUtils() {}
private BukkitUuids() {}
}
@@ -33,20 +33,21 @@ import de.bananaco.bpermissions.api.WorldManager;
import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.command.CommandResult;
import me.lucko.luckperms.common.command.abstraction.SubCommand;
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.logging.ProgressLogger;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.node.model.NodeTypes;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.utils.Iterators;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.SafeIteration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -58,7 +59,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import static me.lucko.luckperms.common.commands.CommandPermission.MIGRATION;
import static me.lucko.luckperms.common.command.access.CommandPermission.MIGRATION;
public class MigrationBPermissions extends SubCommand<Object> {
private static final Field UCONFIG_FIELD;
@@ -72,7 +73,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
}
public MigrationBPermissions(LocaleManager locale) {
super(CommandSpec.MIGRATION_COMMAND.spec(locale), "bpermissions", MIGRATION, Predicates.alwaysFalse());
super(CommandSpec.MIGRATION_COMMAND.localize(locale), "bpermissions", MIGRATION, Predicates.alwaysFalse());
}
@Override
@@ -85,7 +86,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
WorldManager worldManager = WorldManager.getInstance();
if (worldManager == null) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@@ -111,7 +112,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
Set<String> users = configSection.getKeys(false);
if (users == null) {
log.logErr("Couldn't get a list of users.");
log.logError("Couldn't get a list of users.");
return CommandResult.FAILURE;
}
AtomicInteger userLoadCount = new AtomicInteger(0);
@@ -124,14 +125,14 @@ public class MigrationBPermissions extends SubCommand<Object> {
// Migrate one world at a time.
log.log("Starting world migration.");
SafeIteration.iterate(worldManager.getAllWorlds(), world -> {
Iterators.iterate(worldManager.getAllWorlds(), world -> {
log.log("Migrating world: " + world.getName());
// Migrate all groups
log.log("Starting group migration in world " + world.getName() + ".");
AtomicInteger groupCount = new AtomicInteger(0);
SafeIteration.iterate(world.getAll(CalculableType.GROUP), group -> {
Iterators.iterate(world.getAll(CalculableType.GROUP), group -> {
String groupName = MigrationUtils.standardizeName(group.getName());
if (group.getName().equalsIgnoreCase(world.getDefaultGroup())) {
groupName = NodeFactory.DEFAULT_GROUP_NAME;
@@ -153,9 +154,9 @@ public class MigrationBPermissions extends SubCommand<Object> {
// Migrate all users
log.log("Starting user migration in world " + world.getName() + ".");
AtomicInteger userCount = new AtomicInteger(0);
SafeIteration.iterate(world.getAll(CalculableType.USER), user -> {
Iterators.iterate(world.getAll(CalculableType.USER), user -> {
// There is no mention of UUIDs in the API. I assume that name = uuid. idk?
UUID uuid = BukkitMigrationUtils.lookupUuid(log, user.getName());
UUID uuid = BukkitUuids.lookupUuid(log, user.getName());
if (uuid == null) {
return;
}
@@ -212,7 +213,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
continue;
}
if (meta.getKey().equalsIgnoreCase(NodeFactory.PREFIX_KEY) || meta.getKey().equalsIgnoreCase(NodeFactory.SUFFIX_KEY)) {
if (meta.getKey().equalsIgnoreCase(NodeTypes.PREFIX_KEY) || meta.getKey().equalsIgnoreCase(NodeTypes.SUFFIX_KEY)) {
ChatMetaType type = ChatMetaType.valueOf(meta.getKey().toUpperCase());
holder.setPermission(NodeFactory.buildChatMetaNode(type, c.getPriority(), meta.getValue()).setWorld(world.getName()).build());
continue;
@@ -28,20 +28,23 @@ package me.lucko.luckperms.bukkit.migration;
import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.CommandPermission;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.command.CommandResult;
import me.lucko.luckperms.common.command.abstraction.SubCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.logging.ProgressLogger;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.model.UserIdentifier;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.node.model.NodeTypes;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.utils.Iterators;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.SafeIteration;
import me.lucko.luckperms.common.utils.Uuids;
import org.anjocaido.groupmanager.GlobalGroups;
import org.anjocaido.groupmanager.GroupManager;
@@ -62,7 +65,7 @@ import java.util.stream.Collectors;
public class MigrationGroupManager extends SubCommand<Object> {
public MigrationGroupManager(LocaleManager locale) {
super(CommandSpec.MIGRATION_GROUPMANAGER.spec(locale), "groupmanager", CommandPermission.MIGRATION, Predicates.is(0));
super(CommandSpec.MIGRATION_GROUPMANAGER.localize(locale), "groupmanager", CommandPermission.MIGRATION, Predicates.is(0));
}
@Override
@@ -74,14 +77,14 @@ public class MigrationGroupManager extends SubCommand<Object> {
log.log("Starting.");
if (!args.get(0).equalsIgnoreCase("true") && !args.get(0).equalsIgnoreCase("false")) {
log.logErr("Was expecting true/false, but got " + args.get(0) + " instead.");
log.logError("Was expecting true/false, but got " + args.get(0) + " instead.");
return CommandResult.STATE_ERROR;
}
final boolean migrateAsGlobal = Boolean.parseBoolean(args.get(0));
final Function<String, String> worldMappingFunc = s -> migrateAsGlobal ? null : s;
if (!Bukkit.getPluginManager().isPluginEnabled("GroupManager")) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@@ -93,7 +96,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
GlobalGroups gg = GroupManager.getGlobalGroups();
AtomicInteger globalGroupCount = new AtomicInteger(0);
SafeIteration.iterate(gg.getGroupList(), g -> {
Iterators.iterate(gg.getGroupList(), g -> {
String groupName = MigrationUtils.standardizeName(g.getName());
Group group = plugin.getStorage().createAndLoadGroup(groupName, CreationCause.INTERNAL).join();
@@ -112,7 +115,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
log.log("Migrated " + globalGroupCount.get() + " global groups");
// Collect data
Map<UUID, Set<Node>> users = new HashMap<>();
Map<UserIdentifier, Set<Node>> users = new HashMap<>();
Map<UUID, String> primaryGroups = new HashMap<>();
Map<String, Set<Node>> groups = new HashMap<>();
@@ -120,13 +123,13 @@ public class MigrationGroupManager extends SubCommand<Object> {
// Collect data for all users and groups.
log.log("Collecting user and group data.");
SafeIteration.iterate(worlds, String::toLowerCase, world -> {
Iterators.iterate(worlds, String::toLowerCase, world -> {
log.log("Querying world " + world);
WorldDataHolder wdh = wh.getWorldData(world);
AtomicInteger groupWorldCount = new AtomicInteger(0);
SafeIteration.iterate(wdh.getGroupList(), group -> {
Iterators.iterate(wdh.getGroupList(), group -> {
String groupName = MigrationUtils.standardizeName(group.getName());
groups.putIfAbsent(groupName, new HashSet<>());
@@ -147,7 +150,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
if (key.isEmpty() || value.isEmpty()) continue;
if (key.equals("build")) continue;
if (key.equals(NodeFactory.PREFIX_KEY) || key.equals(NodeFactory.SUFFIX_KEY)) {
if (key.equals(NodeTypes.PREFIX_KEY) || key.equals(NodeTypes.SUFFIX_KEY)) {
ChatMetaType type = ChatMetaType.valueOf(key.toUpperCase());
groups.get(groupName).add(NodeFactory.buildChatMetaNode(type, 50, value).setWorld(worldMappingFunc.apply(world)).build());
} else {
@@ -160,22 +163,29 @@ public class MigrationGroupManager extends SubCommand<Object> {
log.log("Migrated " + groupWorldCount.get() + " groups in world " + world);
AtomicInteger userWorldCount = new AtomicInteger(0);
SafeIteration.iterate(wdh.getUserList(), user -> {
UUID uuid = BukkitMigrationUtils.lookupUuid(log, user.getUUID());
Iterators.iterate(wdh.getUserList(), user -> {
UUID uuid = BukkitUuids.lookupUuid(log, user.getUUID());
if (uuid == null) {
return;
}
users.putIfAbsent(uuid, new HashSet<>());
String lastName = user.getLastName();
if (Uuids.parse(lastName).isPresent()) {
lastName = null;
}
UserIdentifier id = UserIdentifier.of(uuid, lastName);
users.putIfAbsent(id, new HashSet<>());
for (String node : user.getPermissionList()) {
if (node.isEmpty()) continue;
users.get(uuid).add(MigrationUtils.parseNode(node, true).setWorld(worldMappingFunc.apply(world)).build());
users.get(id).add(MigrationUtils.parseNode(node, true).setWorld(worldMappingFunc.apply(world)).build());
}
// Collect sub groups
String finalWorld = worldMappingFunc.apply(world);
users.get(uuid).addAll(user.subGroupListStringCopy().stream()
users.get(id).addAll(user.subGroupListStringCopy().stream()
.filter(n -> !n.isEmpty())
.map(n -> NodeFactory.groupNode(MigrationUtils.standardizeName(n)))
.map(n -> NodeFactory.make(n, true, null, finalWorld))
@@ -192,11 +202,11 @@ public class MigrationGroupManager extends SubCommand<Object> {
if (key.isEmpty() || value.isEmpty()) continue;
if (key.equals("build")) continue;
if (key.equals(NodeFactory.PREFIX_KEY) || key.equals(NodeFactory.SUFFIX_KEY)) {
if (key.equals(NodeTypes.PREFIX_KEY) || key.equals(NodeTypes.SUFFIX_KEY)) {
ChatMetaType type = ChatMetaType.valueOf(key.toUpperCase());
users.get(uuid).add(NodeFactory.buildChatMetaNode(type, 100, value).setWorld(worldMappingFunc.apply(world)).build());
users.get(id).add(NodeFactory.buildChatMetaNode(type, 100, value).setWorld(worldMappingFunc.apply(world)).build());
} else {
users.get(uuid).add(NodeFactory.buildMetaNode(key, value).setWorld(worldMappingFunc.apply(world)).build());
users.get(id).add(NodeFactory.buildMetaNode(key, value).setWorld(worldMappingFunc.apply(world)).build());
}
}
@@ -210,7 +220,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
log.log("Starting group migration.");
AtomicInteger groupCount = new AtomicInteger(0);
SafeIteration.iterate(groups.entrySet(), e -> {
Iterators.iterate(groups.entrySet(), e -> {
Group group = plugin.getStorage().createAndLoadGroup(e.getKey(), CreationCause.INTERNAL).join();
for (Node node : e.getValue()) {
@@ -224,14 +234,14 @@ public class MigrationGroupManager extends SubCommand<Object> {
log.log("Starting user migration.");
AtomicInteger userCount = new AtomicInteger(0);
SafeIteration.iterate(users.entrySet(), e -> {
User user = plugin.getStorage().loadUser(e.getKey(), null).join();
Iterators.iterate(users.entrySet(), e -> {
User user = plugin.getStorage().loadUser(e.getKey().getUuid(), e.getKey().getUsername().orElse(null)).join();
for (Node node : e.getValue()) {
user.setPermission(node);
}
String primaryGroup = primaryGroups.get(e.getKey());
String primaryGroup = primaryGroups.get(e.getKey().getUuid());
if (primaryGroup != null && !primaryGroup.isEmpty()) {
user.setPermission(NodeFactory.buildGroupNode(primaryGroup).build());
user.getPrimaryGroup().setStoredValue(primaryGroup);
@@ -28,21 +28,21 @@ package me.lucko.luckperms.bukkit.migration;
import com.platymuus.bukkit.permissions.PermissionsPlugin;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.CommandPermission;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.command.CommandResult;
import me.lucko.luckperms.common.command.abstraction.SubCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.logging.ProgressLogger;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.utils.Iterators;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.SafeIteration;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
@@ -54,7 +54,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class MigrationPermissionsBukkit extends SubCommand<Object> {
public MigrationPermissionsBukkit(LocaleManager locale) {
super(CommandSpec.MIGRATION_COMMAND.spec(locale), "permissionsbukkit", CommandPermission.MIGRATION, Predicates.alwaysFalse());
super(CommandSpec.MIGRATION_COMMAND.localize(locale), "permissionsbukkit", CommandPermission.MIGRATION, Predicates.alwaysFalse());
}
@Override
@@ -66,7 +66,7 @@ public class MigrationPermissionsBukkit extends SubCommand<Object> {
log.log("Starting.");
if (!Bukkit.getPluginManager().isPluginEnabled("PermissionsBukkit")) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@@ -79,7 +79,7 @@ public class MigrationPermissionsBukkit extends SubCommand<Object> {
ConfigurationSection groupsSection = config.getConfigurationSection("groups");
SafeIteration.iterate(groupsSection.getKeys(false), key -> {
Iterators.iterate(groupsSection.getKeys(false), key -> {
final String groupName = MigrationUtils.standardizeName(key);
Group lpGroup = plugin.getStorage().createAndLoadGroup(groupName, CreationCause.INTERNAL).join();
@@ -99,8 +99,8 @@ public class MigrationPermissionsBukkit extends SubCommand<Object> {
ConfigurationSection usersSection = config.getConfigurationSection("users");
SafeIteration.iterate(usersSection.getKeys(false), key -> {
UUID uuid = BukkitMigrationUtils.lookupUuid(log, key);
Iterators.iterate(usersSection.getKeys(false), key -> {
UUID uuid = BukkitUuids.lookupUuid(log, key);
if (uuid == null) {
return;
}
@@ -28,22 +28,23 @@ package me.lucko.luckperms.bukkit.migration;
import com.google.common.base.Strings;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.CommandPermission;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.command.CommandResult;
import me.lucko.luckperms.common.command.abstraction.SubCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.logging.ProgressLogger;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.node.model.NodeTypes;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.utils.Iterators;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.SafeIteration;
import org.bukkit.Bukkit;
@@ -86,7 +87,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
}
public MigrationPermissionsEx(LocaleManager locale) {
super(CommandSpec.MIGRATION_COMMAND.spec(locale), "permissionsex", CommandPermission.MIGRATION, Predicates.alwaysFalse());
super(CommandSpec.MIGRATION_COMMAND.localize(locale), "permissionsex", CommandPermission.MIGRATION, Predicates.alwaysFalse());
}
@SuppressWarnings("deprecation")
@@ -99,7 +100,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
log.log("Starting.");
if (!Bukkit.getPluginManager().isPluginEnabled("PermissionsEx")) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@@ -117,7 +118,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
log.log("Starting group migration.");
AtomicInteger groupCount = new AtomicInteger(0);
Set<String> ladders = new HashSet<>();
SafeIteration.iterate(manager.getGroupList(), group -> {
Iterators.iterate(manager.getGroupList(), group -> {
int groupWeight = maxWeight - group.getRank();
final String groupName = MigrationUtils.standardizeName(group.getName());
@@ -161,8 +162,8 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
// Increment the max weight from the group migrations. All user meta should override.
int userWeight = maxWeight + 5;
SafeIteration.iterate(manager.getUsers(), user -> {
UUID u = BukkitMigrationUtils.lookupUuid(log, user.getIdentifier());
Iterators.iterate(manager.getUsers(), user -> {
UUID u = BukkitUuids.lookupUuid(log, user.getIdentifier());
if (u == null) {
return;
}
@@ -288,9 +289,9 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
}
String key = opt.getKey().toLowerCase();
boolean ignore = key.equals(NodeFactory.PREFIX_KEY) ||
key.equals(NodeFactory.SUFFIX_KEY) ||
key.equals(NodeFactory.WEIGHT_KEY) ||
boolean ignore = key.equals(NodeTypes.PREFIX_KEY) ||
key.equals(NodeTypes.SUFFIX_KEY) ||
key.equals(NodeTypes.WEIGHT_KEY) ||
key.equals("rank") ||
key.equals("rank-ladder") ||
key.equals("name") ||
@@ -35,21 +35,21 @@ import com.zaxxer.hikari.HikariDataSource;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.command.CommandResult;
import me.lucko.luckperms.common.command.abstraction.SubCommand;
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.logging.ProgressLogger;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.storage.StorageType;
import me.lucko.luckperms.common.utils.Iterators;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.SafeIteration;
import org.bukkit.Bukkit;
@@ -68,12 +68,12 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import static me.lucko.luckperms.common.commands.CommandPermission.MIGRATION;
import static me.lucko.luckperms.common.command.access.CommandPermission.MIGRATION;
// Only supports the latest versions of the PP API. (it seems to change randomly almost every release)
public class MigrationPowerfulPerms extends SubCommand<Object> {
public MigrationPowerfulPerms(LocaleManager locale) {
super(CommandSpec.MIGRATION_POWERFULPERMS.spec(locale), "powerfulperms", MIGRATION, Predicates.not(5));
super(CommandSpec.MIGRATION_POWERFULPERMS.localize(locale), "powerfulperms", MIGRATION, Predicates.not(5));
}
@Override
@@ -85,7 +85,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
log.log("Starting.");
if (!Bukkit.getPluginManager().isPluginEnabled("PowerfulPerms")) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@@ -143,7 +143,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
}
if (uuids.isEmpty()) {
log.logErr("Unable to find any UUIDs to migrate.");
log.logError("Unable to find any UUIDs to migrate.");
return CommandResult.FAILURE;
}
@@ -159,7 +159,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
// Groups first.
log.log("Starting group migration.");
AtomicInteger groupCount = new AtomicInteger(0);
SafeIteration.iterate(groups, g -> {
Iterators.iterate(groups, g -> {
maxWeight.set(Math.max(maxWeight.get(), g.getRank()));
String groupName = MigrationUtils.standardizeName(g.getName());
@@ -219,7 +219,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
maxWeight.addAndGet(5);
// Migrate all users and their groups
SafeIteration.iterate(uuids, uuid -> {
Iterators.iterate(uuids, uuid -> {
// Create a LuckPerms user for the UUID
User user = plugin.getStorage().loadUser(uuid, null).join();
@@ -28,22 +28,23 @@ package me.lucko.luckperms.bukkit.migration;
import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.CommandPermission;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.command.CommandResult;
import me.lucko.luckperms.common.command.abstraction.SubCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.logging.ProgressLogger;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.node.model.NodeTypes;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.utils.Iterators;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.SafeIteration;
import org.bukkit.Bukkit;
import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
@@ -64,7 +65,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class MigrationZPermissions extends SubCommand<Object> {
public MigrationZPermissions(LocaleManager locale) {
super(CommandSpec.MIGRATION_COMMAND.spec(locale), "zpermissions", CommandPermission.MIGRATION, Predicates.alwaysFalse());
super(CommandSpec.MIGRATION_COMMAND.localize(locale), "zpermissions", CommandPermission.MIGRATION, Predicates.alwaysFalse());
}
@Override
@@ -76,12 +77,12 @@ public class MigrationZPermissions extends SubCommand<Object> {
log.log("Starting.");
if (!Bukkit.getPluginManager().isPluginEnabled("zPermissions")) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
if (!Bukkit.getServicesManager().isProvidedFor(ZPermissionsService.class)) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@@ -104,7 +105,7 @@ public class MigrationZPermissions extends SubCommand<Object> {
AtomicInteger groupCount = new AtomicInteger(0);
AtomicInteger maxWeight = new AtomicInteger(0);
SafeIteration.iterate(internalService.getEntities(true), entity -> {
Iterators.iterate(internalService.getEntities(true), entity -> {
String groupName = MigrationUtils.standardizeName(entity.getDisplayName());
Group group = plugin.getStorage().createAndLoadGroup(groupName, CreationCause.INTERNAL).join();
@@ -116,7 +117,7 @@ public class MigrationZPermissions extends SubCommand<Object> {
// store user data for later
Set<Membership> members = entity.getMemberships();
for (Membership membership : members) {
UUID uuid = BukkitMigrationUtils.lookupUuid(log, membership.getMember());
UUID uuid = BukkitUuids.lookupUuid(log, membership.getMember());
if (uuid == null) {
continue;
}
@@ -138,7 +139,7 @@ public class MigrationZPermissions extends SubCommand<Object> {
// Migrate all tracks
log.log("Starting track migration.");
AtomicInteger trackCount = new AtomicInteger(0);
SafeIteration.iterate(service.getAllTracks(), t -> {
Iterators.iterate(service.getAllTracks(), t -> {
String trackName = MigrationUtils.standardizeName(t);
Track track = plugin.getStorage().createAndLoadTrack(trackName, CreationCause.INTERNAL).join();
track.setGroups(service.getTrackGroups(t));
@@ -156,7 +157,7 @@ public class MigrationZPermissions extends SubCommand<Object> {
Set<UUID> usersToMigrate = new HashSet<>(userParents.keySet());
usersToMigrate.addAll(service.getAllPlayersUUID());
SafeIteration.iterate(usersToMigrate, u -> {
Iterators.iterate(usersToMigrate, u -> {
PermissionEntity entity = internalService.getEntity(null, u, false);
String username = null;
@@ -211,13 +212,18 @@ public class MigrationZPermissions extends SubCommand<Object> {
for (EntityMetadata metadata : entity.getMetadata()) {
String key = metadata.getName().toLowerCase();
if (key.isEmpty() || metadata.getStringValue().isEmpty()) continue;
Object value = metadata.getValue();
if (key.equals(NodeFactory.PREFIX_KEY) || key.equals(NodeFactory.SUFFIX_KEY)) {
if (key.isEmpty() || value == null) continue;
String valueString = value.toString();
if (valueString.isEmpty()) continue;
if (key.equals(NodeTypes.PREFIX_KEY) || key.equals(NodeTypes.SUFFIX_KEY)) {
ChatMetaType type = ChatMetaType.valueOf(key.toUpperCase());
holder.setPermission(NodeFactory.buildChatMetaNode(type, weight, metadata.getStringValue()).build());
holder.setPermission(NodeFactory.buildChatMetaNode(type, weight, valueString).build());
} else {
holder.setPermission(NodeFactory.buildMetaNode(key, metadata.getStringValue()).build());
holder.setPermission(NodeFactory.buildMetaNode(key, valueString).build());
}
}
}
@@ -219,7 +219,7 @@ public class LPPermissible extends PermissibleBase {
}
LPPermissionAttachment ret = addAttachment(plugin);
if (getPlugin().getServer().getScheduler().scheduleSyncDelayedTask(plugin, ret::remove, ticks) == -1) {
if (getPlugin().getBootstrap().getServer().getScheduler().scheduleSyncDelayedTask(plugin, ret::remove, ticks) == -1) {
ret.remove();
throw new RuntimeException("Could not add PermissionAttachment to " + this.player + " for plugin " + plugin.getDescription().getFullName() + ": Scheduler returned -1");
}
@@ -31,8 +31,8 @@ import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.bukkit.model.dummy.DummyPlugin;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.ImmutableTransientNode;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.node.model.ImmutableTransientNode;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionRemovedExecutor;
@@ -178,9 +178,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
// set the transient node
User user = this.permissible.getUser();
if (user.setTransientPermission(transientNode).asBoolean()) {
user.reloadCachedData();
}
user.setTransientPermission(transientNode);
}
private void unsetPermissionInternal(String name) {
@@ -190,17 +188,13 @@ public class LPPermissionAttachment extends PermissionAttachment {
// remove transient permissions from the holder which were added by this attachment & equal the permission
User user = this.permissible.getUser();
if (user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name))) {
user.reloadCachedData();
}
user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name));
}
private void clearInternal() {
// remove all transient permissions added by this attachment
User user = this.permissible.getUser();
if (user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this)) {
user.reloadCachedData();
}
user.removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this);
}
@Override
@@ -276,7 +270,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
@Override
public Plugin getPlugin() {
return this.owner != null ? this.owner : this.permissible.getPlugin();
return this.owner != null ? this.owner : this.permissible.getPlugin().getBootstrap();
}
@Override
@@ -72,7 +72,7 @@ public class MonitoredPermissibleBase extends PermissibleBase {
private void logCheck(CheckOrigin origin, String permission, boolean result) {
this.plugin.getVerboseHandler().offerCheckData(origin, this.name, ContextSet.empty(), permission, Tristate.fromBoolean(result));
this.plugin.getPermissionVault().offer(permission);
this.plugin.getPermissionRegistry().offer(permission);
}
PermissibleBase getDelegate() {
@@ -81,7 +81,7 @@ public class PermissibleMonitoringInjector implements Runnable {
}
private void injectConsole() throws Exception {
ConsoleCommandSender consoleSender = this.plugin.getServer().getConsoleSender();
ConsoleCommandSender consoleSender = this.plugin.getBootstrap().getServer().getConsoleSender();
// get the ServerCommandSender class
Class<?> serverCommandSenderClass = ReflectionUtil.obcClass("command.ServerCommandSender");
@@ -69,18 +69,18 @@ public class InjectorDefaultsMap implements Runnable {
this.plugin.setDefaultPermissionMap(ret);
}
} catch (Exception e) {
this.plugin.getLog().severe("Exception occurred whilst injecting LuckPerms Default Permission map.");
this.plugin.getLogger().severe("Exception occurred whilst injecting LuckPerms Default Permission map.");
e.printStackTrace();
}
}
private LPDefaultsMap inject() throws Exception {
Objects.requireNonNull(DEFAULT_PERMISSIONS_FIELD, "DEFAULT_PERMISSIONS_FIELD");
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
PluginManager pluginManager = this.plugin.getBootstrap().getServer().getPluginManager();
if (!(pluginManager instanceof SimplePluginManager)) {
this.plugin.getLog().severe("PluginManager instance is not a 'SimplePluginManager', instead: " + pluginManager.getClass());
this.plugin.getLog().severe("Unable to inject LuckPerms Default Permission map.");
this.plugin.getLogger().severe("PluginManager instance is not a 'SimplePluginManager', instead: " + pluginManager.getClass());
this.plugin.getLogger().severe("Unable to inject LuckPerms Default Permission map.");
return null;
}
@@ -68,18 +68,18 @@ public class InjectorPermissionMap implements Runnable {
this.plugin.setPermissionMap(ret);
}
} catch (Exception e) {
this.plugin.getLog().severe("Exception occurred whilst injecting LuckPerms Permission map.");
this.plugin.getLogger().severe("Exception occurred whilst injecting LuckPerms Permission map.");
e.printStackTrace();
}
}
private LPPermissionMap inject() throws Exception {
Objects.requireNonNull(PERMISSIONS_FIELD, "PERMISSIONS_FIELD");
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
PluginManager pluginManager = this.plugin.getBootstrap().getServer().getPluginManager();
if (!(pluginManager instanceof SimplePluginManager)) {
this.plugin.getLog().severe("PluginManager instance is not a 'SimplePluginManager', instead: " + pluginManager.getClass());
this.plugin.getLog().severe("Unable to inject LuckPerms Permission map.");
this.plugin.getLogger().severe("PluginManager instance is not a 'SimplePluginManager', instead: " + pluginManager.getClass());
this.plugin.getLogger().severe("Unable to inject LuckPerms Permission map.");
return null;
}
@@ -67,18 +67,18 @@ public class InjectorSubscriptionMap implements Runnable {
this.plugin.setSubscriptionMap(ret);
}
} catch (Exception e) {
this.plugin.getLog().severe("Exception occurred whilst injecting LuckPerms Permission Subscription map.");
this.plugin.getLogger().severe("Exception occurred whilst injecting LuckPerms Permission Subscription map.");
e.printStackTrace();
}
}
private LPSubscriptionMap inject() throws Exception {
Objects.requireNonNull(PERM_SUBS_FIELD, "PERM_SUBS_FIELD");
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
PluginManager pluginManager = this.plugin.getBootstrap().getServer().getPluginManager();
if (!(pluginManager instanceof SimplePluginManager)) {
this.plugin.getLog().severe("PluginManager instance is not a 'SimplePluginManager', instead: " + pluginManager.getClass());
this.plugin.getLog().severe("Unable to inject LuckPerms Permission Subscription map.");
this.plugin.getLogger().severe("PluginManager instance is not a 'SimplePluginManager', instead: " + pluginManager.getClass());
this.plugin.getLogger().severe("Unable to inject LuckPerms Permission Subscription map.");
return null;
}
@@ -32,7 +32,7 @@ import com.google.common.collect.ForwardingMap;
import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.treeview.PermissionVault;
import me.lucko.luckperms.common.treeview.PermissionRegistry;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.PluginManager;
@@ -40,17 +40,19 @@ import org.bukkit.plugin.PluginManager;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A replacement map for the 'permissions' instance in Bukkit's SimplePluginManager.
*
* This instance allows LuckPerms to intercept calls to
* {@link PluginManager#addPermission(Permission)} and record permissions in the
* {@link PermissionVault}.
* {@link PermissionRegistry}.
*
* It also allows us to pre-determine child permission relationships.
*
@@ -94,7 +96,10 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
@Override
public Permission put(@Nonnull String key, @Nonnull Permission value) {
this.plugin.getPermissionVault().offer(key);
Objects.requireNonNull(key, "key");
Objects.requireNonNull(value, "value");
this.plugin.getPermissionRegistry().offer(key);
Permission ret = super.put(key, value);
update();
return ret;
@@ -102,19 +107,55 @@ public final class LPPermissionMap extends ForwardingMap<String, Permission> {
@Override
public void putAll(@Nonnull Map<? extends String, ? extends Permission> m) {
this.plugin.getPermissionVault().offerAll(m.keySet());
this.plugin.getPermissionRegistry().offerAll(m.keySet());
super.putAll(m);
update();
}
@Override
public Permission putIfAbsent(String key, Permission value) {
this.plugin.getPermissionVault().offer(key);
Objects.requireNonNull(key, "key");
Objects.requireNonNull(value, "value");
this.plugin.getPermissionRegistry().offer(key);
Permission ret = super.putIfAbsent(key, value);
update();
return ret;
}
// null-safe - the plugin manager uses hashmap
@Override
public Permission remove(@Nullable Object object) {
if (object == null) {
return null;
}
return super.remove(object);
}
@Override
public boolean remove(Object key, Object value) {
return key != null && value != null && super.remove(key, value);
}
@Override
public boolean containsKey(@Nullable Object key) {
return key != null && super.containsKey(key);
}
@Override
public boolean containsValue(@Nullable Object value) {
return value != null && super.containsValue(value);
}
@Override
public Permission get(@Nullable Object key) {
if (key == null) {
return null;
}
return super.get(key);
}
private final class ChildPermissionResolver implements CacheLoader<String, Map<String, Boolean>> {
private final boolean value;
@@ -207,7 +207,7 @@ public final class LPSubscriptionMap extends HashMap<String, Map<Permissible, Bo
@Override
public Set<Permissible> keySet() {
// gather players (LPPermissibles)
Set<Permissible> players = LPSubscriptionMap.this.plugin.getServer().getOnlinePlayers().stream()
Set<Permissible> players = LPSubscriptionMap.this.plugin.getBootstrap().getServer().getOnlinePlayers().stream()
.filter(player -> player.isPermissionSet(this.permission))
.collect(Collectors.toSet());
@@ -33,6 +33,7 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Function;
@@ -73,18 +74,18 @@ public abstract class AbstractVaultChat extends Chat {
}
// methods subclasses are expected to implement
public abstract String getPlayerPrefix(String world, UUID uuid);
public abstract String getPlayerSuffix(String world, UUID uuid);
public abstract void setPlayerPrefix(String world, UUID uuid, String prefix);
public abstract void setPlayerSuffix(String world, UUID uuid, String suffix);
public abstract String getPlayerInfo(String world, UUID uuid, String key);
public abstract void setPlayerInfo(String world, UUID uuid, String key, Object value);
public abstract String getGroupsPrefix(String world, String name); // note "groups" not "group"
public abstract String getGroupsSuffix(String world, String name); // note "groups" not "group"
public abstract void setGroupsPrefix(String world, String name, String prefix); // note "groups" not "group"
public abstract void setGroupsSuffix(String world, String name, String suffix); // note "groups" not "group"
public abstract String getGroupInfo(String world, String name, String key);
public abstract void setGroupInfo(String world, String name, String key, Object value);
public abstract String getUserChatPrefix(String world, UUID uuid);
public abstract String getUserChatSuffix(String world, UUID uuid);
public abstract void setUserChatPrefix(String world, UUID uuid, String prefix);
public abstract void setUserChatSuffix(String world, UUID uuid, String suffix);
public abstract String getUserMeta(String world, UUID uuid, String key);
public abstract void setUserMeta(String world, UUID uuid, String key, Object value);
public abstract String getGroupChatPrefix(String world, String name);
public abstract String getGroupChatSuffix(String world, String name);
public abstract void setGroupChatPrefix(String world, String name, String prefix);
public abstract void setGroupChatSuffix(String world, String name, String suffix);
public abstract String getGroupMeta(String world, String name, String key);
public abstract void setGroupMeta(String world, String name, String key, Object value);
// utility methods for parsing metadata values from strings
@@ -165,362 +166,482 @@ public abstract class AbstractVaultChat extends Chat {
@Override
public String getPlayerPrefix(String world, String player) {
return getPlayerPrefix(world(world), player(player));
Objects.requireNonNull(player, "player");
return getUserChatPrefix(world(world), player(player));
}
@Override
public String getPlayerPrefix(String world, OfflinePlayer player) {
return getPlayerPrefix(world(world), player(player));
Objects.requireNonNull(player, "player");
return getUserChatPrefix(world(world), player(player));
}
@Override
public String getPlayerPrefix(World world, String player) {
return getPlayerPrefix(world(world), player(player));
Objects.requireNonNull(player, "player");
return getUserChatPrefix(world(world), player(player));
}
@Override
public String getPlayerPrefix(Player player) {
return getPlayerPrefix(world(player), player(player));
Objects.requireNonNull(player, "player");
return getUserChatPrefix(world(player), player(player));
}
@Override
public void setPlayerPrefix(String world, String player, String prefix) {
setPlayerPrefix(world(world), player(player), prefix);
Objects.requireNonNull(player, "player");
setUserChatPrefix(world(world), player(player), prefix);
}
@Override
public void setPlayerPrefix(String world, OfflinePlayer player, String prefix) {
setPlayerPrefix(world(world), player(player), prefix);
Objects.requireNonNull(player, "player");
setUserChatPrefix(world(world), player(player), prefix);
}
@Override
public void setPlayerPrefix(World world, String player, String prefix) {
setPlayerPrefix(world(world), player(player), prefix);
Objects.requireNonNull(player, "player");
setUserChatPrefix(world(world), player(player), prefix);
}
@Override
public void setPlayerPrefix(Player player, String prefix) {
setPlayerPrefix(world(player), player(player), prefix);
Objects.requireNonNull(player, "player");
setUserChatPrefix(world(player), player(player), prefix);
}
@Override
public String getPlayerSuffix(String world, String player) {
return getPlayerSuffix(world(world), player(player));
Objects.requireNonNull(player, "player");
return getUserChatSuffix(world(world), player(player));
}
@Override
public String getPlayerSuffix(String world, OfflinePlayer player) {
return getPlayerSuffix(world(world), player(player));
Objects.requireNonNull(player, "player");
return getUserChatSuffix(world(world), player(player));
}
@Override
public String getPlayerSuffix(World world, String player) {
return getPlayerSuffix(world(world), player(player));
Objects.requireNonNull(player, "player");
return getUserChatSuffix(world(world), player(player));
}
@Override
public String getPlayerSuffix(Player player) {
return getPlayerSuffix(world(player), player(player));
Objects.requireNonNull(player, "player");
return getUserChatSuffix(world(player), player(player));
}
@Override
public void setPlayerSuffix(String world, String player, String suffix) {
setPlayerSuffix(world(world), player(player), suffix);
Objects.requireNonNull(player, "player");
setUserChatSuffix(world(world), player(player), suffix);
}
@Override
public void setPlayerSuffix(String world, OfflinePlayer player, String suffix) {
setPlayerSuffix(world(world), player(player), suffix);
Objects.requireNonNull(player, "player");
setUserChatSuffix(world(world), player(player), suffix);
}
@Override
public void setPlayerSuffix(World world, String player, String suffix) {
setPlayerSuffix(world(world), player(player), suffix);
Objects.requireNonNull(player, "player");
setUserChatSuffix(world(world), player(player), suffix);
}
@Override
public void setPlayerSuffix(Player player, String suffix) {
setPlayerSuffix(world(player), player(player), suffix);
Objects.requireNonNull(player, "player");
setUserChatSuffix(world(player), player(player), suffix);
}
@Override
public String getGroupPrefix(String world, String group) {
return getGroupsPrefix(world(world), group);
Objects.requireNonNull(group, "group");
return getGroupChatPrefix(world(world), group);
}
@Override
public String getGroupPrefix(World world, String group) {
return getGroupsPrefix(world(world), group);
Objects.requireNonNull(group, "group");
return getGroupChatPrefix(world(world), group);
}
@Override
public void setGroupPrefix(String world, String group, String prefix) {
setGroupsPrefix(world(world), group, prefix);
Objects.requireNonNull(group, "group");
setGroupChatPrefix(world(world), group, prefix);
}
@Override
public void setGroupPrefix(World world, String group, String prefix) {
setGroupsPrefix(world(world), group, prefix);
Objects.requireNonNull(group, "group");
setGroupChatPrefix(world(world), group, prefix);
}
@Override
public String getGroupSuffix(String world, String group) {
return getGroupsSuffix(world(world), group);
Objects.requireNonNull(group, "group");
return getGroupChatSuffix(world(world), group);
}
@Override
public String getGroupSuffix(World world, String group) {
return getGroupsSuffix(world(world), group);
Objects.requireNonNull(group, "group");
return getGroupChatSuffix(world(world), group);
}
@Override
public void setGroupSuffix(String world, String group, String suffix) {
setGroupsSuffix(world(world), group, suffix);
Objects.requireNonNull(group, "group");
setGroupChatSuffix(world(world), group, suffix);
}
@Override
public void setGroupSuffix(World world, String group, String suffix) {
setGroupsSuffix(world(world), group, suffix);
Objects.requireNonNull(group, "group");
setGroupChatSuffix(world(world), group, suffix);
}
@Override
public int getPlayerInfoInteger(String world, OfflinePlayer player, String node, int defaultValue) {
return intConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return intConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public int getPlayerInfoInteger(String world, String player, String node, int defaultValue) {
return intConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return intConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public int getPlayerInfoInteger(World world, String player, String node, int defaultValue) {
return intConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return intConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public int getPlayerInfoInteger(Player player, String node, int defaultValue) {
return intConvert(getPlayerInfo(world(player), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return intConvert(getUserMeta(world(player), player(player), node), defaultValue);
}
@Override
public void setPlayerInfoInteger(String world, OfflinePlayer player, String node, int value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoInteger(String world, String player, String node, int value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoInteger(World world, String player, String node, int value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoInteger(Player player, String node, int value) {
setPlayerInfo(world(player), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(player), player(player), node, value);
}
@Override
public int getGroupInfoInteger(String world, String group, String node, int defaultValue) {
return intConvert(getGroupInfo(world(world), group, node), defaultValue);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
return intConvert(getGroupMeta(world(world), group, node), defaultValue);
}
@Override
public int getGroupInfoInteger(World world, String group, String node, int defaultValue) {
return intConvert(getGroupInfo(world(world), group, node), defaultValue);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
return intConvert(getGroupMeta(world(world), group, node), defaultValue);
}
@Override
public void setGroupInfoInteger(String world, String group, String node, int value) {
setGroupInfo(world(world), group, node, value);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
setGroupMeta(world(world), group, node, value);
}
@Override
public void setGroupInfoInteger(World world, String group, String node, int value) {
setGroupInfo(world(world), group, node, value);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
setGroupMeta(world(world), group, node, value);
}
@Override
public double getPlayerInfoDouble(String world, OfflinePlayer player, String node, double defaultValue) {
return doubleConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return doubleConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public double getPlayerInfoDouble(String world, String player, String node, double defaultValue) {
return doubleConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return doubleConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public double getPlayerInfoDouble(World world, String player, String node, double defaultValue) {
return doubleConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return doubleConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public double getPlayerInfoDouble(Player player, String node, double defaultValue) {
return doubleConvert(getPlayerInfo(world(player), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return doubleConvert(getUserMeta(world(player), player(player), node), defaultValue);
}
@Override
public void setPlayerInfoDouble(String world, OfflinePlayer player, String node, double value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoDouble(String world, String player, String node, double value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoDouble(World world, String player, String node, double value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoDouble(Player player, String node, double value) {
setPlayerInfo(world(player), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(player), player(player), node, value);
}
@Override
public double getGroupInfoDouble(String world, String group, String node, double defaultValue) {
return doubleConvert(getGroupInfo(world(world), group, node), defaultValue);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
return doubleConvert(getGroupMeta(world(world), group, node), defaultValue);
}
@Override
public double getGroupInfoDouble(World world, String group, String node, double defaultValue) {
return doubleConvert(getGroupInfo(world(world), group, node), defaultValue);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
return doubleConvert(getGroupMeta(world(world), group, node), defaultValue);
}
@Override
public void setGroupInfoDouble(String world, String group, String node, double value) {
setGroupInfo(world(world), group, node, value);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
setGroupMeta(world(world), group, node, value);
}
@Override
public void setGroupInfoDouble(World world, String group, String node, double value) {
setGroupInfo(world(world), group, node, value);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
setGroupMeta(world(world), group, node, value);
}
@Override
public boolean getPlayerInfoBoolean(String world, OfflinePlayer player, String node, boolean defaultValue) {
return booleanConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return booleanConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public boolean getPlayerInfoBoolean(String world, String player, String node, boolean defaultValue) {
return booleanConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return booleanConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public boolean getPlayerInfoBoolean(World world, String player, String node, boolean defaultValue) {
return booleanConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return booleanConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public boolean getPlayerInfoBoolean(Player player, String node, boolean defaultValue) {
return booleanConvert(getPlayerInfo(world(player), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return booleanConvert(getUserMeta(world(player), player(player), node), defaultValue);
}
@Override
public void setPlayerInfoBoolean(String world, OfflinePlayer player, String node, boolean value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoBoolean(String world, String player, String node, boolean value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoBoolean(World world, String player, String node, boolean value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoBoolean(Player player, String node, boolean value) {
setPlayerInfo(world(player), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(player), player(player), node, value);
}
@Override
public boolean getGroupInfoBoolean(String world, String group, String node, boolean defaultValue) {
return booleanConvert(getGroupInfo(world(world), group, node), defaultValue);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
return booleanConvert(getGroupMeta(world(world), group, node), defaultValue);
}
@Override
public boolean getGroupInfoBoolean(World world, String group, String node, boolean defaultValue) {
return booleanConvert(getGroupInfo(world(world), group, node), defaultValue);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
return booleanConvert(getGroupMeta(world(world), group, node), defaultValue);
}
@Override
public void setGroupInfoBoolean(String world, String group, String node, boolean value) {
setGroupInfo(world(world), group, node, value);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
setGroupMeta(world(world), group, node, value);
}
@Override
public void setGroupInfoBoolean(World world, String group, String node, boolean value) {
setGroupInfo(world(world), group, node, value);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
setGroupMeta(world(world), group, node, value);
}
@Override
public String getPlayerInfoString(String world, OfflinePlayer player, String node, String defaultValue) {
return strConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return strConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public String getPlayerInfoString(String world, String player, String node, String defaultValue) {
return strConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return strConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public String getPlayerInfoString(World world, String player, String node, String defaultValue) {
return strConvert(getPlayerInfo(world(world), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return strConvert(getUserMeta(world(world), player(player), node), defaultValue);
}
@Override
public String getPlayerInfoString(Player player, String node, String defaultValue) {
return strConvert(getPlayerInfo(world(player), player(player), node), defaultValue);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
return strConvert(getUserMeta(world(player), player(player), node), defaultValue);
}
@Override
public void setPlayerInfoString(String world, OfflinePlayer player, String node, String value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoString(String world, String player, String node, String value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoString(World world, String player, String node, String value) {
setPlayerInfo(world(world), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(world), player(player), node, value);
}
@Override
public void setPlayerInfoString(Player player, String node, String value) {
setPlayerInfo(world(player), player(player), node, value);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(node, "node");
setUserMeta(world(player), player(player), node, value);
}
@Override
public String getGroupInfoString(String world, String group, String node, String defaultValue) {
return strConvert(getGroupInfo(world(world), group, node), defaultValue);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
return strConvert(getGroupMeta(world(world), group, node), defaultValue);
}
@Override
public String getGroupInfoString(World world, String group, String node, String defaultValue) {
return strConvert(getGroupInfo(world(world), group, node), defaultValue);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
return strConvert(getGroupMeta(world(world), group, node), defaultValue);
}
@Override
public void setGroupInfoString(String world, String group, String node, String value) {
setGroupInfo(world(world), group, node, value);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
setGroupMeta(world(world), group, node, value);
}
@Override
public void setGroupInfoString(World world, String group, String node, String value) {
setGroupInfo(world(world), group, node, value);
Objects.requireNonNull(group, "group");
Objects.requireNonNull(node, "node");
setGroupMeta(world(world), group, node, value);
}
@Override
@@ -33,6 +33,7 @@ import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Function;
@@ -81,14 +82,14 @@ public abstract class AbstractVaultPermission extends Permission {
}
// methods subclasses are expected to implement
public abstract boolean hasPermission(String world, UUID uuid, String permission);
public abstract boolean playerAddPermission(String world, UUID uuid, String permission);
public abstract boolean playerRemovePermission(String world, UUID uuid, String permission);
public abstract boolean playerInGroup(String world, UUID uuid, String group);
public abstract boolean playerAddGroup(String world, UUID uuid, String group);
public abstract boolean playerRemoveGroup(String world, UUID uuid, String group);
public abstract String[] playerGetGroups(String world, UUID uuid);
public abstract String playerPrimaryGroup(String world, UUID uuid);
public abstract boolean userHasPermission(String world, UUID uuid, String permission);
public abstract boolean userAddPermission(String world, UUID uuid, String permission);
public abstract boolean userRemovePermission(String world, UUID uuid, String permission);
public abstract boolean userInGroup(String world, UUID uuid, String group);
public abstract boolean userAddGroup(String world, UUID uuid, String group);
public abstract boolean userRemoveGroup(String world, UUID uuid, String group);
public abstract String[] userGetGroups(String world, UUID uuid);
public abstract String userGetPrimaryGroup(String world, UUID uuid);
public abstract boolean groupHasPermission(String world, String name, String permission);
public abstract boolean groupAddPermission(String world, String name, String permission);
public abstract boolean groupRemovePermission(String world, String name, String permission);
@@ -129,207 +130,280 @@ public abstract class AbstractVaultPermission extends Permission {
@Override
public boolean has(String world, String player, String permission) {
return hasPermission(world(world), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userHasPermission(world(world), player(player), permission);
}
@Override
public boolean has(World world, String player, String permission) {
return hasPermission(world(world), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userHasPermission(world(world), player(player), permission);
}
@Override
public boolean has(Player player, String permission) {
return hasPermission(world(player), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userHasPermission(world(player), player(player), permission);
}
@Override
public boolean playerHas(String world, String player, String permission) {
return hasPermission(world(world), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userHasPermission(world(world), player(player), permission);
}
@Override
public boolean playerHas(World world, String player, String permission) {
return hasPermission(world(world), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userHasPermission(world(world), player(player), permission);
}
@Override
public boolean playerHas(String world, OfflinePlayer player, String permission) {
return hasPermission(world(world), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userHasPermission(world(world), player(player), permission);
}
@Override
public boolean playerHas(Player player, String permission) {
return hasPermission(world(player), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userHasPermission(world(player), player(player), permission);
}
@Override
public boolean playerAdd(String world, String player, String permission) {
return playerAddPermission(world(world), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userAddPermission(world(world), player(player), permission);
}
@Override
public boolean playerAdd(World world, String player, String permission) {
return playerAddPermission(world(world), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userAddPermission(world(world), player(player), permission);
}
@Override
public boolean playerAdd(String world, OfflinePlayer player, String permission) {
return playerAddPermission(world(world), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userAddPermission(world(world), player(player), permission);
}
@Override
public boolean playerAdd(Player player, String permission) {
return playerAddPermission(world(player), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userAddPermission(world(player), player(player), permission);
}
@Override
public boolean playerRemove(String world, String player, String permission) {
return playerRemovePermission(world(world), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userRemovePermission(world(world), player(player), permission);
}
@Override
public boolean playerRemove(String world, OfflinePlayer player, String permission) {
return playerRemovePermission(world(world), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userRemovePermission(world(world), player(player), permission);
}
@Override
public boolean playerRemove(World world, String player, String permission) {
return playerRemovePermission(world(world), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userRemovePermission(world(world), player(player), permission);
}
@Override
public boolean playerRemove(Player player, String permission) {
return playerRemovePermission(world(player), player(player), permission);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(permission, "permission");
return userRemovePermission(world(player), player(player), permission);
}
@Override
public boolean groupHas(String world, String group, String permission) {
Objects.requireNonNull(group, "group");
Objects.requireNonNull(permission, "permission");
return groupHasPermission(world(world), group, permission);
}
@Override
public boolean groupHas(World world, String group, String permission) {
Objects.requireNonNull(group, "group");
Objects.requireNonNull(permission, "permission");
return groupHasPermission(world(world), group, permission);
}
@Override
public boolean groupAdd(String world, String group, String permission) {
Objects.requireNonNull(group, "group");
Objects.requireNonNull(permission, "permission");
return groupAddPermission(world(world), group, permission);
}
@Override
public boolean groupAdd(World world, String group, String permission) {
Objects.requireNonNull(group, "group");
Objects.requireNonNull(permission, "permission");
return groupAddPermission(world(world), group, permission);
}
@Override
public boolean groupRemove(String world, String group, String permission) {
Objects.requireNonNull(group, "group");
Objects.requireNonNull(permission, "permission");
return groupRemovePermission(world(world), group, permission);
}
@Override
public boolean groupRemove(World world, String group, String permission) {
Objects.requireNonNull(group, "group");
Objects.requireNonNull(permission, "permission");
return groupRemovePermission(world(world), group, permission);
}
@Override
public boolean playerInGroup(String world, String player, String group) {
return playerInGroup(world(world), player(player), group);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(group, "group");
return userInGroup(world(world), player(player), group);
}
@Override
public boolean playerInGroup(World world, String player, String group) {
return playerInGroup(world(world), player(player), group);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(group, "group");
return userInGroup(world(world), player(player), group);
}
@Override
public boolean playerInGroup(String world, OfflinePlayer player, String group) {
return playerInGroup(world(world), player(player), group);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(group, "group");
return userInGroup(world(world), player(player), group);
}
@Override
public boolean playerInGroup(Player player, String group) {
return playerInGroup(world(player), player(player), group);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(group, "group");
return userInGroup(world(player), player(player), group);
}
@Override
public boolean playerAddGroup(String world, String player, String group) {
return playerAddGroup(world(world), player(player), group);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(group, "group");
return userAddGroup(world(world), player(player), group);
}
@Override
public boolean playerAddGroup(World world, String player, String group) {
return playerAddGroup(world(world), player(player), group);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(group, "group");
return userAddGroup(world(world), player(player), group);
}
@Override
public boolean playerAddGroup(String world, OfflinePlayer player, String group) {
return playerAddGroup(world(world), player(player), group);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(group, "group");
return userAddGroup(world(world), player(player), group);
}
@Override
public boolean playerAddGroup(Player player, String group) {
return playerAddGroup(world(player), player(player), group);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(group, "group");
return userAddGroup(world(player), player(player), group);
}
@Override
public boolean playerRemoveGroup(String world, String player, String group) {
return playerRemoveGroup(world(world), player(player), group);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(group, "group");
return userRemoveGroup(world(world), player(player), group);
}
@Override
public boolean playerRemoveGroup(World world, String player, String group) {
return playerRemoveGroup(world(world), player(player), group);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(group, "group");
return userRemoveGroup(world(world), player(player), group);
}
@Override
public boolean playerRemoveGroup(String world, OfflinePlayer player, String group) {
return playerRemoveGroup(world(world), player(player), group);
Objects.requireNonNull(player, "player");
Objects.requireNonNull(group, "group");
return userRemoveGroup(world(world), player(player), group);
}
@Override
public boolean playerRemoveGroup(Player player, String group) {
return playerRemoveGroup(world(player), player(player), group);
Objects.requireNonNull(player, "player");
return userRemoveGroup(world(player), player(player), group);
}
@Override
public String[] getPlayerGroups(String world, String player) {
return playerGetGroups(world(world), player(player));
Objects.requireNonNull(player, "player");
return userGetGroups(world(world), player(player));
}
@Override
public String[] getPlayerGroups(World world, String player) {
return playerGetGroups(world(world), player(player));
Objects.requireNonNull(player, "player");
return userGetGroups(world(world), player(player));
}
@Override
public String[] getPlayerGroups(String world, OfflinePlayer player) {
return playerGetGroups(world(world), player(player));
Objects.requireNonNull(player, "player");
return userGetGroups(world(world), player(player));
}
@Override
public String[] getPlayerGroups(Player player) {
return playerGetGroups(world(player), player(player));
Objects.requireNonNull(player, "player");
return userGetGroups(world(player), player(player));
}
@Override
public String getPrimaryGroup(String world, String player) {
return playerPrimaryGroup(world(world), player(player));
Objects.requireNonNull(player, "player");
return userGetPrimaryGroup(world(world), player(player));
}
@Override
public String getPrimaryGroup(World world, String player) {
return playerPrimaryGroup(world(world), player(player));
Objects.requireNonNull(player, "player");
return userGetPrimaryGroup(world(world), player(player));
}
@Override
public String getPrimaryGroup(String world, OfflinePlayer player) {
return playerPrimaryGroup(world(world), player(player));
Objects.requireNonNull(player, "player");
return userGetPrimaryGroup(world(world), player(player));
}
@Override
public String getPrimaryGroup(Player player) {
return playerPrimaryGroup(world(player), player(player));
Objects.requireNonNull(player, "player");
return userGetPrimaryGroup(world(player), player(player));
}
}
@@ -34,12 +34,13 @@ import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.caching.type.MetaAccumulator;
import me.lucko.luckperms.common.caching.type.MetaCache;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.node.model.NodeTypes;
import net.milkbowl.vault.chat.Chat;
@@ -84,8 +85,10 @@ public class VaultChatHook extends AbstractVaultChat {
}
@Override
public String getPlayerPrefix(String world, UUID uuid) {
Objects.requireNonNull(uuid, "uuid");
public String getUserChatPrefix(String world, UUID uuid) {
if (uuid == null) {
return null;
}
User user = getUser(uuid);
if (user == null) {
return null;
@@ -94,14 +97,16 @@ public class VaultChatHook extends AbstractVaultChat {
MetaCache metaData = user.getCachedData().getMetaData(contexts);
String ret = metaData.getPrefix();
if (log()) {
logMsg("#getPlayerPrefix: %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), ret);
logMsg("#getUserChatPrefix: %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), ret);
}
return Strings.nullToEmpty(ret);
}
@Override
public String getPlayerSuffix(String world, UUID uuid) {
Objects.requireNonNull(uuid, "uuid");
public String getUserChatSuffix(String world, UUID uuid) {
if (uuid == null) {
return null;
}
User user = getUser(uuid);
if (user == null) {
return null;
@@ -110,14 +115,16 @@ public class VaultChatHook extends AbstractVaultChat {
MetaCache metaData = user.getCachedData().getMetaData(contexts);
String ret = metaData.getSuffix();
if (log()) {
logMsg("#getPlayerSuffix: %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), ret);
logMsg("#getUserChatSuffix: %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), ret);
}
return Strings.nullToEmpty(ret);
}
@Override
public void setPlayerPrefix(String world, UUID uuid, String prefix) {
Objects.requireNonNull(uuid, "uuid");
public void setUserChatPrefix(String world, UUID uuid, String prefix) {
if (uuid == null) {
return;
}
User user = getUser(uuid);
if (user == null) {
return;
@@ -126,8 +133,10 @@ public class VaultChatHook extends AbstractVaultChat {
}
@Override
public void setPlayerSuffix(String world, UUID uuid, String suffix) {
Objects.requireNonNull(uuid, "uuid");
public void setUserChatSuffix(String world, UUID uuid, String suffix) {
if (uuid == null) {
return;
}
User user = getUser(uuid);
if (user == null) {
return;
@@ -136,8 +145,10 @@ public class VaultChatHook extends AbstractVaultChat {
}
@Override
public String getPlayerInfo(String world, UUID uuid, String key) {
Objects.requireNonNull(uuid, "uuid");
public String getUserMeta(String world, UUID uuid, String key) {
if (uuid == null) {
return null;
}
Objects.requireNonNull(key, "key");
User user = getUser(uuid);
if (user == null) {
@@ -147,14 +158,16 @@ public class VaultChatHook extends AbstractVaultChat {
MetaCache metaData = user.getCachedData().getMetaData(contexts);
String ret = metaData.getMeta().get(key);
if (log()) {
logMsg("#getPlayerInfo: %s - %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), key, ret);
logMsg("#getUserMeta: %s - %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), key, ret);
}
return ret;
}
@Override
public void setPlayerInfo(String world, UUID uuid, String key, Object value) {
Objects.requireNonNull(uuid, "uuid");
public void setUserMeta(String world, UUID uuid, String key, Object value) {
if (uuid == null) {
return;
}
Objects.requireNonNull(key, "key");
User user = getUser(uuid);
if (user == null) {
@@ -164,7 +177,7 @@ public class VaultChatHook extends AbstractVaultChat {
}
@Override
public String getGroupsPrefix(String world, String name) {
public String getGroupChatPrefix(String world, String name) {
Objects.requireNonNull(name, "name");
Group group = getGroup(name);
if (group == null) {
@@ -180,7 +193,7 @@ public class VaultChatHook extends AbstractVaultChat {
}
@Override
public String getGroupsSuffix(String world, String name) {
public String getGroupChatSuffix(String world, String name) {
Objects.requireNonNull(name, "name");
Group group = getGroup(name);
if (group == null) {
@@ -196,7 +209,7 @@ public class VaultChatHook extends AbstractVaultChat {
}
@Override
public void setGroupsPrefix(String world, String name, String prefix) {
public void setGroupChatPrefix(String world, String name, String prefix) {
Objects.requireNonNull(name, "name");
Group group = getGroup(name);
if (group == null) {
@@ -206,7 +219,7 @@ public class VaultChatHook extends AbstractVaultChat {
}
@Override
public void setGroupsSuffix(String world, String name, String suffix) {
public void setGroupChatSuffix(String world, String name, String suffix) {
Objects.requireNonNull(name, "name");
Group group = getGroup(name);
if (group == null) {
@@ -216,7 +229,7 @@ public class VaultChatHook extends AbstractVaultChat {
}
@Override
public String getGroupInfo(String world, String name, String key) {
public String getGroupMeta(String world, String name, String key) {
Objects.requireNonNull(name, "name");
Objects.requireNonNull(key, "key");
Group group = getGroup(name);
@@ -227,13 +240,13 @@ public class VaultChatHook extends AbstractVaultChat {
MetaCache metaData = group.getCachedData().getMetaData(contexts);
String ret = metaData.getMeta().get(key);
if (log()) {
logMsg("#getGroupInfo: %s - %s - %s - %s", group.getName(), contexts.getContexts().toMultimap(), key, ret);
logMsg("#getGroupMeta: %s - %s - %s - %s", group.getName(), contexts.getContexts().toMultimap(), key, ret);
}
return ret;
}
@Override
public void setGroupInfo(String world, String name, String key, Object value) {
public void setGroupMeta(String world, String name, String key, Object value) {
Objects.requireNonNull(name, "name");
Objects.requireNonNull(key, "key");
Group group = getGroup(name);
@@ -258,7 +271,7 @@ public class VaultChatHook extends AbstractVaultChat {
return this.plugin.getConfiguration().get(ConfigKeys.VAULT_DEBUG);
}
private void logMsg(String format, Object... args) {
this.plugin.getLog().info("[VAULT-CHAT] " + String.format(format, args)
this.plugin.getLogger().info("[VAULT-CHAT] " + String.format(format, args)
.replace(CommandManager.SECTION_CHAR, '$')
.replace(CommandManager.AMPERSAND_CHAR, '$')
);
@@ -306,7 +319,7 @@ public class VaultChatHook extends AbstractVaultChat {
}
Node.Builder metaNode;
if (key.equalsIgnoreCase(NodeFactory.PREFIX_KEY) || key.equalsIgnoreCase(NodeFactory.SUFFIX_KEY)) {
if (key.equalsIgnoreCase(NodeTypes.PREFIX_KEY) || key.equalsIgnoreCase(NodeTypes.SUFFIX_KEY)) {
metaNode = NodeFactory.buildChatMetaNode(ChatMetaType.valueOf(key.toUpperCase()), 100, value.toString());
} else {
metaNode = NodeFactory.buildMetaNode(key, value.toString());
@@ -326,6 +339,6 @@ public class VaultChatHook extends AbstractVaultChat {
context.add(Contexts.WORLD_KEY, world.toLowerCase());
}
context.add(Contexts.SERVER_KEY, this.permissionHook.getVaultServer());
return new Contexts(context.build(), this.permissionHook.isIncludeGlobal(), true, true, true, true, false);
return Contexts.of(context.build(), this.permissionHook.isIncludeGlobal(), true, true, true, true, false);
}
}
@@ -56,9 +56,9 @@ public class VaultHookManager {
this.chatHook = new VaultChatHook(plugin, this.permissionHook);
}
final ServicesManager sm = plugin.getServer().getServicesManager();
sm.register(Permission.class, this.permissionHook, plugin, ServicePriority.High);
sm.register(Chat.class, this.chatHook, plugin, ServicePriority.High);
final ServicesManager sm = plugin.getBootstrap().getServer().getServicesManager();
sm.register(Permission.class, this.permissionHook, plugin.getBootstrap(), ServicePriority.High);
sm.register(Chat.class, this.chatHook, plugin.getBootstrap(), ServicePriority.High);
} catch (Exception e) {
e.printStackTrace();
@@ -71,7 +71,7 @@ public class VaultHookManager {
* @param plugin the plugin
*/
public void unhook(LPBukkitPlugin plugin) {
final ServicesManager sm = plugin.getServer().getServicesManager();
final ServicesManager sm = plugin.getBootstrap().getServer().getServicesManager();
if (this.permissionHook != null) {
sm.unregister(Permission.class, this.permissionHook);
@@ -34,12 +34,12 @@ import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.caching.type.PermissionCache;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.verbose.CheckOrigin;
import net.milkbowl.vault.permission.Permission;
@@ -48,6 +48,7 @@ import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -116,8 +117,10 @@ public class VaultPermissionHook extends AbstractVaultPermission {
}
@Override
public boolean hasPermission(String world, UUID uuid, String permission) {
Objects.requireNonNull(uuid, "uuid");
public boolean userHasPermission(String world, UUID uuid, String permission) {
if (uuid == null) {
return false;
}
Objects.requireNonNull(permission, "permission");
User user = getUser(uuid);
@@ -130,14 +133,16 @@ public class VaultPermissionHook extends AbstractVaultPermission {
Tristate result = permissionData.getPermissionValue(permission, CheckOrigin.INTERNAL);
if (log()) {
logMsg("#hasPermission: %s - %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), permission, result);
logMsg("#userHasPermission: %s - %s - %s - %s", user.getFriendlyName(), contexts.getContexts().toMultimap(), permission, result);
}
return result.asBoolean();
}
@Override
public boolean playerAddPermission(String world, UUID uuid, String permission) {
Objects.requireNonNull(uuid, "uuid");
public boolean userAddPermission(String world, UUID uuid, String permission) {
if (uuid == null) {
return false;
}
Objects.requireNonNull(permission, "permission");
User user = getUser(uuid);
@@ -150,8 +155,10 @@ public class VaultPermissionHook extends AbstractVaultPermission {
}
@Override
public boolean playerRemovePermission(String world, UUID uuid, String permission) {
Objects.requireNonNull(uuid, "uuid");
public boolean userRemovePermission(String world, UUID uuid, String permission) {
if (uuid == null) {
return false;
}
Objects.requireNonNull(permission, "permission");
User user = getUser(uuid);
@@ -164,29 +171,37 @@ public class VaultPermissionHook extends AbstractVaultPermission {
}
@Override
public boolean playerInGroup(String world, UUID uuid, String group) {
Objects.requireNonNull(uuid, "uuid");
public boolean userInGroup(String world, UUID uuid, String group) {
if (uuid == null) {
return false;
}
Objects.requireNonNull(group, "group");
return hasPermission(world, uuid, NodeFactory.groupNode(rewriteGroupName(group)));
return userHasPermission(world, uuid, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public boolean playerAddGroup(String world, UUID uuid, String group) {
Objects.requireNonNull(uuid, "uuid");
public boolean userAddGroup(String world, UUID uuid, String group) {
if (uuid == null) {
return false;
}
Objects.requireNonNull(group, "group");
return checkGroupExists(group) && playerAddPermission(world, uuid, NodeFactory.groupNode(rewriteGroupName(group)));
return checkGroupExists(group) && userAddPermission(world, uuid, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public boolean playerRemoveGroup(String world, UUID uuid, String group) {
Objects.requireNonNull(uuid, "uuid");
public boolean userRemoveGroup(String world, UUID uuid, String group) {
if (uuid == null) {
return false;
}
Objects.requireNonNull(group, "group");
return checkGroupExists(group) && playerRemovePermission(world, uuid, NodeFactory.groupNode(rewriteGroupName(group)));
return checkGroupExists(group) && userRemovePermission(world, uuid, NodeFactory.groupNode(rewriteGroupName(group)));
}
@Override
public String[] playerGetGroups(String world, UUID uuid) {
Objects.requireNonNull(uuid, "uuid");
public String[] userGetGroups(String world, UUID uuid) {
if (uuid == null) {
return new String[0];
}
User user = getUser(uuid);
if (user == null) {
@@ -195,7 +210,7 @@ public class VaultPermissionHook extends AbstractVaultPermission {
ContextSet contexts = contextForLookup(user, world).getContexts();
String[] ret = user.getEnduringNodes().values().stream()
String[] ret = user.enduringData().immutable().values().stream()
.filter(Node::isGroupNode)
.filter(n -> n.shouldApplyWithContext(contexts))
.map(n -> {
@@ -208,15 +223,17 @@ public class VaultPermissionHook extends AbstractVaultPermission {
.toArray(String[]::new);
if (log()) {
logMsg("#playerGetGroups: %s - %s - %s", user.getFriendlyName(), contexts, Arrays.toString(ret));
logMsg("#userGetGroups: %s - %s - %s", user.getFriendlyName(), contexts, Arrays.toString(ret));
}
return ret;
}
@Override
public String playerPrimaryGroup(String world, UUID uuid) {
Objects.requireNonNull(uuid, "uuid");
public String userGetPrimaryGroup(String world, UUID uuid) {
if (uuid == null) {
return null;
}
User user = getUser(uuid);
if (user == null) {
@@ -230,7 +247,7 @@ public class VaultPermissionHook extends AbstractVaultPermission {
}
if (log()) {
logMsg("#playerPrimaryGroup: %s - %s - %s", user.getFriendlyName(), world, value);
logMsg("#userGetPrimaryGroup: %s - %s - %s", user.getFriendlyName(), world, value);
}
return value;
@@ -311,7 +328,7 @@ public class VaultPermissionHook extends AbstractVaultPermission {
return this.plugin.getConfiguration().get(ConfigKeys.VAULT_DEBUG);
}
private void logMsg(String format, Object... args) {
this.plugin.getLog().info("[VAULT-PERMS] " + String.format(format, args)
this.plugin.getLogger().info("[VAULT-PERMS] " + String.format(format, args)
.replace(CommandManager.SECTION_CHAR, '$')
.replace(CommandManager.AMPERSAND_CHAR, '$')
);
@@ -321,7 +338,7 @@ public class VaultPermissionHook extends AbstractVaultPermission {
Contexts contextForLookup(User user, String world) {
MutableContextSet context;
Player player = user == null ? null : this.plugin.getPlayer(user);
Player player = Optional.ofNullable(user).flatMap(u -> this.plugin.getBootstrap().getPlayer(u.getUuid())).orElse(null);
if (player != null) {
context = this.plugin.getContextManager().getApplicableContext(player).mutableCopy();
} else {
@@ -348,7 +365,7 @@ public class VaultPermissionHook extends AbstractVaultPermission {
}
}
return new Contexts(context, isIncludeGlobal(), true, true, true, true, false);
return Contexts.of(context, isIncludeGlobal(), true, true, true, true, false);
}
// utility methods for modifying the state of PermissionHolders
@@ -386,11 +403,11 @@ public class VaultPermissionHook extends AbstractVaultPermission {
void holderSave(PermissionHolder holder) {
if (holder.getType().isUser()) {
User u = (User) holder;
this.plugin.getStorage().saveUser(u).thenRunAsync(() -> u.getRefreshBuffer().request(), this.plugin.getScheduler().async());
this.plugin.getStorage().saveUser(u);
}
if (holder.getType().isGroup()) {
Group g = (Group) holder;
this.plugin.getStorage().saveGroup(g).thenRunAsync(() -> this.plugin.getUpdateTaskBuffer().request(), this.plugin.getScheduler().async());
this.plugin.getStorage().saveGroup(g).thenRunAsync(() -> this.plugin.getUpdateTaskBuffer().request(), this.plugin.getBootstrap().getScheduler().async());
}
}
+433 -288
View File
@@ -18,161 +18,312 @@
####################################################################################################
# +----------------------------------------------------------------------------------------------+ #
# | General | #
# | | #
# | ESSENTIAL SETTINGS | #
# | | #
# | Important settings that control how LuckPerms functions. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# The name of the server, used for server specific permissions. Set to 'global' to disable.
# The name of the server, used for server specific permissions.
#
# - When set to "global" this setting is effectively ignored.
# - In all other cases, the value here is added to all players in a "server" context.
# - See: https://github.com/lucko/LuckPerms/wiki/Context
server: global
# If users on this server should have their global permissions applied.
# If set to false, only server specific permissions will apply for users on this server
include-global: true
# If users on this server should have their global world permissions applied.
# If set to false, only world specific permissions will apply for users on this server
include-global-world: true
# If users on this server should have global (non-server specific) groups applied
apply-global-groups: true
# If users on this server should have global (non-world specific) groups applied
apply-global-world-groups: true
# If the servers own UUID cache/lookup facility should be used when there is no record for a player
# in the LuckPerms cache.
# already in LuckPerms.
#
# - When this is set to 'false', commands using a player's username will not work unless the player
# has joined since LuckPerms was first installed.
# - To get around this, you can use a player's uuid directly in the command, or enable this option.
# - When this is set to 'true', the server facility is used. This may use a number of methods,
# including checking the servers local cache, or making a request to the Mojang API.
use-server-uuid-cache: false
# If LuckPerms should use the "server-name" property from the "server.properties"
# file as the "server" option within LuckPerms.
use-server-properties-name: false
# If set to true, LuckPerms will allow usernames with non alphanumeric characters.
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | STORAGE SETTINGS | #
# | | #
# | Controls which storage method LuckPerms will use to store data. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# How the plugin should store data
#
# Note that due to the design of the storage implementation, usernames must still be
# 16 characters or less.
allow-invalid-usernames: false
# If LuckPerms should produce extra logging output when it handles logins.
# Useful if you're having issues with UUID forwarding or data not being loaded.
debug-logins: false
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in
# this list, the value assigned will be sent forward for permission calculation instead.
world-rewrite:
# world_nether: world
# world_the_end: world
# Controls how temporary permissions/parents/meta should be accumulated
# - The various options are explained in more detail on the wiki:
# https://github.com/lucko/LuckPerms/wiki/Choosing-a-Storage-type
#
# The default behaviour is "deny"
# If "accumulate": durations will be added to the existing expiry time
# If "replace": durations will be replaced if the new duration is later than the current expiration
# If "deny": the command will just fail if you try to add another node with the same expiry
# - Possible options:
#
# | Remote databases - require connection information to be configured below
# |=> MySQL
# |=> MariaDB (preferred over MySQL)
# |=> PostgreSQL
# |=> MongoDB
#
# | Flatfile/local database - don't require any extra configuration
# |=> H2 (preferred over SQLite)
# |=> SQLite
#
# | Readable & editable text files - don't require any extra configuration
# |=> YAML (.yml files)
# |=> JSON (.json files)
# |=> HOCON (.conf files)
# |=> TOML (.toml files)
# |
# | By default, user, group and track data is separated into different files. Data can be combined
# | and all stored in the same file by switching to a combined storage variant.
# | Just add '-combined' to the end of the storage-method, e.g. 'yaml-combined'
#
# - A H2 database is the default option.
# - If you want to edit data manually in "traditional" storage files, we suggest using YAML.
storage-method: h2
# The following block defines the settings for remote database storage methods.
#
# - You don't need to touch any of the settings here if you're using a local storage method!
# - The connection detail options are shared between all remote storage types.
data:
# Define the address and port for the database.
# - The standard DB engine port is used by default
# (MySQL: 3306, PostgreSQL: 5432, MongoDB: 27017)
# - Specify as "host:port" if differs
address: localhost
# The name of the database to store LuckPerms data in.
# - This must be created already. Don't worry about this setting if you're using MongoDB.
database: minecraft
# Credentials for the database.
username: root
password: ''
# These settings apply to the MySQL connection pool.
# - The default values will be suitable for the majority of users.
# - Do not change these settings unless you know what you're doing!
pool-settings:
# Sets the maximum size of the MySQL connection pool.
# - Basically this value will determine the maximum number of actual
# connections to the database backend.
# - More information about determining the size of connection pools can be found here:
# https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
maximum-pool-size: 10
# Sets the minimum number of idle connections that the pool will try to maintain.
# - For maximum performance and responsiveness to spike demands, it is recommended to not set
# this value and instead allow the pool to act as a fixed size connection pool.
# (set this value to the same as 'maximum-pool-size')
minimum-idle: 10
# This setting controls the maximum lifetime of a connection in the pool in milliseconds.
# - The value should be at least 30 seconds less than any database or infrastructure imposed
# connection time limit.
maximum-lifetime: 1800000 # 30 minutes
# This setting controls the maximum number of milliseconds that the plugin will wait for a
# connection from the pool, before timing out.
connection-timeout: 5000 # 5 seconds
# This setting allows you to define extra properties for connections.
properties:
useUnicode: true
characterEncoding: utf8
# The prefix for all LuckPerms SQL tables.
# - Change this is 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 ClientConnectionURI for use with replica sets and custom connection options
# - See https://docs.mongodb.com/manual/reference/connection-string/
mongodb_connection_URI: ''
# Define settings for a "split" storage setup.
#
# - This allows you to define a storage method for each type of data.
# - The connection options above still have to be correct for each type here.
split-storage:
# Don't touch this if you don't want to use split storage!
enabled: false
methods:
# These options don't need to be modified if split storage isn't enabled.
user: h2
group: h2
track: h2
uuid: h2
log: h2
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | UPDATE PROPAGATION & MESSAGING SERVICE | #
# | | #
# | Controls the ways in which LuckPerms will sync data & notify other servers of changes. | #
# | These options are documented on greater detail on the wiki under "Instant Updates". | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# This option controls how frequently LuckPerms will perform a sync task.
#
# - A sync task will refresh all data from the storage, and ensure that the most up-to-date data is
# being used by the plugin.
# - This is disabled by default, as most users will not need it. However, if you're using a remote
# storage type without a messaging service setup, you may wish to set this to something like 3.
# - Set to -1 to disable the task completely.
sync-minutes: -1
# If the file watcher should be enabled.
#
# - When using a file-based storage type, LuckPerms can monitor the data files for changes, and
# automatically update when changes are detected.
# - If you don't want this feature to be active, set this option to false.
watch-files: true
# Define which messaging service should be used by the plugin.
#
# - If enabled and configured, LuckPerms will use the messaging service to inform other connected
# servers of changes.
# - Use the command "/lp networksync" to manually push changes.
# - Data is NOT stored using this service. It is only used as a messaging platform.
#
# - If you decide to enable this feature, you should set "sync-minutes" to -1, as there is no need
# for LuckPerms to poll the database for changes.
#
# - 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.
# => bungee 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 BungeeCord proxy.
# => lilypad Uses LilyPad pub-sub to push changes. You need to have the LilyPad-Connect plugin
# installed.
# => redis Uses Redis pub-sub to push changes. Your server connection info must be configured
# below.
# => none Disables the service.
messaging-service: none
# If LuckPerms should automatically push updates after a change has been made with a command.
auto-push-updates: true
# If LuckPerms should push logging entries to connected servers via the messaging service.
push-log-entries: true
# If LuckPerms should broadcast received logging entries to players on this platform.
#
# - If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you
# should set this option to false on either your backends or your proxies, to avoid players being
# messaged twice about log entries.
broadcast-received-log-entries: true
# Settings for Redis.
# Port 6379 is used by default; set address to "host:port" if differs
redis:
enabled: false
address: localhost
password: ''
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | CUSTOMIZATION SETTINGS | #
# | | #
# | Settings that allow admins to customize the way LuckPerms operates. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# Controls how temporary permissions/parents/meta should be accumulated.
#
# - The default behaviour is "deny".
# - This behaviour can also be specified when the command is executed. See the command usage
# documentation for more info.
#
# - Possible options:
# => accumulate durations will be added to the existing expiry time
# => replace durations will be replaced if the new duration is later than the current
# expiration
# => deny the command will just fail if you try to add another node with the same expiry
temporary-add-behaviour: deny
# How should LuckPerms determine a users "primary" group.
# Controls how LuckPerms will determine a users "primary" group.
#
# Available Options:
# -> stored use the value stored against the users record in the file/database
# -> parents-by-weight just use the users most highly weighted parent
# -> all-parents-by-weight same as above, but calculates based upon all parents inherited from both
# directly and indirectly
# - The meaning and influence of "primary groups" are explained in detail on the wiki.
# - The preferred approach is to let LuckPerms automatically determine a users primary group
# based on the relative weight of their parent groups.
#
# - Possible options:
# => stored use the value stored against the users record in the file/database
# => parents-by-weight just use the users most highly weighted parent
# => all-parents-by-weight same as above, but calculates based upon all parents inherited from
# both directly and indirectly
primary-group-calculation: parents-by-weight
# If set to false, the plugin will allow a Users primary group to be removed with the
# 'parent remove' command, and will set their primary group back to default.
prevent-primary-group-removal: false
# If the plugin should check for "extra" permissions with users run LP commands.
#
# These extra permissions allow finer control over what users can do with each command, and
# who they have access to edit.
#
# The permissions are *not* static, unlike the 'base' permisssions, and will depend upon the
# arguments given within the command.
# - These extra permissions allow finer control over what users can do with each command, and who
# they have access to edit.
# - The nature of the checks are documented on the wiki under "Argument based command permissions".
# - Argument based permissions are *not* static, unlike the 'base' permissions, and will depend upon
# the arguments given within the command.
argument-based-command-permissions: false
# +----------------------------------------------------------------------------------------------+ #
# | Permission Calculation | #
# +----------------------------------------------------------------------------------------------+ #
# If the plugin should apply wildcard permissions.
# If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered
# permissions matching the wildcard.
apply-wildcards: true
# If the plugin should parse regex permissions.
# If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the
# node, and resolve & apply all registered permissions matching the regex.
apply-regex: true
# If the plugin should complete and apply shorthand permissions.
# If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# If the plugin should apply Bukkit child permissions.
# Plugin authors can define custom permissions structures for their plugin, which will be resolved
# and used by LuckPerms if this setting is enabled.
apply-bukkit-child-permissions: true
# If the plugin should apply Bukkit default permissions.
# Plugin authors can define permissions which should be given to all users by default, or setup
# permissions which should/shouldn't be given to opped players.
# If this option is set to false, LuckPerms will ignore these defaults.
apply-bukkit-default-permissions: true
# If the plugin should apply attachment permissions.
# Other plugins on the server are able to add their own "permission attachments" to players. This
# allows them to grant players additional permissions which last until the end of the session, or
# until they're removed. If this option is set to false, LuckPerms will not include these attachment
# permissions when considering if a player should have access to a certain permission.
apply-bukkit-attachment-permissions: true
# The algorithm LuckPerms should use when traversing the "inheritance tree".
# If the plugin should send log notifications to users whenever permissions are modified.
#
# The valid options are:
# - breadth-first
# - depth-first-pre-order
# - depth-first-post-order
# - Notifications are only sent to those with the appropriate permission to receive them
# - They can also be temporarily enabled/disabled on a per-user basis using
# '/lp log notify <on|off>'
log-notify: true
# Defines the options for prefix and suffix stacking.
#
# See here for information about the differences between each algorithm.
# - https://en.wikipedia.org/wiki/Breadth-first_search
# - https://en.wikipedia.org/wiki/Depth-first_search
inheritance-traversal-algorithm: depth-first-pre-order
# Define special group weights for this server.
# Default is just 0.
group-weight:
# admin: 10
# +----------------------------------------------------------------------------------------------+ #
# | Meta Formatting & Stacking | #
# +----------------------------------------------------------------------------------------------+ #
# Allows you to setup prefix/suffix stacking options.
# - The feature allows you to display multiple prefixes or suffixes alongside a players username in
# chat.
# - It is explained and documented in more detail on the wiki under "Prefix & Suffix Stacking".
#
# Available formats:
# - highest
# - lowest
# - highest_own
# - lowest_own
# - highest_inherited
# - lowest_inherited
# - highest_on_track_<track>
# - lowest_on_track_<track>
# - highest_not_on_track_<track>
# - lowest_not_on_track_<track>
# - The options are divided into separate sections for prefixes and suffixes.
# - The value of 'start-spacer' is included at the start of the resultant prefix/suffix.
# - The value of 'end-spacer' is included at the end of the resultant prefix/suffix.
# - The value of 'middle-spacer' is included between each element in the resultant prefix/suffix.
#
# Each element is added in the order listed.
# - Possible format options:
# => highest Selects the value with the highest weight, from all values
# held by or inherited by the player.
#
# => lowest Same as above, except takes the one with the lowest weight.
#
# => highest_own Selects the value with the highest weight, but will not
# accept any inherited values.
#
# => lowest_own Same as above, except takes the value with the lowest weight.
#
# => highest_inherited Selects the value with the highest weight, but will only
# accept inherited values.
#
# => lowest_inherited Same as above, except takes the value with the lowest weight.
#
# => highest_on_track_<track> Selects the value with the highest weight, but only if the
# value was inherited from a group on the given track.
#
# => lowest_on_track_<track> Same as above, except takes the value with the lowest weight.
#
# => highest_not_on_track_<track> Selects the value with the highest weight, but only if the
# 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.
meta-formatting:
prefix:
format:
@@ -191,46 +342,153 @@ meta-formatting:
# +----------------------------------------------------------------------------------------------+ #
# | OP (Server Operator) Settings | #
# | | #
# | PERMISSION CALCULATION AND INHERITANCE | #
# | | #
# | Modify the way permission checks, meta lookups and inheritance resolutions are handled. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# If the vanilla OP system is enabled. If set to false, all users will be de-opped, and the op/deop
# commands will be disabled.
# The algorithm LuckPerms should use when traversing the "inheritance tree".
#
# - Possible options:
# => breadth-first See: https://en.wikipedia.org/wiki/Breadth-first_search
# => depth-first-pre-order See: https://en.wikipedia.org/wiki/Depth-first_search
# => depth-first-post-order See: https://en.wikipedia.org/wiki/Depth-first_search
inheritance-traversal-algorithm: depth-first-pre-order
# +----------------------------------------------------------------------------------------------+ #
# | Permission resolution settings | #
# +----------------------------------------------------------------------------------------------+ #
# If users on this server should have their global permissions applied.
# When set to false, only server specific permissions will apply for users on this server
include-global: true
# If users on this server should have their global world permissions applied.
# When set to false, only world specific permissions will apply for users on this server
include-global-world: true
# If users on this server should have global (non-server specific) groups applied
apply-global-groups: true
# If users on this server should have global (non-world specific) groups applied
apply-global-world-groups: true
# +----------------------------------------------------------------------------------------------+ #
# | Inheritance settings | #
# +----------------------------------------------------------------------------------------------+ #
# If the plugin should apply wildcard permissions.
#
# - If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered
# permissions matching the wildcard.
apply-wildcards: true
# If the plugin should parse regex permissions.
#
# - If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the
# node, and resolve & apply all registered permissions matching the regex.
apply-regex: true
# If the plugin should complete and apply shorthand permissions.
#
# - If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# If the plugin should apply Bukkit child permissions.
#
# - Plugin authors can define custom permissions structures for their plugin, which will be resolved
# and used by LuckPerms if this setting is enabled.
apply-bukkit-child-permissions: true
# If the plugin should apply Bukkit default permissions.
#
# - Plugin authors can define permissions which should be given to all users by default, or setup
# permissions which should/shouldn't be given to opped players.
# - If this option is set to false, LuckPerms will ignore these defaults.
apply-bukkit-default-permissions: true
# If the plugin should apply attachment permissions.
#
# - Other plugins on the server are able to add their own "permission attachments" to players.
# - This allows them to grant players additional permissions which last until the end of the
# session, or until they're removed.
# - If this option is set to false, LuckPerms will not include these attachment permissions when
# considering if a player should have access to a certain permission.
apply-bukkit-attachment-permissions: true
# +----------------------------------------------------------------------------------------------+ #
# | Extra settings | #
# +----------------------------------------------------------------------------------------------+ #
# Allows you to set "aliases" for the worlds sent forward for context calculation.
#
# - These aliases are provided in addition to the real world name. Applied recursively.
# - Remove the comment characters for the default aliases to apply.
world-rewrite:
# world_nether: world
# world_the_end: world
# Define special group weights for this server.
#
# - Group weights can also be applied directly to group data, using the setweight command.
# - This section allows weights to be set on a per-server basis.
group-weight:
# admin: 10
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | FINE TUNING OPTIONS | #
# | | #
# | A number of more niche settings for tweaking and changing behaviour. The section also | #
# | contains toggles for some more specialised features. It is only necessary to make changes to | #
# | these options if you want to fine-tune LuckPerms behaviour. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# +----------------------------------------------------------------------------------------------+ #
# | Server Operator (OP) settings | #
# +----------------------------------------------------------------------------------------------+ #
# Controls whether server operators should exist at all.
#
# - When set to 'false', all players will be de-opped, and the /op and /deop commands will be
# disabled.
enable-ops: true
# If set to true, any user with the permission "luckperms.autoop" will automatically be granted
# server operator status. This permission can be inherited, or set on specific servers/worlds,
# temporarily, etc.
# Enables or disables a special permission based system in LuckPerms for controlling OP status.
#
# Additionally, setting this to true will force the "enable-ops" option above to false. All users
# will be de-opped unless they have the permission node, and the op/deop commands will be disabled.
#
# It is important to note that this setting is only checked when a player first joins the server,
# and when they switch worlds. Therefore, simply removing this permission from a user will not
# automatically de-op them. A player needs to relog to have the change take effect.
#
# It is recommended that you use this option instead of assigning a single '*' permission.
# - If set to true, any user with the permission "luckperms.autoop" will automatically be granted
# server operator status. This permission can be inherited, or set on specific servers/worlds,
# temporarily, etc.
# - Additionally, setting this to true will force the "enable-ops" option above to false. All users
# will be de-opped unless they have the permission node, and the op/deop commands will be
# disabled.
# - It is recommended that you use this option instead of assigning a single '*' permission.
auto-op: false
# If opped players should be allowed to use LuckPerms commands. Set to false to only allow users who
# have the permissions access to the commands
# Defines if "opped" players should be able to use all LuckPerms commands by default.
#
# - Set to false to only allow users who have the permissions access to the commands
commands-allow-op: true
# +----------------------------------------------------------------------------------------------+ #
# | Vault | #
# | Vault integration settings | #
# +----------------------------------------------------------------------------------------------+ #
# If the vault-server option below should be used.
# When this option is set to false, the server value defined above under "server" is used.
#
# - When this option is set to false, the server value defined above under "server" is used.
use-vault-server: false
# The name of the server used within Vault operations. If you don't want Vault operations to be
# server specific, set this to "global".
# The name of the server used within Vault operations.
#
# Will only take effect if use-vault-server is set to true above.
# - If you don't want Vault operations to be server specific, set this to "global".
# - Will only take effect if use-vault-server is set to true above.
vault-server: global
# If global permissions should be considered when retrieving meta or player groups
@@ -242,150 +500,37 @@ vault-ignore-world: false
# If LuckPerms should print debugging info to console when a plugin uses a Vault function
vault-debug: false
# +----------------------------------------------------------------------------------------------+ #
# | Storage | #
# | Miscellaneous (and rarely used) settings | #
# +----------------------------------------------------------------------------------------------+ #
# Which storage method the plugin should use.
# If LuckPerms should produce extra logging output when it handles logins.
#
# See: https://github.com/lucko/LuckPerms/wiki/Choosing-a-Storage-type
# Currently supported: mysql, mariadb, postgresql, sqlite, h2, json, yaml, hocon, mongodb
# - Useful if you're having issues with UUID forwarding or data not being loaded.
debug-logins: false
# If LuckPerms should use the "server-name" property from the "server.properties" file as the
# "server" option within LuckPerms.
use-server-properties-name: false
# If LuckPerms should allow usernames with non alphanumeric characters.
#
# Fill out connection info below if you're using MySQL, MariaDB, PostgreSQL or MongoDB
# If your MySQL server supports it, the "mariadb" option is preferred over "mysql".
storage-method: h2
# - Note that due to the design of the storage implementation, usernames must still be 16 characters
# or less.
allow-invalid-usernames: false
# When using a file-based storage type, LuckPerms can monitor the data files for changes, and then
# schedule automatic updates when changes are detected.
# If LuckPerms should allow a users primary group to be removed with the 'parent remove' command.
#
# If you don't want this to happen, set this option to false.
watch-files: true
# This block enables support for split datastores.
split-storage:
enabled: false
methods:
user: h2
group: h2
track: h2
uuid: h2
log: h2
data:
# Uses standard DB engine port by default
# MySQL: 3306, PostgreSQL: 5432, MongoDB: 27017
# Specify as "host:port" if differs
address: localhost
database: minecraft
username: root
password: ''
# These settings apply to the MySQL connection pool.
# The default values will be suitable for the majority of users.
# Do not change these settings unless you know what you're doing!
pool-settings:
# Sets the maximum size of the MySQL connection pool.
# Basically this value will determine the maximum number of actual
# connections to the database backend.
#
# More information about determining the size of connection pools can be found here:
# https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
maximum-pool-size: 10
# Sets the minimum number of idle connections that the pool will try to maintain.
#
# For maximum performance and responsiveness to spike demands, it is recommended to not set
# this value and instead allow the pool to act as a fixed size connection pool.
# (set this value to the same as 'maximum-pool-size')
minimum-idle: 10
# This setting controls the maximum lifetime of a connection in the pool in milliseconds.
# The value should be at least 30 seconds less than any database or infrastructure imposed
# connection time limit.
maximum-lifetime: 1800000 # 30 minutes
# This setting controls the maximum number of milliseconds that the plugin will wait for a
# connection from the pool, before timing out.
connection-timeout: 5000 # 5 seconds
# This setting allows you to define extra properties for connections.
properties:
useUnicode: true
characterEncoding: utf8
# The prefix for all LuckPerms tables. Change this is you want to use different tables for
# different servers.
#
# This should *not* be set to "lp_" if you have previously ran LuckPerms v2.16.81 or earlier with
# this database.
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 ClientConnectionURI for use with replicasets and custom connection options
# See https://docs.mongodb.com/manual/reference/connection-string/
mongodb_connection_URI: ''
# This option controls how frequently LuckPerms will perform a sync task.
# A sync task will refresh all data from the storage, and ensure that the most up-to-date data is
# being used by the plugin.
#
# This is disabled by default, as most users will not need it. However, if you're using a remote
# storage type without a messaging service setup, you may wish to set this value to something like
# 3.
#
# Set to -1 to disable the task completely.
sync-minutes: -1
# Settings for the messaging service
#
# If enabled and configured, LuckPerms will use the messaging system to inform other
# connected servers of changes. Use the command "/luckperms networksync" to push changes.
# Data is NOT stored using this service. It is only used as a messaging platform.
#
# If you decide to enable this feature, you should set "sync-minutes" to -1, as there is no need for
# LuckPerms to poll the database for changes.
#
# Available options:
# -> bungee uses the plugin messaging channels. Must be enabled on all connected servers to work.
# -> lilypad uses lilypad pub sub to push changes. You need to have the LilyPad-Connect plugin
# installed.
# -> redis uses redis pub sub to push changes. Your redis server must be configured below.
# -> none nothing
messaging-service: none
# If LuckPerms should automatically push updates after a change has been made with a command.
auto-push-updates: true
# If LuckPerms should push logging entries to connected servers via the messaging service.
push-log-entries: true
# If LuckPerms should broadcast received logging entries to players on this platform.
#
# If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you should
# set this option to false on either your backends or your proxies, to avoid players being messaged
# twice about log entries.
broadcast-received-log-entries: true
# Settings for Redis.
# Port 6379 is used by default; set address to "host:port" if differs
redis:
enabled: false
address: localhost
password: ''
# - When this happens, the plugin will set their primary group back to default.
prevent-primary-group-removal: false
# +----------------------------------------------------------------------------------------------+ #
# | Default Assignments | #
# | | #
# | DEFAULT ASSIGNMENTS | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# This section allows you to define defaults to give users whenever they connect to the server.
+1 -1
View File
@@ -4,7 +4,7 @@ description: A permissions plugin
author: Luck
website: https://github.com/lucko/LuckPerms
main: me.lucko.luckperms.bukkit.LPBukkitPlugin
main: me.lucko.luckperms.bukkit.LPBukkitBootstrap
load: STARTUP
# This means that all plugins that (soft-)depend on Vault, depend on LuckPerms too.
+1 -5
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>4.1-SNAPSHOT</version>
<version>4.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -100,10 +100,6 @@
<pattern>ninja.leaping.configurate</pattern>
<shadedPattern>me.lucko.luckperms.lib.configurate</shadedPattern>
</relocation>
<relocation>
<pattern>com.typesafe.config</pattern>
<shadedPattern>me.lucko.luckperms.lib.hocon</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
@@ -28,8 +28,8 @@ package me.lucko.luckperms.bungee;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.sender.Sender;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
@@ -45,7 +45,7 @@ public class BungeeCommandExecutor extends Command implements TabExecutor {
private final LPBungeePlugin plugin;
private final CommandManager manager;
BungeeCommandExecutor(LPBungeePlugin plugin, CommandManager manager) {
public BungeeCommandExecutor(LPBungeePlugin plugin, CommandManager manager) {
super("luckpermsbungee", null, "lpb", "bperm", "bperms", "bpermission", "bpermissions");
this.plugin = plugin;
this.manager = manager;
@@ -61,11 +61,6 @@ public class BungeeConfigAdapter extends AbstractConfigurationAdapter implements
}
}
@Override
public boolean contains(String path) {
return this.configuration.contains(path);
}
@Override
public String getString(String path, String def) {
return this.configuration.getString(path, def);
@@ -0,0 +1,97 @@
/*
* 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.bungee;
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
import me.lucko.luckperms.common.event.AbstractEventBus;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
public class BungeeEventBus extends AbstractEventBus<Plugin> implements Listener {
private final LPBungeeBootstrap bootstrap;
public BungeeEventBus(LPBungeePlugin plugin, LuckPermsApiProvider apiProvider) {
super(plugin, apiProvider);
this.bootstrap = plugin.getBootstrap();
}
@Override
protected Plugin checkPlugin(Object plugin) throws IllegalArgumentException {
if (plugin instanceof Plugin) {
Plugin bungeePlugin = (Plugin) plugin;
// add a custom log handler to effectively listen for the plugin being disabled.
// BungeeCord doesn't really support enabling/disabling plugins at runtime, and as
// such doesn't have a PluginDisableEvent. However, some plugins do exist to reload
// plugins at runtime. We rely on these plugins following the BungeeCord behaviour,
// and #close ing the plugins logger, so we can unregister the listeners. :)
Handler[] handlers = bungeePlugin.getLogger().getHandlers();
for (Handler handler : handlers) {
if (handler instanceof UnloadHookLoggerHandler) {
return bungeePlugin;
}
}
bungeePlugin.getLogger().addHandler(new UnloadHookLoggerHandler(bungeePlugin));
return bungeePlugin;
}
throw new IllegalArgumentException("Object " + plugin + " (" + plugin.getClass().getName() + ") is not a plugin.");
}
@Override
public void close() {
for (Plugin plugin : this.bootstrap.getProxy().getPluginManager().getPlugins()) {
for (Handler handler : plugin.getLogger().getHandlers()) {
if (handler instanceof UnloadHookLoggerHandler) {
plugin.getLogger().removeHandler(handler);
}
}
}
super.close();
}
private final class UnloadHookLoggerHandler extends Handler {
private final Plugin plugin;
private UnloadHookLoggerHandler(Plugin plugin) {
this.plugin = plugin;
}
@Override
public void close() {
unregisterHandlers(this.plugin);
}
@Override public void publish(LogRecord record) {}
@Override public void flush() {}
}
}
@@ -27,7 +27,7 @@ package me.lucko.luckperms.bungee;
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
import me.lucko.luckperms.common.plugin.SchedulerTask;
import me.lucko.luckperms.common.utils.SafeIteration;
import me.lucko.luckperms.common.utils.Iterators;
import net.md_5.bungee.api.scheduler.ScheduledTask;
import net.md_5.bungee.api.scheduler.TaskScheduler;
@@ -50,18 +50,18 @@ public class BungeeSchedulerAdapter implements SchedulerAdapter {
return ticks * MILLISECONDS_PER_TICK;
}
private final LPBungeePlugin plugin;
private final LPBungeeBootstrap bootstrap;
private final Executor asyncExecutor;
private final Set<SchedulerTask> tasks = ConcurrentHashMap.newKeySet();
public BungeeSchedulerAdapter(LPBungeePlugin plugin) {
this.plugin = plugin;
this.asyncExecutor = r -> plugin.getProxy().getScheduler().runAsync(plugin, r);
public BungeeSchedulerAdapter(LPBungeeBootstrap bootstrap) {
this.bootstrap = bootstrap;
this.asyncExecutor = r -> bootstrap.getProxy().getScheduler().runAsync(bootstrap, r);
}
private TaskScheduler scheduler() {
return this.plugin.getProxy().getScheduler();
return this.bootstrap.getProxy().getScheduler();
}
@Override
@@ -87,7 +87,7 @@ public class BungeeSchedulerAdapter implements SchedulerAdapter {
@Override
public SchedulerTask asyncRepeating(Runnable runnable, long intervalTicks) {
long millis = ticksToMillis(intervalTicks);
SchedulerTask task = new BungeeSchedulerTask(scheduler().schedule(this.plugin, runnable, millis, millis, TimeUnit.MILLISECONDS));
SchedulerTask task = new BungeeSchedulerTask(scheduler().schedule(this.bootstrap, runnable, millis, millis, TimeUnit.MILLISECONDS));
this.tasks.add(task);
return task;
}
@@ -99,7 +99,7 @@ public class BungeeSchedulerAdapter implements SchedulerAdapter {
@Override
public SchedulerTask asyncLater(Runnable runnable, long delayTicks) {
return new BungeeSchedulerTask(scheduler().schedule(this.plugin, runnable, ticksToMillis(delayTicks), TimeUnit.MILLISECONDS));
return new BungeeSchedulerTask(scheduler().schedule(this.bootstrap, runnable, ticksToMillis(delayTicks), TimeUnit.MILLISECONDS));
}
@Override
@@ -109,7 +109,7 @@ public class BungeeSchedulerAdapter implements SchedulerAdapter {
@Override
public void shutdown() {
SafeIteration.iterate(this.tasks, SchedulerTask::cancel);
Iterators.iterate(this.tasks, SchedulerTask::cancel);
}
private static final class BungeeSchedulerTask implements SchedulerTask {
@@ -27,15 +27,16 @@ package me.lucko.luckperms.bungee;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.bungee.event.TristateCheckEvent;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.commands.sender.SenderFactory;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.SenderFactory;
import me.lucko.luckperms.common.utils.TextUtils;
import net.kyori.text.Component;
import net.kyori.text.serializer.ComponentSerializers;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.chat.ComponentSerializer;
import java.util.UUID;
@@ -67,7 +68,7 @@ public class BungeeSenderFactory extends SenderFactory<CommandSender> {
@Override
protected void sendMessage(CommandSender sender, Component message) {
sender.sendMessage(net.md_5.bungee.chat.ComponentSerializer.parse(ComponentSerializers.JSON.serialize(message)));
sender.sendMessage(ComponentSerializer.parse(ComponentSerializers.JSON.serialize(message)));
}
@Override
@@ -0,0 +1,218 @@
/*
* 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.bungee;
import me.lucko.luckperms.api.platform.PlatformType;
import me.lucko.luckperms.bungee.util.RedisBungeeUtil;
import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader;
import me.lucko.luckperms.common.dependencies.classloader.ReflectionClassLoader;
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
import java.io.InputStream;
import java.nio.file.Path;
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.
*/
public class LPBungeeBootstrap extends Plugin implements LuckPermsBootstrap {
/**
* A scheduler adapter for the platform
*/
private final SchedulerAdapter schedulerAdapter;
/**
* The plugin classloader
*/
private final PluginClassLoader classLoader;
/**
* The plugin instance
*/
private final LPBungeePlugin plugin;
/**
* The time when the plugin was enabled
*/
private long startTime;
// load/enable latches
private final CountDownLatch loadLatch = new CountDownLatch(1);
private final CountDownLatch enableLatch = new CountDownLatch(1);
public LPBungeeBootstrap() {
this.schedulerAdapter = new BungeeSchedulerAdapter(this);
this.classLoader = new ReflectionClassLoader(this);
this.plugin = new LPBungeePlugin(this);
}
// provide adapters
@Override
public SchedulerAdapter getScheduler() {
return this.schedulerAdapter;
}
@Override
public PluginClassLoader getPluginClassLoader() {
return this.classLoader;
}
// lifecycle
@Override
public void onLoad() {
try {
this.plugin.load();
} finally {
this.loadLatch.countDown();
}
}
@Override
public void onEnable() {
this.startTime = System.currentTimeMillis();
try {
this.plugin.enable();
} finally {
this.enableLatch.countDown();
}
}
@Override
public void onDisable() {
this.plugin.disable();
}
@Override
public CountDownLatch getEnableLatch() {
return this.enableLatch;
}
@Override
public CountDownLatch getLoadLatch() {
return this.loadLatch;
}
// provide information about the plugin
@Override
public String getVersion() {
return getDescription().getVersion();
}
@Override
public long getStartupTime() {
return this.startTime;
}
// provide information about the platform
@Override
public PlatformType getType() {
return PlatformType.BUNGEE;
}
@Override
public String getServerBrand() {
return getProxy().getName();
}
@Override
public String getServerVersion() {
return getProxy().getVersion();
}
@Override
public Path getDataDirectory() {
return getDataFolder().toPath().toAbsolutePath();
}
@Override
public InputStream getResourceStream(String path) {
return getResourceAsStream(path);
}
@Override
public Optional<ProxiedPlayer> getPlayer(UUID uuid) {
return Optional.ofNullable(getProxy().getPlayer(uuid));
}
@Override
public Optional<UUID> lookupUuid(String username) {
if (getProxy().getPluginManager().getPlugin("RedisBungee") != null) {
try {
return RedisBungeeUtil.lookupUuid(username);
} catch (Throwable t) {
t.printStackTrace();
}
}
return Optional.empty();
}
@Override
public Optional<String> lookupUsername(UUID uuid) {
if (getProxy().getPluginManager().getPlugin("RedisBungee") != null) {
try {
return RedisBungeeUtil.lookupUsername(uuid);
} catch (Throwable t) {
t.printStackTrace();
}
}
return Optional.empty();
}
@Override
public int getPlayerCount() {
return getProxy().getOnlineCount();
}
@Override
public Stream<String> getPlayerList() {
return getProxy().getPlayers().stream().map(ProxiedPlayer::getName);
}
@Override
public Stream<UUID> getOnlinePlayers() {
return getProxy().getPlayers().stream().map(ProxiedPlayer::getUniqueId);
}
@Override
public boolean isPlayerOnline(UUID uuid) {
ProxiedPlayer player = getProxy().getPlayer(uuid);
return player != null && player.isConnected();
}
}
@@ -26,7 +26,7 @@
package me.lucko.luckperms.bungee;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.platform.PlatformType;
import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.bungee.calculators.BungeeCalculatorFactory;
import me.lucko.luckperms.bungee.contexts.BackendServerCalculator;
import me.lucko.luckperms.bungee.contexts.BungeeContextManager;
@@ -34,235 +34,148 @@ import me.lucko.luckperms.bungee.contexts.RedisBungeeCalculator;
import me.lucko.luckperms.bungee.listeners.BungeeConnectionListener;
import me.lucko.luckperms.bungee.listeners.BungeePermissionCheckListener;
import me.lucko.luckperms.bungee.messaging.BungeeMessagingFactory;
import me.lucko.luckperms.bungee.util.RedisBungeeUtil;
import me.lucko.luckperms.common.actionlog.LogDispatcher;
import me.lucko.luckperms.common.api.ApiRegistrationUtil;
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
import me.lucko.luckperms.common.buffers.BufferedRequest;
import me.lucko.luckperms.common.buffers.UpdateTaskBuffer;
import me.lucko.luckperms.common.caching.handlers.CachedStateManager;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.config.AbstractConfiguration;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
import me.lucko.luckperms.common.calculators.PlatformCalculatorFactory;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.config.adapter.ConfigurationAdapter;
import me.lucko.luckperms.common.contexts.ContextManager;
import me.lucko.luckperms.common.contexts.LuckPermsCalculator;
import me.lucko.luckperms.common.dependencies.DependencyManager;
import me.lucko.luckperms.common.dependencies.DependencyRegistry;
import me.lucko.luckperms.common.dependencies.classloader.PluginClassLoader;
import me.lucko.luckperms.common.dependencies.classloader.ReflectionClassLoader;
import me.lucko.luckperms.common.event.EventFactory;
import me.lucko.luckperms.common.inheritance.InheritanceHandler;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.NoopLocaleManager;
import me.lucko.luckperms.common.locale.SimpleLocaleManager;
import me.lucko.luckperms.common.logging.Logger;
import me.lucko.luckperms.common.logging.SenderLogger;
import me.lucko.luckperms.common.dependencies.Dependency;
import me.lucko.luckperms.common.event.AbstractEventBus;
import me.lucko.luckperms.common.listener.ConnectionListener;
import me.lucko.luckperms.common.managers.group.StandardGroupManager;
import me.lucko.luckperms.common.managers.track.StandardTrackManager;
import me.lucko.luckperms.common.managers.user.StandardUserManager;
import me.lucko.luckperms.common.messaging.InternalMessagingService;
import me.lucko.luckperms.common.messaging.MessagingFactory;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.plugin.SchedulerAdapter;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.storage.StorageFactory;
import me.lucko.luckperms.common.storage.StorageType;
import me.lucko.luckperms.common.storage.dao.file.FileWatcher;
import me.lucko.luckperms.common.plugin.AbstractLuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.tasks.CacheHousekeepingTask;
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
import me.lucko.luckperms.common.tasks.UpdateTask;
import me.lucko.luckperms.common.treeview.PermissionVault;
import me.lucko.luckperms.common.verbose.VerboseHandler;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.EnumSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
/**
* LuckPerms implementation for the BungeeCord API.
*/
public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
public class LPBungeePlugin extends AbstractLuckPermsPlugin {
private final LPBungeeBootstrap bootstrap;
private long startTime;
private SchedulerAdapter scheduler;
private BungeeSenderFactory senderFactory;
private BungeeConnectionListener connectionListener;
private CommandManager commandManager;
private LuckPermsConfiguration configuration;
private StandardUserManager userManager;
private StandardGroupManager groupManager;
private StandardTrackManager trackManager;
private Storage storage;
private FileWatcher fileWatcher = null;
private InternalMessagingService messagingService = null;
private LuckPermsApiProvider apiProvider;
private EventFactory eventFactory;
private Logger log;
private LocaleManager localeManager;
private PluginClassLoader pluginClassLoader;
private DependencyManager dependencyManager;
private InheritanceHandler inheritanceHandler;
private CachedStateManager cachedStateManager;
private ContextManager<ProxiedPlayer> contextManager;
private CalculatorFactory calculatorFactory;
private BufferedRequest<Void> updateTaskBuffer;
private VerboseHandler verboseHandler;
private BungeeSenderFactory senderFactory;
private PermissionVault permissionVault;
private LogDispatcher logDispatcher;
private Set<UUID> uniqueConnections = ConcurrentHashMap.newKeySet();
@Override
public void onLoad() {
// setup minimal functionality in order to load initial dependencies
this.scheduler = new BungeeSchedulerAdapter(this);
this.localeManager = new NoopLocaleManager();
this.senderFactory = new BungeeSenderFactory(this);
this.log = new SenderLogger(this, getConsoleSender());
this.pluginClassLoader = new ReflectionClassLoader(this);
this.dependencyManager = new DependencyManager(this);
this.dependencyManager.loadDependencies(DependencyRegistry.GLOBAL_DEPENDENCIES);
public LPBungeePlugin(LPBungeeBootstrap bootstrap) {
this.bootstrap = bootstrap;
}
@Override
public void onEnable() {
this.startTime = System.currentTimeMillis();
sendStartupBanner(getConsoleSender());
this.verboseHandler = new VerboseHandler(this.scheduler.async());
this.permissionVault = new PermissionVault(this.scheduler.async());
this.logDispatcher = new LogDispatcher(this);
public LPBungeeBootstrap getBootstrap() {
return this.bootstrap;
}
getLog().info("Loading configuration...");
this.configuration = new AbstractConfiguration(this, new BungeeConfigAdapter(this, resolveConfig("config.yml")));
this.configuration.loadAll();
@Override
protected void setupSenderFactory() {
this.senderFactory = new BungeeSenderFactory(this);
}
StorageFactory storageFactory = new StorageFactory(this);
Set<StorageType> storageTypes = storageFactory.getRequiredTypes(StorageType.H2);
this.dependencyManager.loadStorageDependencies(storageTypes);
@Override
protected Set<Dependency> getGlobalDependencies() {
return EnumSet.of(Dependency.CAFFEINE, Dependency.OKIO, Dependency.OKHTTP);
}
// register events
getProxy().getPluginManager().registerListener(this, new BungeeConnectionListener(this));
getProxy().getPluginManager().registerListener(this, new BungeePermissionCheckListener(this));
@Override
protected ConfigurationAdapter provideConfigurationAdapter() {
return new BungeeConfigAdapter(this, resolveConfig());
}
if (getConfiguration().get(ConfigKeys.WATCH_FILES)) {
this.fileWatcher = new FileWatcher(this);
getScheduler().asyncRepeating(this.fileWatcher, 30L);
}
@Override
protected void registerPlatformListeners() {
this.connectionListener = new BungeeConnectionListener(this);
this.bootstrap.getProxy().getPluginManager().registerListener(this.bootstrap, this.connectionListener);
this.bootstrap.getProxy().getPluginManager().registerListener(this.bootstrap, new BungeePermissionCheckListener(this));
}
// initialise datastore
this.storage = storageFactory.getInstance(StorageType.H2);
@Override
protected MessagingFactory<?> provideMessagingFactory() {
return new BungeeMessagingFactory(this);
}
// initialise messaging
this.messagingService = new BungeeMessagingFactory(this).getInstance();
// setup the update task buffer
this.updateTaskBuffer = new UpdateTaskBuffer(this);
// load locale
this.localeManager = new SimpleLocaleManager();
this.localeManager.tryLoad(this, new File(getDataFolder(), "lang.yml"));
// register commands
@Override
protected void registerCommands() {
this.commandManager = new CommandManager(this);
getProxy().getPluginManager().registerCommand(this, new BungeeCommandExecutor(this, this.commandManager));
this.bootstrap.getProxy().getPluginManager().registerCommand(this.bootstrap, new BungeeCommandExecutor(this, this.commandManager));
// disable the default Bungee /perms command so it gets handled by the Bukkit plugin
getProxy().getDisabledCommands().add("perms");
this.bootstrap.getProxy().getDisabledCommands().add("perms");
}
// load internal managers
getLog().info("Loading internal permission managers...");
this.inheritanceHandler = new InheritanceHandler(this);
@Override
protected void setupManagers() {
this.userManager = new StandardUserManager(this);
this.groupManager = new StandardGroupManager(this);
this.trackManager = new StandardTrackManager(this);
this.calculatorFactory = new BungeeCalculatorFactory(this);
this.cachedStateManager = new CachedStateManager();
// setup context manager
this.contextManager = new BungeeContextManager(this);
this.contextManager.registerCalculator(new BackendServerCalculator(this));
this.contextManager.registerStaticCalculator(new LuckPermsCalculator(getConfiguration()));
if (getProxy().getPluginManager().getPlugin("RedisBungee") != null) {
this.contextManager.registerStaticCalculator(new RedisBungeeCalculator());
}
// register with the LP API
this.apiProvider = new LuckPermsApiProvider(this);
// setup event factory
this.eventFactory = new EventFactory(this, this.apiProvider);
ApiRegistrationUtil.registerProvider(this.apiProvider);
// schedule update tasks
int mins = getConfiguration().get(ConfigKeys.SYNC_TIME);
if (mins > 0) {
long ticks = mins * 60 * 20;
this.scheduler.asyncRepeating(() -> this.updateTaskBuffer.request(), ticks);
}
this.scheduler.asyncLater(() -> this.updateTaskBuffer.request(), 40L);
// run an update instantly.
getLog().info("Performing initial data load...");
try {
new UpdateTask(this, true).run();
} catch (Exception e) {
e.printStackTrace();
}
// register tasks
this.scheduler.asyncRepeating(new ExpireTemporaryTask(this), 60L);
this.scheduler.asyncRepeating(new CacheHousekeepingTask(this), 2400L);
getLog().info("Successfully enabled. (took " + (System.currentTimeMillis() - this.startTime) + "ms)");
}
@Override
public void onDisable() {
this.permissionVault.shutdown();
this.verboseHandler.shutdown();
getLog().info("Closing storage...");
this.storage.shutdown();
if (this.fileWatcher != null) {
this.fileWatcher.close();
}
if (this.messagingService != null) {
getLog().info("Closing messaging service...");
this.messagingService.close();
}
ApiRegistrationUtil.unregisterProvider();
getLog().info("Shutting down internal scheduler...");
this.scheduler.shutdown();
getProxy().getScheduler().cancel(this);
getProxy().getPluginManager().unregisterListeners(this);
getLog().info("Goodbye!");
protected PlatformCalculatorFactory provideCalculatorFactory() {
return new BungeeCalculatorFactory(this);
}
private File resolveConfig(String file) {
File configFile = new File(getDataFolder(), file);
@Override
protected void setupContextManager() {
this.contextManager = new BungeeContextManager(this);
this.contextManager.registerCalculator(new BackendServerCalculator(this));
if (this.bootstrap.getProxy().getPluginManager().getPlugin("RedisBungee") != null) {
this.contextManager.registerStaticCalculator(new RedisBungeeCalculator());
}
}
@Override
protected void setupPlatformHooks() {
}
@Override
protected AbstractEventBus provideEventBus(LuckPermsApiProvider apiProvider) {
return new BungeeEventBus(this, apiProvider);
}
@Override
protected void registerApiOnPlatform(LuckPermsApi api) {
// BungeeCord doesn't have a services manager
}
@Override
protected void registerHousekeepingTasks() {
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 60L);
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2400L);
}
@Override
protected void performFinalSetup() {
}
private File resolveConfig() {
File configFile = new File(this.bootstrap.getDataFolder(), "config.yml");
if (!configFile.exists()) {
getDataFolder().mkdirs();
try (InputStream is = getResourceAsStream(file)) {
this.bootstrap.getDataFolder().mkdirs();
try (InputStream is = this.bootstrap.getResourceAsStream("config.yml")) {
Files.copy(is, configFile.toPath());
} catch (IOException e) {
throw new RuntimeException(e);
@@ -272,122 +185,31 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
return configFile;
}
@Override
public Optional<InternalMessagingService> getMessagingService() {
return Optional.ofNullable(this.messagingService);
}
@Override
public void setMessagingService(InternalMessagingService messagingService) {
if (this.messagingService == null) {
this.messagingService = messagingService;
}
}
@Override
public Optional<FileWatcher> getFileWatcher() {
return Optional.ofNullable(this.fileWatcher);
}
@Override
public String getVersion() {
return getDescription().getVersion();
}
@Override
public PlatformType getServerType() {
return PlatformType.BUNGEE;
}
@Override
public String getServerBrand() {
return getProxy().getName();
}
@Override
public String getServerVersion() {
return getProxy().getVersion();
}
@Override
public File getDataDirectory() {
return super.getDataFolder();
}
@Override
public InputStream getResourceStream(String path) {
return getResourceAsStream(path);
}
@Override
public ProxiedPlayer getPlayer(User user) {
return getProxy().getPlayer(user.getUuid());
}
@Override
public Optional<UUID> lookupUuid(String username) {
if (getProxy().getPluginManager().getPlugin("RedisBungee") != null) {
try {
return RedisBungeeUtil.lookupUuid(username);
} catch (Throwable t) {
t.printStackTrace();
}
}
return Optional.empty();
}
@Override
public Optional<Contexts> getContextForUser(User user) {
ProxiedPlayer player = getPlayer(user);
if (player == null) {
return Optional.empty();
}
return Optional.of(this.contextManager.getApplicableContexts(player));
}
@Override
public int getPlayerCount() {
return getProxy().getOnlineCount();
}
@Override
public Stream<String> getPlayerList() {
return getProxy().getPlayers().stream().map(ProxiedPlayer::getName);
}
@Override
public Stream<UUID> getOnlinePlayers() {
return getProxy().getPlayers().stream().map(ProxiedPlayer::getUniqueId);
}
@Override
public boolean isPlayerOnline(UUID external) {
ProxiedPlayer player = getProxy().getPlayer(external);
return player != null && player.isConnected();
return this.bootstrap.getPlayer(user.getUuid()).map(player -> this.contextManager.getApplicableContexts(player));
}
@Override
public Stream<Sender> getOnlineSenders() {
return Stream.concat(
Stream.of(getConsoleSender()),
getProxy().getPlayers().stream().map(p -> getSenderFactory().wrap(p))
this.bootstrap.getProxy().getPlayers().stream().map(p -> this.senderFactory.wrap(p))
);
}
@Override
public Sender getConsoleSender() {
return getSenderFactory().wrap(getProxy().getConsole());
return this.senderFactory.wrap(this.bootstrap.getProxy().getConsole());
}
public BungeeSenderFactory getSenderFactory() {
return this.senderFactory;
}
@Override
public long getStartTime() {
return this.startTime;
}
@Override
public SchedulerAdapter getScheduler() {
return this.scheduler;
public ConnectionListener getConnectionListener() {
return this.connectionListener;
}
@Override
@@ -395,11 +217,6 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
return this.commandManager;
}
@Override
public LuckPermsConfiguration getConfiguration() {
return this.configuration;
}
@Override
public StandardUserManager getUserManager() {
return this.userManager;
@@ -415,87 +232,9 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
return this.trackManager;
}
@Override
public Storage getStorage() {
return this.storage;
}
@Override
public LuckPermsApiProvider getApiProvider() {
return this.apiProvider;
}
@Override
public EventFactory getEventFactory() {
return this.eventFactory;
}
@Override
public Logger getLog() {
return this.log;
}
@Override
public LocaleManager getLocaleManager() {
return this.localeManager;
}
@Override
public PluginClassLoader getPluginClassLoader() {
return this.pluginClassLoader;
}
@Override
public DependencyManager getDependencyManager() {
return this.dependencyManager;
}
@Override
public CachedStateManager getCachedStateManager() {
return this.cachedStateManager;
}
@Override
public ContextManager<ProxiedPlayer> getContextManager() {
return this.contextManager;
}
@Override
public InheritanceHandler getInheritanceHandler() {
return this.inheritanceHandler;
}
@Override
public CalculatorFactory getCalculatorFactory() {
return this.calculatorFactory;
}
@Override
public BufferedRequest<Void> getUpdateTaskBuffer() {
return this.updateTaskBuffer;
}
@Override
public VerboseHandler getVerboseHandler() {
return this.verboseHandler;
}
public BungeeSenderFactory getSenderFactory() {
return this.senderFactory;
}
@Override
public PermissionVault getPermissionVault() {
return this.permissionVault;
}
@Override
public LogDispatcher getLogDispatcher() {
return this.logDispatcher;
}
@Override
public Set<UUID> getUniqueConnections() {
return this.uniqueConnections;
}
}
@@ -40,7 +40,7 @@ public class BungeeContextManager extends AbstractContextManager<ProxiedPlayer>
@Override
public Contexts formContexts(ProxiedPlayer subject, ImmutableContextSet contextSet) {
return new Contexts(
return Contexts.of(
contextSet,
this.plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
this.plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
@@ -29,26 +29,46 @@ import me.lucko.luckperms.api.Tristate;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Event;
import java.util.Objects;
/**
* Copy of the internal BungeeCord PermissionCheckEvent, returning a tristate instead of a boolean.
*/
public class TristateCheckEvent extends Event {
public static Tristate call(CommandSender sender, String permission) {
return ProxyServer.getInstance().getPluginManager().callEvent(new TristateCheckEvent(sender, permission)).getResult();
// calculate a default value based on the internal behaviour of
// ConsoleCommandSender and UserConnection in order to replicate the
// behaviour of CommandSender#hasPermission
Tristate def = Tristate.UNDEFINED;
if (!(sender instanceof ProxiedPlayer)) {
// if not a ProxiedPlayer, assume it's console.
def = Tristate.TRUE;
} else if (sender.getPermissions().contains(permission)) {
def = Tristate.TRUE;
}
return call(sender, permission, def);
}
public static Tristate call(CommandSender sender, String permission, Tristate def) {
Objects.requireNonNull(sender, "sender");
Objects.requireNonNull(permission, "permission");
Objects.requireNonNull(def, "def");
TristateCheckEvent event = new TristateCheckEvent(sender, permission, def);
return ProxyServer.getInstance().getPluginManager().callEvent(event).getResult();
}
private final CommandSender sender;
private final String permission;
private Tristate result;
public TristateCheckEvent(CommandSender sender, String permission) {
this(sender, permission, sender.getPermissions().contains(permission) ? Tristate.TRUE : Tristate.UNDEFINED);
}
public TristateCheckEvent(CommandSender sender, String permission, Tristate result) {
private TristateCheckEvent(CommandSender sender, String permission, Tristate result) {
this.sender = sender;
this.permission = permission;
this.result = result;
@@ -27,9 +27,9 @@ package me.lucko.luckperms.bungee.listeners;
import me.lucko.luckperms.bungee.LPBungeePlugin;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.listener.AbstractConnectionListener;
import me.lucko.luckperms.common.locale.message.Message;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.utils.AbstractLoginListener;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.PendingConnection;
@@ -43,7 +43,7 @@ import net.md_5.bungee.event.EventPriority;
import java.util.concurrent.TimeUnit;
public class BungeeConnectionListener extends AbstractLoginListener implements Listener {
public class BungeeConnectionListener extends AbstractConnectionListener implements Listener {
private final LPBungeePlugin plugin;
public BungeeConnectionListener(LPBungeePlugin plugin) {
@@ -62,16 +62,16 @@ public class BungeeConnectionListener extends AbstractLoginListener implements L
/* registers the plugins intent to modify this events state going forward.
this will prevent the event from completing until we're finished handling. */
e.registerIntent(this.plugin);
e.registerIntent(this.plugin.getBootstrap());
final PendingConnection c = e.getConnection();
if (this.plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
this.plugin.getLog().info("Processing pre-login for " + c.getUniqueId() + " - " + c.getName());
this.plugin.getLogger().info("Processing pre-login for " + c.getUniqueId() + " - " + c.getName());
}
this.plugin.getScheduler().doAsync(() -> {
this.plugin.getUniqueConnections().add(c.getUniqueId());
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
recordConnection(c.getUniqueId());
/* Actually process the login for the connection.
We do this here to delay the login until the data is ready.
@@ -86,7 +86,7 @@ public class BungeeConnectionListener extends AbstractLoginListener implements L
User user = loadUser(c.getUniqueId(), c.getName());
this.plugin.getEventFactory().handleUserLoginProcess(c.getUniqueId(), c.getName(), user);
} catch (Exception ex) {
this.plugin.getLog().severe("Exception occurred whilst loading data for " + c.getUniqueId() + " - " + c.getName());
this.plugin.getLogger().severe("Exception occurred whilst loading data for " + c.getUniqueId() + " - " + c.getName());
ex.printStackTrace();
// there was some error loading
@@ -98,7 +98,7 @@ public class BungeeConnectionListener extends AbstractLoginListener implements L
}
// finally, complete our intent to modify state, so the proxy can continue handling the connection.
e.completeIntent(this.plugin);
e.completeIntent(this.plugin.getBootstrap());
});
}
@@ -108,17 +108,17 @@ public class BungeeConnectionListener extends AbstractLoginListener implements L
final User user = this.plugin.getUserManager().getIfLoaded(e.getPlayer().getUniqueId());
if (this.plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
this.plugin.getLog().info("Processing post-login for " + player.getUniqueId() + " - " + player.getName());
this.plugin.getLogger().info("Processing post-login for " + player.getUniqueId() + " - " + player.getName());
}
if (user == null) {
if (this.plugin.getConfiguration().get(ConfigKeys.CANCEL_FAILED_LOGINS)) {
// disconnect the user
this.plugin.getLog().warn("User " + player.getUniqueId() + " - " + player.getName() + " doesn't have data pre-loaded - cancelling login.");
this.plugin.getLogger().warn("User " + player.getUniqueId() + " - " + player.getName() + " doesn't have data pre-loaded - cancelling login.");
e.getPlayer().disconnect(TextComponent.fromLegacyText(Message.LOADING_ERROR.asString(this.plugin.getLocaleManager())));
} else {
// just send a message
this.plugin.getProxy().getScheduler().schedule(this.plugin, () -> {
this.plugin.getBootstrap().getProxy().getScheduler().schedule(this.plugin.getBootstrap(), () -> {
if (!player.isConnected()) {
return;
}
@@ -139,7 +139,7 @@ public class BungeeConnectionListener extends AbstractLoginListener implements L
this.plugin.getUserManager().getHouseKeeper().registerUsage(player.getUniqueId());
// force a clear of transient nodes
this.plugin.getScheduler().doAsync(() -> {
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
User user = this.plugin.getUserManager().getIfLoaded(player.getUniqueId());
if (user != null) {
user.clearTransientNodes();
@@ -115,6 +115,23 @@ public class BungeePermissionCheckListener implements Listener {
String name = "internal/" + e.getSender().getName();
this.plugin.getVerboseHandler().offerCheckData(CheckOrigin.PLATFORM_PERMISSION_CHECK, name, ContextSet.empty(), permission, result);
this.plugin.getPermissionVault().offer(permission);
this.plugin.getPermissionRegistry().offer(permission);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onOtherTristateCheck(TristateCheckEvent e) {
if (e.getSender() instanceof ProxiedPlayer) {
return;
}
Objects.requireNonNull(e.getPermission(), "permission");
Objects.requireNonNull(e.getSender(), "sender");
String permission = e.getPermission();
Tristate result = e.getResult();
String name = "internal/" + e.getSender().getName();
this.plugin.getVerboseHandler().offerCheckData(CheckOrigin.PLATFORM_LOOKUP_CHECK, name, ContextSet.empty(), permission, result);
this.plugin.getPermissionRegistry().offer(permission);
}
}
@@ -49,8 +49,8 @@ public class BungeeMessagingFactory extends MessagingFactory<LPBungeePlugin> {
e.printStackTrace();
}
} else if (messagingType.equals("redisbungee")) {
if (getPlugin().getProxy().getPluginManager().getPlugin("RedisBungee") == null) {
getPlugin().getLog().warn("RedisBungee plugin not present.");
if (getPlugin().getBootstrap().getProxy().getPluginManager().getPlugin("RedisBungee") == null) {
getPlugin().getLogger().warn("RedisBungee plugin not present.");
} else {
try {
return new LuckPermsMessagingService(getPlugin(), new RedisBungeeMessengerProvider());
@@ -57,13 +57,13 @@ public class BungeeMessenger implements Messenger, Listener {
}
public void init() {
this.plugin.getProxy().getPluginManager().registerListener(this.plugin, this);
this.plugin.getProxy().registerChannel(CHANNEL);
this.plugin.getBootstrap().getProxy().getPluginManager().registerListener(this.plugin.getBootstrap(), this);
this.plugin.getBootstrap().getProxy().registerChannel(CHANNEL);
}
@Override
public void close() {
this.plugin.getProxy().unregisterChannel(CHANNEL);
this.plugin.getBootstrap().getProxy().unregisterChannel(CHANNEL);
}
@Override
@@ -73,7 +73,7 @@ public class BungeeMessenger implements Messenger, Listener {
byte[] data = out.toByteArray();
for (ServerInfo server : this.plugin.getProxy().getServers().values()) {
for (ServerInfo server : this.plugin.getBootstrap().getProxy().getServers().values()) {
server.sendData(CHANNEL, data, true);
}
}
@@ -97,8 +97,8 @@ public class BungeeMessenger implements Messenger, Listener {
if (this.consumer.consumeIncomingMessageAsString(msg)) {
// Forward to other servers
this.plugin.getScheduler().doAsync(() -> {
for (ServerInfo server : this.plugin.getProxy().getServers().values()) {
this.plugin.getBootstrap().getScheduler().doAsync(() -> {
for (ServerInfo server : this.plugin.getBootstrap().getProxy().getServers().values()) {
server.sendData(CHANNEL, data, true);
}
});
@@ -58,7 +58,7 @@ public class RedisBungeeMessenger implements Messenger, Listener {
this.redisBungee = RedisBungee.getApi();
this.redisBungee.registerPubSubChannels(CHANNEL);
this.plugin.getProxy().getPluginManager().registerListener(this.plugin, this);
this.plugin.getBootstrap().getProxy().getPluginManager().registerListener(this.plugin.getBootstrap(), this);
}
@Override
@@ -66,7 +66,7 @@ public class RedisBungeeMessenger implements Messenger, Listener {
this.redisBungee.unregisterPubSubChannels(CHANNEL);
this.redisBungee = null;
this.plugin.getProxy().getPluginManager().unregisterListener(this);
this.plugin.getBootstrap().getProxy().getPluginManager().unregisterListener(this);
}
@Override
@@ -26,19 +26,19 @@
package me.lucko.luckperms.bungee.migration;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.CommandPermission;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
import me.lucko.luckperms.common.commands.impl.migration.MigrationUtils;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.command.CommandResult;
import me.lucko.luckperms.common.command.abstraction.SubCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.commands.migration.MigrationUtils;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.logging.ProgressLogger;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.utils.Iterators;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.SafeIteration;
import net.alpenblock.bungeeperms.BungeePerms;
import net.alpenblock.bungeeperms.Group;
@@ -52,7 +52,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class MigrationBungeePerms extends SubCommand<Object> {
public MigrationBungeePerms(LocaleManager locale) {
super(CommandSpec.MIGRATION_COMMAND.spec(locale), "bungeeperms", CommandPermission.MIGRATION, Predicates.alwaysFalse());
super(CommandSpec.MIGRATION_COMMAND.localize(locale), "bungeeperms", CommandPermission.MIGRATION, Predicates.alwaysFalse());
}
@Override
@@ -66,7 +66,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
// Get BungeePerms instance
BungeePerms bp = BungeePerms.getInstance();
if (bp == null) {
log.logErr("Plugin not loaded.");
log.logError("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
@@ -82,7 +82,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
// Migrate all groups.
log.log("Starting group migration.");
AtomicInteger groupCount = new AtomicInteger(0);
SafeIteration.iterate(groups, g -> {
Iterators.iterate(groups, g -> {
int groupWeight = maxWeight - g.getRank();
// Make a LuckPerms group for the one being migrated
@@ -104,9 +104,9 @@ public class MigrationBungeePerms extends SubCommand<Object> {
// Increment the max weight from the group migrations. All user meta should override.
int userWeight = maxWeight + 5;
SafeIteration.iterate(bp.getPermissionsManager().getBackEnd().loadUsers(), u -> {
Iterators.iterate(bp.getPermissionsManager().getBackEnd().loadUsers(), u -> {
if (u.getUUID() == null) {
log.logErr("Could not parse UUID for user: " + u.getName());
log.logError("Could not parse UUID for user: " + u.getName());
return;
}
@@ -39,7 +39,11 @@ public final class RedisBungeeUtil {
* @return a uuid, if present
*/
public static Optional<UUID> lookupUuid(String username) {
return Optional.ofNullable(RedisBungee.getApi()).flatMap(a -> Optional.ofNullable(a.getUuidFromName(username, true)));
return Optional.ofNullable(RedisBungee.getApi()).map(a -> a.getUuidFromName(username, true));
}
public static Optional<String> lookupUsername(UUID uuid) {
return Optional.ofNullable(RedisBungee.getApi()).map(a -> a.getNameFromUuid(uuid, true));
}
private RedisBungeeUtil() {}
+387 -248
View File
@@ -18,158 +18,320 @@
####################################################################################################
# +----------------------------------------------------------------------------------------------+ #
# | General | #
# | | #
# | ESSENTIAL SETTINGS | #
# | | #
# | Important settings that control how LuckPerms functions. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# The name of the server, used for server specific permissions. Set to 'global' to disable.
# The name of the server, used for server specific permissions.
#
# - When set to "global" this setting is effectively ignored.
# - In all other cases, the value here is added to all players in a "server" context.
# - See: https://github.com/lucko/LuckPerms/wiki/Context
server: bungee
# If users on this server should have their global permissions applied.
# If set to false, only server specific permissions will apply for users on this server
include-global: true
# If users on this server should have their global world permissions applied.
# If set to false, only world specific permissions will apply for users on this server
include-global-world: true
# If users on this server should have global (non-server specific) groups applied
apply-global-groups: true
# If users on this server should have global (non-world specific) groups applied
apply-global-world-groups: true
# If the servers own UUID cache/lookup facility should be used when there is no record for a player
# in the LuckPerms cache.
# already in LuckPerms.
#
# Since BungeeCord doesn't maintain it's own UUID cache, when this option is true, LuckPerms will
# try to find a uuid for a username using RedisBungee, if installed.
# - Since BungeeCord doesn't maintain it's own UUID cache, when this option is true, LuckPerms will
# try to find a uuid for a username using RedisBungee, if installed.
use-server-uuid-cache: false
# If set to true, LuckPerms will allow usernames with non alphanumeric characters.
#
# Note that due to the design of the storage implementation, usernames must still be
# 16 characters or less.
allow-invalid-usernames: false
# If LuckPerms should produce extra logging output when it handles logins.
# Useful if you're having issues with UUID forwarding or data not being loaded.
debug-logins: false
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | STORAGE SETTINGS | #
# | | #
# | Controls which storage method LuckPerms will use to store data. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# 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
#
# - Possible options:
#
# | Remote databases - require connection information to be configured below
# |=> MySQL
# |=> MariaDB (preferred over MySQL)
# |=> PostgreSQL
# |=> MongoDB
#
# | Flatfile/local database - don't require any extra configuration
# |=> H2 (preferred over SQLite)
# |=> SQLite
#
# | Readable & editable text files - don't require any extra configuration
# |=> YAML (.yml files)
# |=> JSON (.json files)
# |=> HOCON (.conf files)
# |=> TOML (.toml files)
# |
# | By default, user, group and track data is separated into different files. Data can be combined
# | and all stored in the same file by switching to a combined storage variant.
# | Just add '-combined' to the end of the storage-method, e.g. 'yaml-combined'
#
# - A H2 database is the default option.
# - If you want to edit data manually in "traditional" storage files, we suggest using YAML.
storage-method: h2
# The following block defines the settings for remote database storage methods.
#
# - You don't need to touch any of the settings here if you're using a local storage method!
# - The connection detail options are shared between all remote storage types.
data:
# Define the address and port for the database.
# - The standard DB engine port is used by default
# (MySQL: 3306, PostgreSQL: 5432, MongoDB: 27017)
# - Specify as "host:port" if differs
address: localhost
# The name of the database to store LuckPerms data in.
# - This must be created already. Don't worry about this setting if you're using MongoDB.
database: minecraft
# Credentials for the database.
username: root
password: ''
# These settings apply to the MySQL connection pool.
# - The default values will be suitable for the majority of users.
# - Do not change these settings unless you know what you're doing!
pool-settings:
# Sets the maximum size of the MySQL connection pool.
# - Basically this value will determine the maximum number of actual
# connections to the database backend.
# - More information about determining the size of connection pools can be found here:
# https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
maximum-pool-size: 10
# Sets the minimum number of idle connections that the pool will try to maintain.
# - For maximum performance and responsiveness to spike demands, it is recommended to not set
# this value and instead allow the pool to act as a fixed size connection pool.
# (set this value to the same as 'maximum-pool-size')
minimum-idle: 10
# This setting controls the maximum lifetime of a connection in the pool in milliseconds.
# - The value should be at least 30 seconds less than any database or infrastructure imposed
# connection time limit.
maximum-lifetime: 1800000 # 30 minutes
# This setting controls the maximum number of milliseconds that the plugin will wait for a
# connection from the pool, before timing out.
connection-timeout: 5000 # 5 seconds
# This setting allows you to define extra properties for connections.
properties:
useUnicode: true
characterEncoding: utf8
# The prefix for all LuckPerms SQL tables.
# - Change this is 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 ClientConnectionURI for use with replica sets and custom connection options
# - See https://docs.mongodb.com/manual/reference/connection-string/
mongodb_connection_URI: ''
# Define settings for a "split" storage setup.
#
# - This allows you to define a storage method for each type of data.
# - The connection options above still have to be correct for each type here.
split-storage:
# Don't touch this if you don't want to use split storage!
enabled: false
methods:
# These options don't need to be modified if split storage isn't enabled.
user: h2
group: h2
track: h2
uuid: h2
log: h2
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | UPDATE PROPAGATION & MESSAGING SERVICE | #
# | | #
# | Controls the ways in which LuckPerms will sync data & notify other servers of changes. | #
# | These options are documented on greater detail on the wiki under "Instant Updates". | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# This option controls how frequently LuckPerms will perform a sync task.
#
# - A sync task will refresh all data from the storage, and ensure that the most up-to-date data is
# being used by the plugin.
# - This is disabled by default, as most users will not need it. However, if you're using a remote
# storage type without a messaging service setup, you may wish to set this to something like 3.
# - Set to -1 to disable the task completely.
sync-minutes: -1
# If the file watcher should be enabled.
#
# - When using a file-based storage type, LuckPerms can monitor the data files for changes, and
# automatically update when changes are detected.
# - If you don't want this feature to be active, set this option to false.
watch-files: true
# Define which messaging service should be used by the plugin.
#
# - If enabled and configured, LuckPerms will use the messaging service to inform other connected
# servers of changes.
# - Use the command "/lp networksync" to manually push changes.
# - Data is NOT stored using this service. It is only used as a messaging platform.
#
# - If you decide to enable this feature, you should set "sync-minutes" to -1, as there is no need
# for LuckPerms to poll the database for changes.
#
# - 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.
# => bungee 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 BungeeCord proxy.
# => redis Uses Redis pub-sub to push changes. Your server connection info must be
# configured below.
# => redisbungee Uses Redis pub-sub to push changes, using the RedisBungee API. You need to have
# the RedisBungee plugin installed.
# => none Disables the service.
messaging-service: none
# If LuckPerms should automatically push updates after a change has been made with a command.
auto-push-updates: true
# If LuckPerms should push logging entries to connected servers via the messaging service.
push-log-entries: true
# If LuckPerms should broadcast received logging entries to players on this platform.
#
# - If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you
# should set this option to false on either your backends or your proxies, to avoid players being
# messaged twice about log entries.
broadcast-received-log-entries: false
# Settings for Redis.
# Port 6379 is used by default; set address to "host:port" if differs
redis:
enabled: false
address: localhost
password: ''
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | CUSTOMIZATION SETTINGS | #
# | | #
# | Settings that allow admins to customize the way LuckPerms operates. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# If LuckPerms should ensure all players have permission data when they connect to the server.
#
# When set to true, LuckPerms will cancel login attempts if it is unable to load permissions data
# for a user, of if the storage provider is unavailable.
#
# When set to false, LuckPerms will allow a player to connect regardless of whether their
# permissions data could be loaded.
#
# This option does not exist on other platforms, and effectively defaults to true - however,
# the option is provided on BungeeCord, as it is less likely to be so dependant on permissions.
# - When set to true, LuckPerms will cancel login attempts if it is unable to load permissions data
# for a user, of if the storage provider is unavailable.
# - When set to false, LuckPerms will allow a player to connect regardless of whether their
# permissions data could be loaded.
# - This option does not exist on other platforms, and effectively defaults to true - however,
# the option is provided on BungeeCord, as it is less likely to be so dependant on permissions.
cancel-failed-logins: false
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in
# this list, the value assigned will be sent forward for permission calculation instead.
world-rewrite:
# world_nether: world
# world_the_end: world
# Controls how temporary permissions/parents/meta should be accumulated
# Controls how temporary permissions/parents/meta should be accumulated.
#
# The default behaviour is "deny"
# If "accumulate": durations will be added to the existing expiry time
# If "replace": durations will be replaced if the new duration is later than the current expiration
# If "deny": the command will just fail if you try to add another node with the same expiry
# - The default behaviour is "deny".
# - This behaviour can also be specified when the command is executed. See the command usage
# documentation for more info.
#
# - Possible options:
# => accumulate durations will be added to the existing expiry time
# => replace durations will be replaced if the new duration is later than the current
# expiration
# => deny the command will just fail if you try to add another node with the same expiry
temporary-add-behaviour: deny
# How should LuckPerms determine a users "primary" group.
# Controls how LuckPerms will determine a users "primary" group.
#
# Available Options:
# -> stored use the value stored against the users record in the file/database
# -> parents-by-weight just use the users most highly weighted parent
# -> all-parents-by-weight same as above, but calculates based upon all parents inherited from both
# directly and indirectly
# - The meaning and influence of "primary groups" are explained in detail on the wiki.
# - The preferred approach is to let LuckPerms automatically determine a users primary group
# based on the relative weight of their parent groups.
#
# - Possible options:
# => stored use the value stored against the users record in the file/database
# => parents-by-weight just use the users most highly weighted parent
# => all-parents-by-weight same as above, but calculates based upon all parents inherited from
# both directly and indirectly
primary-group-calculation: parents-by-weight
# If set to false, the plugin will allow a Users primary group to be removed with the
# 'parent remove' command, and will set their primary group back to default.
prevent-primary-group-removal: false
# If the plugin should check for "extra" permissions with users run LP commands.
#
# These extra permissions allow finer control over what users can do with each command, and
# who they have access to edit.
#
# The permissions are *not* static, unlike the 'base' permisssions, and will depend upon the
# arguments given within the command.
# - These extra permissions allow finer control over what users can do with each command, and who
# they have access to edit.
# - The nature of the checks are documented on the wiki under "Argument based command permissions".
# - Argument based permissions are *not* static, unlike the 'base' permissions, and will depend upon
# the arguments given within the command.
argument-based-command-permissions: false
# +----------------------------------------------------------------------------------------------+ #
# | Permission Calculation | #
# +----------------------------------------------------------------------------------------------+ #
# If the plugin should apply wildcard permissions.
# If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered
# permissions matching the wildcard.
apply-wildcards: true
# If the plugin should parse regex permissions.
# If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the
# node, and resolve & apply all registered permissions matching the regex.
apply-regex: true
# If the plugin should complete and apply shorthand permissions.
# If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# If the plugin should apply the permissions & groups defined in the BungeeCord config.yml
# If set to false, LuckPerms will ignore these values.
apply-bungee-config-permissions: false
# The algorithm LuckPerms should use when traversing the "inheritance tree".
# If the plugin should send log notifications to users whenever permissions are modified.
#
# The valid options are:
# - breadth-first
# - depth-first-pre-order
# - depth-first-post-order
# - Notifications are only sent to those with the appropriate permission to receive them
# - They can also be temporarily enabled/disabled on a per-user basis using
# '/lp log notify <on|off>'
log-notify: true
# Defines the options for prefix and suffix stacking.
#
# See here for information about the differences between each algorithm.
# - https://en.wikipedia.org/wiki/Breadth-first_search
# - https://en.wikipedia.org/wiki/Depth-first_search
inheritance-traversal-algorithm: depth-first-pre-order
# Define special group weights for this server.
# Default is just 0.
group-weight:
# admin: 10
# +----------------------------------------------------------------------------------------------+ #
# | Meta Formatting & Stacking | #
# +----------------------------------------------------------------------------------------------+ #
# Allows you to setup prefix/suffix stacking options.
# - The feature allows you to display multiple prefixes or suffixes alongside a players username in
# chat.
# - It is explained and documented in more detail on the wiki under "Prefix & Suffix Stacking".
#
# Available formats:
# - highest
# - lowest
# - highest_own
# - lowest_own
# - highest_inherited
# - lowest_inherited
# - highest_on_track_<track>
# - lowest_on_track_<track>
# - highest_not_on_track_<track>
# - lowest_not_on_track_<track>
# - The options are divided into separate sections for prefixes and suffixes.
# - The value of 'start-spacer' is included at the start of the resultant prefix/suffix.
# - The value of 'end-spacer' is included at the end of the resultant prefix/suffix.
# - The value of 'middle-spacer' is included between each element in the resultant prefix/suffix.
#
# Each element is added in the order listed.
# - Possible format options:
# => highest Selects the value with the highest weight, from all values
# held by or inherited by the player.
#
# => lowest Same as above, except takes the one with the lowest weight.
#
# => highest_own Selects the value with the highest weight, but will not
# accept any inherited values.
#
# => lowest_own Same as above, except takes the value with the lowest weight.
#
# => highest_inherited Selects the value with the highest weight, but will only
# accept inherited values.
#
# => lowest_inherited Same as above, except takes the value with the lowest weight.
#
# => highest_on_track_<track> Selects the value with the highest weight, but only if the
# value was inherited from a group on the given track.
#
# => lowest_on_track_<track> Same as above, except takes the value with the lowest weight.
#
# => highest_not_on_track_<track> Selects the value with the highest weight, but only if the
# 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.
meta-formatting:
prefix:
format:
@@ -188,147 +350,124 @@ meta-formatting:
# +----------------------------------------------------------------------------------------------+ #
# | Storage | #
# | | #
# | PERMISSION CALCULATION AND INHERITANCE | #
# | | #
# | Modify the way permission checks, meta lookups and inheritance resolutions are handled. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# Which storage method the plugin should use.
# The algorithm LuckPerms should use when traversing the "inheritance tree".
#
# See: https://github.com/lucko/LuckPerms/wiki/Choosing-a-Storage-type
# Currently supported: mysql, mariadb, postgresql, sqlite, h2, json, yaml, hocon, mongodb
# - Possible options:
# => breadth-first See: https://en.wikipedia.org/wiki/Breadth-first_search
# => depth-first-pre-order See: https://en.wikipedia.org/wiki/Depth-first_search
# => depth-first-post-order See: https://en.wikipedia.org/wiki/Depth-first_search
inheritance-traversal-algorithm: depth-first-pre-order
# +----------------------------------------------------------------------------------------------+ #
# | Permission resolution settings | #
# +----------------------------------------------------------------------------------------------+ #
# If users on this server should have their global permissions applied.
# When set to false, only server specific permissions will apply for users on this server
include-global: true
# If users on this server should have their global world permissions applied.
# When set to false, only world specific permissions will apply for users on this server
include-global-world: true
# If users on this server should have global (non-server specific) groups applied
apply-global-groups: true
# If users on this server should have global (non-world specific) groups applied
apply-global-world-groups: true
# +----------------------------------------------------------------------------------------------+ #
# | Inheritance settings | #
# +----------------------------------------------------------------------------------------------+ #
# If the plugin should apply wildcard permissions.
#
# Fill out connection info below if you're using MySQL, MariaDB, PostgreSQL or MongoDB
# If your MySQL server supports it, the "mariadb" option is preferred over "mysql".
storage-method: h2
# - If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered
# permissions matching the wildcard.
apply-wildcards: true
# When using a file-based storage type, LuckPerms can monitor the data files for changes, and then
# schedule automatic updates when changes are detected.
# If the plugin should parse regex permissions.
#
# If you don't want this to happen, set this option to false.
watch-files: true
# - If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the
# node, and resolve & apply all registered permissions matching the regex.
apply-regex: true
# This block enables support for split datastores.
split-storage:
enabled: false
methods:
user: h2
group: h2
track: h2
uuid: h2
log: h2
data:
# Uses standard DB engine port by default
# MySQL: 3306, PostgreSQL: 5432, MongoDB: 27017
# Specify as "host:port" if differs
address: localhost
database: minecraft
username: root
password: ''
# These settings apply to the MySQL connection pool.
# The default values will be suitable for the majority of users.
# Do not change these settings unless you know what you're doing!
pool-settings:
# Sets the maximum size of the MySQL connection pool.
# Basically this value will determine the maximum number of actual
# connections to the database backend.
#
# More information about determining the size of connection pools can be found here:
# https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
maximum-pool-size: 10
# Sets the minimum number of idle connections that the pool will try to maintain.
#
# For maximum performance and responsiveness to spike demands, it is recommended to not set
# this value and instead allow the pool to act as a fixed size connection pool.
# (set this value to the same as 'maximum-pool-size')
minimum-idle: 10
# This setting controls the maximum lifetime of a connection in the pool in milliseconds.
# The value should be at least 30 seconds less than any database or infrastructure imposed
# connection time limit.
maximum-lifetime: 1800000 # 30 minutes
# This setting controls the maximum number of milliseconds that the plugin will wait for a
# connection from the pool, before timing out.
connection-timeout: 5000 # 5 seconds
# This setting allows you to define extra properties for connections.
properties:
useUnicode: true
characterEncoding: utf8
# The prefix for all LuckPerms tables. Change this is you want to use different tables for
# different servers.
#
# This should *not* be set to "lp_" if you have previously ran LuckPerms v2.16.81 or earlier with
# this database.
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 ClientConnectionURI for use with replicasets and custom connection options
# See https://docs.mongodb.com/manual/reference/connection-string/
mongodb_connection_URI: ''
# This option controls how frequently LuckPerms will perform a sync task.
# A sync task will refresh all data from the storage, and ensure that the most up-to-date data is
# being used by the plugin.
#
# This is disabled by default, as most users will not need it. However, if you're using a remote
# storage type without a messaging service setup, you may wish to set this value to something like
# 3.
#
# Set to -1 to disable the task completely.
sync-minutes: -1
# Settings for the messaging service
# If the plugin should complete and apply shorthand permissions.
#
# If enabled and configured, LuckPerms will use the messaging system to inform other
# connected servers of changes. Use the command "/luckpermsbungee networksync" to push changes.
# Data is NOT stored using this service. It is only used as a messaging platform.
# - If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# If the plugin should apply the permissions & groups defined in the BungeeCord config.yml
#
# If you decide to enable this feature, you should set "sync-minutes" to -1, as there is no need for
# LuckPerms to poll the database for changes.
# - If set to false, LuckPerms will ignore these values.
apply-bungee-config-permissions: false
# +----------------------------------------------------------------------------------------------+ #
# | Extra settings | #
# +----------------------------------------------------------------------------------------------+ #
# Allows you to set "aliases" for the worlds sent forward for context calculation.
#
# Available options:
# -> bungee uses the plugin messaging channels. Must be enabled on all connected servers to
# work.
# -> redis uses redis pub sub to push changes. Your redis server must be configured below.
# -> redisbungee uses redis pub sub to push changes, using RedisBungee's API. You need to have the
# RedisBungee plugin installed.
# -> none nothing
messaging-service: none
# - These aliases are provided in addition to the real world name. Applied recursively.
# - Remove the comment characters for the default aliases to apply.
world-rewrite:
# world_nether: world
# world_the_end: world
# If LuckPerms should automatically push updates after a change has been made with a command.
auto-push-updates: true
# If LuckPerms should push logging entries to connected servers via the messaging service.
push-log-entries: true
# If LuckPerms should broadcast received logging entries to players on this platform.
# Define special group weights for this server.
#
# If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you should
# set this option to false on either your backends or your proxies, to avoid players being messaged
# twice about log entries.
broadcast-received-log-entries: false
# Settings for Redis.
# Port 6379 is used by default; set address to "host:port" if differs
redis:
enabled: false
address: localhost
password: ''
# - Group weights can also be applied directly to group data, using the setweight command.
# - This section allows weights to be set on a per-server basis.
group-weight:
# admin: 10
# +----------------------------------------------------------------------------------------------+ #
# | Default Assignments | #
# | | #
# | FINE TUNING OPTIONS | #
# | | #
# | A number of more niche settings for tweaking and changing behaviour. The section also | #
# | contains toggles for some more specialised features. It is only necessary to make changes to | #
# | these options if you want to fine-tune LuckPerms behaviour. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# +----------------------------------------------------------------------------------------------+ #
# | Miscellaneous (and rarely used) settings | #
# +----------------------------------------------------------------------------------------------+ #
# If LuckPerms should produce extra logging output when it handles logins.
#
# - Useful if you're having issues with UUID forwarding or data not being loaded.
debug-logins: false
# If LuckPerms should allow usernames with non alphanumeric characters.
#
# - Note that due to the design of the storage implementation, usernames must still be 16 characters
# or less.
allow-invalid-usernames: false
# If LuckPerms should allow a users primary group to be removed with the 'parent remove' command.
#
# - When this happens, the plugin will set their primary group back to default.
prevent-primary-group-removal: false
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | DEFAULT ASSIGNMENTS | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# This section allows you to define defaults to give users whenever they connect to the server.
+1 -1
View File
@@ -2,5 +2,5 @@ name: LuckPerms
version: ${full.version}
description: A permissions plugin
author: Luck
main: me.lucko.luckperms.bungee.LPBungeePlugin
main: me.lucko.luckperms.bungee.LPBungeeBootstrap
softDepends: ["RedisBungee"]
+27 -14
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>4.1-SNAPSHOT</version>
<version>4.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -89,29 +89,29 @@
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.6.1</version>
<version>2.6.2</version>
<scope>provided</scope>
</dependency>
<!-- okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.9.1</version>
<version>3.10.0</version>
<scope>provided</scope>
</dependency>
<!-- okio -->
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>1.13.0</version>
<version>1.14.0</version>
<scope>provided</scope>
</dependency>
<!-- configurate -->
<dependency>
<groupId>ninja.leaping.configurate</groupId>
<groupId>me.lucko.configurate</groupId>
<artifactId>configurate-core</artifactId>
<version>3.3</version>
<version>3.4</version>
<scope>provided</scope>
<exclusions>
<exclusion>
@@ -122,9 +122,9 @@
</dependency>
<!-- configurate yaml -->
<dependency>
<groupId>ninja.leaping.configurate</groupId>
<groupId>me.lucko.configurate</groupId>
<artifactId>configurate-yaml</artifactId>
<version>3.3</version>
<version>3.4</version>
<scope>provided</scope>
<exclusions>
<exclusion>
@@ -135,9 +135,9 @@
</dependency>
<!-- configurate gson -->
<dependency>
<groupId>ninja.leaping.configurate</groupId>
<groupId>me.lucko.configurate</groupId>
<artifactId>configurate-gson</artifactId>
<version>3.3</version>
<version>3.4</version>
<scope>provided</scope>
<exclusions>
<exclusion>
@@ -148,16 +148,29 @@
</dependency>
<!-- configurate hocon -->
<dependency>
<groupId>ninja.leaping.configurate</groupId>
<groupId>me.lucko.configurate</groupId>
<artifactId>configurate-hocon</artifactId>
<version>3.3</version>
<version>3.4</version>
<scope>provided</scope>
</dependency>
<!-- configurate toml -->
<dependency>
<groupId>me.lucko.configurate</groupId>
<artifactId>configurate-toml</artifactId>
<version>3.4</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>com.moandjiezana.toml</groupId>
<artifactId>toml4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>2.7.6</version>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Jedis -->
@@ -171,7 +184,7 @@
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.6.1</version>
<version>3.6.3</version>
<scope>provided</scope>
</dependency>
<!-- SnakeYAML -->
@@ -30,13 +30,12 @@ import com.google.common.base.Strings;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.sender.Sender;
import java.util.ArrayList;
import java.util.Comparator;
@@ -70,8 +69,8 @@ public class ExtendedLogEntry implements LogEntry {
*
* @return a new builder
*/
public static ExtendedLogEntryBuilder build() {
return new ExtendedLogEntryBuilder();
public static Builder build() {
return new Builder();
}
private final long timestamp;
@@ -207,7 +206,7 @@ public class ExtendedLogEntry implements LogEntry {
return result;
}
public static class ExtendedLogEntryBuilder implements LogEntry.Builder {
public static class Builder implements LogEntry.Builder {
private long timestamp = 0L;
private UUID actor = null;
@@ -219,88 +218,88 @@ public class ExtendedLogEntry implements LogEntry {
@Nonnull
@Override
public ExtendedLogEntryBuilder setTimestamp(long timestamp) {
public Builder setTimestamp(long timestamp) {
this.timestamp = timestamp;
return this;
}
@Nonnull
@Override
public ExtendedLogEntryBuilder setActor(@Nonnull UUID actor) {
public Builder setActor(@Nonnull UUID actor) {
this.actor = Objects.requireNonNull(actor, "actor");
return this;
}
@Nonnull
@Override
public ExtendedLogEntryBuilder setActorName(@Nonnull String actorName) {
public Builder setActorName(@Nonnull String actorName) {
this.actorName = Objects.requireNonNull(actorName, "actorName");
return this;
}
@Nonnull
@Override
public ExtendedLogEntryBuilder setType(@Nonnull Type type) {
public Builder setType(@Nonnull Type type) {
this.type = Objects.requireNonNull(type, "type");
return this;
}
@Nonnull
@Override
public ExtendedLogEntryBuilder setActed(UUID acted) {
public Builder setActed(UUID acted) {
this.acted = acted; // nullable
return this;
}
@Nonnull
@Override
public ExtendedLogEntryBuilder setActedName(@Nonnull String actedName) {
public Builder setActedName(@Nonnull String actedName) {
this.actedName = Objects.requireNonNull(actedName, "actedName");
return this;
}
@Nonnull
@Override
public ExtendedLogEntryBuilder setAction(@Nonnull String action) {
public Builder setAction(@Nonnull String action) {
this.action = Objects.requireNonNull(action, "action");
return this;
}
public ExtendedLogEntryBuilder timestamp(long timestamp) {
public Builder timestamp(long timestamp) {
return setTimestamp(timestamp);
}
public ExtendedLogEntryBuilder actor(UUID actor) {
public Builder actor(UUID actor) {
return setActor(actor);
}
public ExtendedLogEntryBuilder actorName(String actorName) {
public Builder actorName(String actorName) {
return setActorName(actorName);
}
public ExtendedLogEntryBuilder type(Type type) {
public Builder type(Type type) {
return setType(type);
}
public ExtendedLogEntryBuilder acted(UUID acted) {
public Builder acted(UUID acted) {
return setActed(acted);
}
public ExtendedLogEntryBuilder actedName(String actedName) {
public Builder actedName(String actedName) {
return setActedName(actedName);
}
public ExtendedLogEntryBuilder action(String action) {
public Builder action(String action) {
return setAction(action);
}
public ExtendedLogEntryBuilder actor(Sender actor) {
public Builder actor(Sender actor) {
actorName(actor.getNameWithLocation());
actor(actor.getUuid());
return this;
}
public ExtendedLogEntryBuilder acted(PermissionHolder acted) {
public Builder acted(PermissionHolder acted) {
if (acted.getType().isUser()) {
actedName(((User) acted).getName().orElse("null"));
acted(((User) acted).getUuid());
@@ -312,13 +311,13 @@ public class ExtendedLogEntry implements LogEntry {
return this;
}
public ExtendedLogEntryBuilder acted(Track track) {
public Builder acted(Track track) {
actedName(track.getName());
type(Type.TRACK);
return this;
}
public ExtendedLogEntryBuilder action(Object... args) {
public Builder action(Object... args) {
List<String> parts = new ArrayList<>();
for (Object o : args) {
@@ -353,7 +352,7 @@ public class ExtendedLogEntry implements LogEntry {
@Override
public ExtendedLogEntry build() {
if (this.timestamp == 0L) {
timestamp(DateUtil.unixSecondsNow());
timestamp(System.currentTimeMillis() / 1000L);
}
Objects.requireNonNull(this.actor, "actor");
@@ -367,7 +366,7 @@ public class ExtendedLogEntry implements LogEntry {
@Override
public String toString() {
return "ExtendedLogEntry.ExtendedLogEntryBuilder(" +
return "ExtendedLogEntry.Builder(" +
"timestamp=" + this.timestamp + ", " +
"actor=" + this.actor + ", " +
"actorName=" + this.actorName + ", " +
@@ -44,7 +44,7 @@ public class Log {
return new Builder();
}
public synchronized static Log empty() {
public static synchronized Log empty() {
if (empty == null) {
empty = builder().build();
}
@@ -27,13 +27,13 @@ package me.lucko.luckperms.common.actionlog;
import me.lucko.luckperms.api.event.log.LogBroadcastEvent;
import me.lucko.luckperms.api.event.log.LogNotifyEvent;
import me.lucko.luckperms.common.commands.CommandPermission;
import me.lucko.luckperms.common.commands.impl.log.LogNotify;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.commands.log.LogNotify;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.locale.message.Message;
import me.lucko.luckperms.common.messaging.InternalMessagingService;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import java.util.Optional;
@@ -0,0 +1,124 @@
/*
* 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.common.api;
import me.lucko.luckperms.api.DemotionResult;
import java.util.Objects;
import java.util.Optional;
import javax.annotation.Nonnull;
/**
* Utility class for creating instances of {@link DemotionResult}.
*/
public final class DemotionResults {
public static DemotionResult success(String groupFrom, String groupTo) {
return new Impl(DemotionResult.Status.SUCCESS, groupFrom, groupTo);
}
public static DemotionResult removedFromFirst(String groupFrom) {
return new Impl(DemotionResult.Status.REMOVED_FROM_FIRST_GROUP, groupFrom, null);
}
public static DemotionResult malformedTrack(String groupTo) {
return new Impl(DemotionResult.Status.MALFORMED_TRACK, null, groupTo);
}
public static DemotionResult notOnTrack() {
return new Impl(DemotionResult.Status.NOT_ON_TRACK);
}
public static DemotionResult ambiguousCall() {
return new Impl(DemotionResult.Status.AMBIGUOUS_CALL);
}
public static DemotionResult undefinedFailure() {
return new Impl(DemotionResult.Status.UNDEFINED_FAILURE);
}
private static final class Impl implements DemotionResult {
private final Status status;
private final String groupFrom;
private final String groupTo;
private Impl(Status status, String groupFrom, String groupTo) {
this.status = status;
this.groupFrom = groupFrom;
this.groupTo = groupTo;
}
private Impl(Status status) {
this(status, null, null);
}
@Nonnull
@Override
public Status getStatus() {
return this.status;
}
@Nonnull
@Override
public Optional<String> getGroupFrom() {
return Optional.ofNullable(this.groupFrom);
}
@Nonnull
@Override
public Optional<String> getGroupTo() {
return Optional.ofNullable(this.groupTo);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Impl that = (Impl) o;
return this.status == that.status &&
Objects.equals(this.groupFrom, that.groupFrom) &&
Objects.equals(this.groupTo, that.groupTo);
}
@Override
public int hashCode() {
return Objects.hash(this.status, this.groupFrom, this.groupTo);
}
@Override
public String toString() {
return "DemotionResult(" +
"status=" + this.status + ", " +
"groupFrom='" + this.groupFrom + "', " +
"groupTo='" + this.groupTo + "')";
}
}
private DemotionResults() {}
}
Loaded 100 of 507 files, more files were not shown because too many files have changed in this diff. Show more