Compare commits

..
74 Commits
Author SHA1 Message Date
Luck 6798fb21b2 Events rewrite, remove most deprecated API methods (v3.0) 2017-02-19 14:57:20 +00:00
Luck 89ff3b169b Fix bukkit child permission handling to not include permissions with no children & cleanup permission registration 2017-02-18 21:01:09 +00:00
Luck abddb265be ensure all bukkit permissions are registered on startup 2017-02-18 08:50:06 +00:00
Luck b328fa74a7 Clarify thrown exception when a null context is returned 2017-02-16 21:45:43 +00:00
Luck f97aa651a0 Fix NPE caused by generating the wrong ExtractedContexts type - closes #185 2017-02-16 21:43:27 +00:00
Luck 8d86eed0a7 Don't bother adding checks to the listener queue if no listeners are registered 2017-02-15 19:39:24 +00:00
Luck 05f906a759 Add /lp tree command - closes #175 2017-02-15 19:21:27 +00:00
Luck 4b16be1b75 Fix setting chat meta with Vault, remove unnecessary permissible recalculations & general cleanup 2017-02-15 12:53:52 +00:00
Luck bd97a7c5d2 Respect prefix option set in subject - closes #149 2017-02-14 17:11:17 +00:00
Luck a3a23d8870 Remove redundant SQL queries and fix issue where multiple uuids could be mapped to the same username - fixes #179 2017-02-14 16:23:54 +00:00
Luck 30bddceac5 import log should be sent to console too 2017-02-13 16:26:41 +00:00
Luck 989a2cc89c Make the bukkit command manager more accessible 2017-02-13 12:53:22 +00:00
Luck 3f17e8c3c8 Test verbose filters before registering them (#178) 2017-02-12 17:19:16 +00:00
Luck 140e6b08ca Apply regex perms before wildcards 2017-02-11 12:12:28 +00:00
Luck 6a39b721ba Fix sponge service returning subjects in reverse priority order 2017-02-09 23:00:48 +00:00
Luck 1df6f4b9df Allow negated group permissions 2017-02-08 21:04:34 +00:00
Luck 9493fb3a7a Switch SpongeGroup meta handling to use MetaHolder - closes #171 2017-02-06 22:38:03 +00:00
Luck 0d1f3b855f Ignore commented lines on dump imports & add annotations to export files - closes #169 2017-02-05 09:58:24 +00:00
Michael Vorburger 0982154a15 "Explaination" --> "Explanation" (#168) 2017-02-04 22:32:34 +00:00
Luck 378f3f5efa Fix NPE for vault getUserMeta when defaultValue is null and the LP value is also null 2017-02-04 17:45:26 +00:00
Luck 9b8d6e1dc7 Modify node escaping to use "\" characters, and remove all limits on node/server/world strings - closes #166 2017-02-04 12:18:45 +00:00
Luck 6540c695de Add configurable duration handling when a holder already has a temporary permission/parent/option set - closes #152 2017-02-03 22:24:42 +00:00
Luck 1d71ec07be fix option lookups in specific contexts returning as global instead 2017-02-03 17:18:18 +00:00
Luck c837dd5cc8 fix jedis shading - closes #158 2017-02-02 16:00:18 +00:00
Luck bc52e4da0e Fix OPs disabled message 2017-02-02 15:58:34 +00:00
Luck f0b4040458 Fix Sponge PEX meta migration weightings 2017-02-02 15:33:15 +00:00
Luck d804c4be2a fix build 2017-02-02 15:16:08 +00:00
Luck ede413a213 Fix import/export handling - closes #159 2017-02-02 15:13:44 +00:00
Luck 9cee319ed9 Cleanup all migration commands - closes #63 2017-02-01 18:41:15 +00:00
Luck f7b281f655 Fix build 2017-01-31 12:32:18 +00:00
Luck 8dbb083b90 Fix migration log being sent to the console twice 2017-01-31 12:29:06 +00:00
Luck 0be6d658ed Refactor plugin and scheduler interfaces 2017-01-31 12:14:42 +00:00
Luck 1efce41767 Fix search command page number 2017-01-30 20:13:19 +00:00
Luck da23b6ea9a Fix search command page number 2017-01-30 20:13:19 +00:00
Luck a61d3b3fd4 Fix sponge PEX/PM migration issue with defaults 2017-01-29 21:56:09 +00:00
Luck ab9284b80f Use reflection in the #getAllKeys method instead of a list 2017-01-29 14:52:42 +00:00
Luck 424af27a47 Change update messages to account for more than just redis messaging 2017-01-29 11:09:11 +00:00
Luck 5039a05055 Update readme 2017-01-27 20:37:27 +00:00
Luck d150b22eae fix NPE on login 2017-01-26 21:05:44 +00:00
Luck a617675771 prettify the verbose paste output 2017-01-26 19:47:46 +00:00
Luck f27034bb35 Pull git commit id once only - should improve build time 2017-01-26 13:55:06 +00:00
Luck 86b203c21b Compile with shaded redis version - fixes #150 2017-01-26 13:54:23 +00:00
Luck 73c5a1ad9b Fix apache pool2 jar not loading correctly - closes #150 2017-01-25 22:07:50 +00:00
Luck 81c71777cb Fix some usage messages 2017-01-24 21:48:47 +00:00
Luck 599072eef6 Fix null config values throwing exception - closes #147 2017-01-24 20:13:18 +00:00
Luck 02ea3afbe9 Add "!" delimiter to verbose matching 2017-01-23 22:47:39 +00:00
Luck 0c1a2e82bf implement verbose expression matching 2017-01-23 22:43:52 +00:00
Luck f89fb87c92 Log the file name when I/O fails 2017-01-23 21:15:25 +00:00
Luck 98d6cf842a reword check result message slightly 2017-01-23 21:08:27 +00:00
Luck 69dc02b2c2 Add /lp check <user> <permission> command 2017-01-23 21:03:58 +00:00
Luck 7d1a3d32e9 Fix login NPE when async tasks run after the event has been fully handled 2017-01-23 16:22:25 +00:00
Luck d93cc826b2 Fix backwards compatibility with redis 2017-01-22 22:49:11 +00:00
Luck 8025f3a082 Fix all users sharing the same meta state 2017-01-22 22:19:29 +00:00
Luck 247871f678 Cancel messaging task when the message is sent 2017-01-22 21:47:57 +00:00
Luck 327c8b83be Implement BungeeCord & LilyPad messaging services - closes #142 2017-01-22 21:46:22 +00:00
Luck 0f8c334de8 FIx stacking backwards compatibility 2017-01-22 19:01:34 +00:00
Luck 292d4cd450 Implement stacking prefixes - closes #60 2017-01-22 18:23:08 +00:00
Luck 38d1c9974b Soften server checking regex - also towards #143 2017-01-22 16:36:06 +00:00
Luck 0be7300677 Fix node shorthand parsing - closes #143 2017-01-22 16:29:52 +00:00
Luck c03585aeca Fix using UTF-8 characters with MySQL - closes #129 2017-01-22 12:19:29 +00:00
Luck d39dad3287 Fix config reloading causing ClassCastExceptions 2017-01-22 11:58:48 +00:00
Luck 0a3ca3affe Add /lp reloadconfig command - closes #100 2017-01-21 20:14:25 +00:00
Luck b7cf0e6bc7 Refactor config handling - towards #100 2017-01-21 15:36:13 +00:00
Luck 7430013cc3 don't unload sponge data when a player quits 2017-01-20 20:02:42 +00:00
Luck 6dd093fe72 fix API ClassCastException 2017-01-19 21:29:54 +00:00
Luck 8a8d6f16ae Return subjects in priority order - related CodeCrafter47/BungeeTabListPlus#175 2017-01-19 21:09:44 +00:00
Luck 2e16844141 Remove console only commands - closes #137 2017-01-19 20:39:09 +00:00
Luck a152cc47c7 Fix bukkit login handling - closes #110 2017-01-19 20:04:22 +00:00
Luck 241507228f Colorize console info messages 2017-01-19 19:51:41 +00:00
Luck 8aa7d272fa Include license file in the jars 2017-01-19 19:03:59 +00:00
Luck 01ac5382ea Prevent some shutdown exceptions - closes #136 2017-01-19 18:56:22 +00:00
Luck 02b88a8357 Maybe fix default assignment parsing error with sponge 2017-01-18 22:40:25 +00:00
Luck c99d6556db Fix issues with default assignment loading on Sponge 2017-01-18 21:37:41 +00:00
Luck 1db777cd31 Remove world cache - fixes #135 2017-01-18 21:05:14 +00:00
363 changed files with 9260 additions and 5079 deletions

No files matched your search

View File
File renamed without changes.
+26 -16
View File
@@ -1,34 +1,44 @@
![alt text](https://i.imgur.com/7TwJZ5e.png "Banner")
# LuckPerms [![Build Status](https://ci.lucko.me/job/LuckPerms/badge/icon)](https://ci.lucko.me/job/LuckPerms/)
An advanced permissions implementation for Bukkit/Spigot, BungeeCord and Sponge.
## Links
* **Development Builds** - <https://ci.lucko.me/job/LuckPerms>
* **Javadocs** - <https://jd.lucko.me/LuckPerms>
* **Wiki** - <https://github.com/lucko/LuckPerms/wiki>
## Description
LuckPerms is an advanced permissions implementation aiming to be a fast, reliable and flexible alternative to existing permission plugins. The project's main goals are centered around high performance and a wide feature set, filling the gaps of functionality and building upon existing features found in other plugins.
LuckPerms also includes an extensive API for developers, and support for a variety of Minecraft server software & data storage options.
See the charts below for a partial list of features & comparison with other providers.
[See the charts below](https://github.com/lucko/LuckPerms#luckperms-vs-other-plugins) for a partial list of features & comparison with other providers.
* [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")
## Useful Links
* **Development Builds** - <https://ci.lucko.me/job/LuckPerms>
* **Javadocs** - <https://jd.lucko.me/LuckPerms>
* **Wiki** - <https://github.com/lucko/LuckPerms/wiki>
## Building
LuckPerms uses Maven to handle dependencies.
#### Requirements
* Maven 3.3.x (the older versions will not work.)
* Git
#### Then run
```sh
git clone https://github.com/lucko/LuckPerms.git
mvn clean package
```
## 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.
## LuckPerms vs Other Plugins
### Bukkit
![alt text](https://static.lucko.me/luckperms-compare-copy.png "Feature comparison")
_Features checked on 23rd Aug 2016. If you find any inaccuracies, please do let me know. I tried to be as fair as possible, and copy all major features from the respective plugin pages._
###### _Features checked on 23rd Aug 2016. If you find any inaccuracies, please let me know._
### Sponge
![alt text](https://static.lucko.me/luckperms-compare-sponge.png "Feature comparison")
_Features checked on 8th Oct 2016. If you find any inaccuracies, please do let me know. I tried to be as fair as possible, and copy all major features from the respective plugin pages._
###### _Features checked on 8th Oct 2016. If you find any inaccuracies, please let me know._
## License
LuckPerms is licensed under the permissive MIT license. See LICENSE.md for more info.
## Sponsor
## Thanks
[![JProfiler](https://www.ej-technologies.com/images/product_banners/jprofiler_large.png)](http://www.ej-technologies.com/products/jprofiler/overview.html)
Thanks to ej-technologies for granting LuckPerms an open source licence to their [Java Profiling Software](http://www.ej-technologies.com/products/jprofiler/overview.html "Java Profiler").
Thanks to ej-technologies for granting LuckPerms an open source licence to their [Java Profiling Software](http://www.ej-technologies.com/products/jprofiler/overview.html "Java Profiler").
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.17-SNAPSHOT</version>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -24,8 +24,6 @@ package me.lucko.luckperms.api;
import me.lucko.luckperms.api.context.ContextSet;
import java.util.Map;
/**
* Context and options for a permission lookup.
*
@@ -51,18 +49,6 @@ public class Contexts {
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
}
@SuppressWarnings("deprecation")
@Deprecated
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups);
}
@SuppressWarnings("deprecation")
@Deprecated
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
}
/**
* The contexts that apply for this lookup
* The keys for servers and worlds are defined as static values.
@@ -115,17 +101,6 @@ public class Contexts {
this.op = op;
}
@Deprecated
public Contexts(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
this(context == null ? null : ContextSet.fromMap(context), includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
}
@SuppressWarnings("deprecation")
@Deprecated
public Contexts(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
this(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, false);
}
/**
* Gets the contexts that apply for this lookup
*
@@ -136,17 +111,6 @@ public class Contexts {
return this.context;
}
/**
* Gets the contexts that apply for this lookup
*
* @return an immutable map of context key value pairs
* @deprecated in favour of {@link #getContexts()}
*/
@Deprecated
public Map<String, String> getContext() {
return this.context.toMap();
}
/**
* Gets if OP defaults should be included
*
@@ -1,185 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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 me.lucko.luckperms.api.data.Callback;
import java.util.Set;
import java.util.UUID;
/**
* Deprecated Storage interface. Use {@link Storage} instead.
*
* @deprecated as of version 2.14 in favour of {@link Storage}.
*/
@Deprecated
public interface Datastore {
String getName();
boolean isAcceptingLogins();
@Deprecated
Sync sync();
@Deprecated
Async async();
@Deprecated
Future future();
@Deprecated
interface Sync {
boolean logAction(LogEntry entry);
Log getLog();
@Deprecated
boolean loadOrCreateUser(UUID uuid, String username);
@Deprecated
boolean loadUser(UUID uuid);
boolean loadUser(UUID uuid, String username);
boolean saveUser(User user);
boolean cleanupUsers();
Set<UUID> getUniqueUsers();
boolean createAndLoadGroup(String name);
boolean loadGroup(String name);
boolean loadAllGroups();
boolean saveGroup(Group group);
boolean deleteGroup(Group group);
boolean createAndLoadTrack(String name);
boolean loadTrack(String name);
boolean loadAllTracks();
boolean saveTrack(Track track);
boolean deleteTrack(Track track);
boolean saveUUIDData(String username, UUID uuid);
UUID getUUID(String username);
}
@Deprecated
interface Async {
void logAction(LogEntry entry, Callback<Boolean> callback);
void getLog(Callback<Log> callback);
@Deprecated
void loadOrCreateUser(UUID uuid, String username, Callback<Boolean> callback);
@Deprecated
void loadUser(UUID uuid, Callback<Boolean> callback);
void loadUser(UUID uuid, String username, Callback<Boolean> callback);
void saveUser(User user, Callback<Boolean> callback);
void cleanupUsers(Callback<Boolean> callback);
void getUniqueUsers(Callback<Set<UUID>> callback);
void createAndLoadGroup(String name, Callback<Boolean> callback);
void loadGroup(String name, Callback<Boolean> callback);
void loadAllGroups(Callback<Boolean> callback);
void saveGroup(Group group, Callback<Boolean> callback);
void deleteGroup(Group group, Callback<Boolean> callback);
void createAndLoadTrack(String name, Callback<Boolean> callback);
void loadTrack(String name, Callback<Boolean> callback);
void loadAllTracks(Callback<Boolean> callback);
void saveTrack(Track track, Callback<Boolean> callback);
void deleteTrack(Track track, Callback<Boolean> callback);
void saveUUIDData(String username, UUID uuid, Callback<Boolean> callback);
void getUUID(String username, Callback<UUID> callback);
}
@Deprecated
interface Future {
java.util.concurrent.Future<Boolean> logAction(LogEntry entry);
java.util.concurrent.Future<Log> getLog();
@Deprecated
java.util.concurrent.Future<Boolean> loadOrCreateUser(UUID uuid, String username);
@Deprecated
java.util.concurrent.Future<Boolean> loadUser(UUID uuid);
java.util.concurrent.Future<Boolean> loadUser(UUID uuid, String username);
java.util.concurrent.Future<Boolean> saveUser(User user);
java.util.concurrent.Future<Boolean> cleanupUsers();
java.util.concurrent.Future<Set<UUID>> getUniqueUsers();
java.util.concurrent.Future<Boolean> createAndLoadGroup(String name);
java.util.concurrent.Future<Boolean> loadGroup(String name);
java.util.concurrent.Future<Boolean> loadAllGroups();
java.util.concurrent.Future<Boolean> saveGroup(Group group);
java.util.concurrent.Future<Boolean> deleteGroup(Group group);
java.util.concurrent.Future<Boolean> createAndLoadTrack(String name);
java.util.concurrent.Future<Boolean> loadTrack(String name);
java.util.concurrent.Future<Boolean> loadAllTracks();
java.util.concurrent.Future<Boolean> saveTrack(Track track);
java.util.concurrent.Future<Boolean> deleteTrack(Track track);
java.util.concurrent.Future<Boolean> saveUUIDData(String username, UUID uuid);
java.util.concurrent.Future<UUID> getUUID(String username);
}
}
@@ -23,7 +23,6 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.data.DatastoreConfiguration;
import me.lucko.luckperms.api.data.MySQLConfiguration;
import java.util.Map;
@@ -44,22 +43,6 @@ public interface LPConfiguration {
*/
int getSyncTime();
/**
* Returns the default group, in a node representation
* @return the default group, in a node representation
* @deprecated as of 2.6, the default group is always "default"
*/
@Deprecated
String getDefaultGroupNode();
/**
* Returns the name of the default group
* @return the name of the default group
* @deprecated as of 2.6, the default group is always "default"
*/
@Deprecated
String getDefaultGroupName();
/**
* Returns if the users on this server will have their global permissions applied
* @return if the users on this server will have their global permissions applied
@@ -118,15 +101,6 @@ public interface LPConfiguration {
*/
boolean getLogNotify();
/**
* Returns true if permission checks are being recorded / debugged
* @return true if permission checks are being recorded / debugged
* @since 2.9
* @deprecated as this value is now always false. Functionality was replaced by the verbose command.
*/
@Deprecated
boolean getDebugPermissionChecks();
/**
* Returns true if the vanilla op system is enabled
* @return true if the vanilla op system is enabled
@@ -162,15 +136,6 @@ public interface LPConfiguration {
*/
boolean getVaultIncludeGlobal();
/**
* Returns the database values set in the configuration
* @return the database values set in the configuration
* @deprecated use {@link #getDatastoreConfig()}
*/
@SuppressWarnings("deprecation")
@Deprecated
MySQLConfiguration getDatabaseValues();
/**
* Returns the values set for data storage in the configuration
* @return the values set for data storage in the configuration
@@ -22,10 +22,9 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.context.ContextListener;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.IContextCalculator;
import me.lucko.luckperms.api.event.LPListener;
import me.lucko.luckperms.api.event.EventBus;
import java.util.Optional;
import java.util.Set;
@@ -42,37 +41,31 @@ public interface LuckPermsApi {
void runUpdateTask();
/**
* Gets the API version
* @return the version of the API running on the platform
* @since 2.6
*/
double getApiVersion();
/**
* Gets the plugin version
* @return the version of the plugin running on the platform
*/
String getVersion();
/**
* Gets the platform LuckPerms is running on
* @return the platform LuckPerms is running on
* @since 2.7
*/
PlatformType getPlatformType();
/**
* Registers a listener to be sent LuckPerms events
*
* @param listener the listener instance
* @throws NullPointerException if the listener is null
* Gets the event bus, used for subscribing to events
* @return the event bus
* @since 3.0
*/
void registerListener(LPListener listener);
/**
* Unregisters a previously registered listener from the EventBus
*
* @param listener the listener instance to unregister
* @throws NullPointerException if the listener is null
*/
void unregisterListener(LPListener listener);
EventBus getEventBus();
/**
* Gets a wrapped {@link LPConfiguration} instance, with read only access
@@ -89,16 +82,6 @@ public interface LuckPermsApi {
*/
Storage getStorage();
/**
* Gets a wrapped Datastore instance.
*
* @return a datastore instance
* @deprecated in favour of {@link #getStorage()}
*/
@SuppressWarnings("deprecation")
@Deprecated
Datastore getDatastore();
/**
* Gets the messaging service in use on the platform, if present.
*
@@ -274,15 +257,7 @@ public interface LuckPermsApi {
* @param contextCalculator the context calculator to register. The type MUST be the player class of the platform.
* @throws ClassCastException if the type is not the player class of the platform.
*/
void registerContextCalculator(IContextCalculator<?> contextCalculator);
/**
* Registers a custom context listener to the server,
*
* @param contextListener the context listener to register. The type MUST be the player class of the platform.
* @throws ClassCastException if the type is not the player class of the platform.
*/
void registerContextListener(ContextListener<?> contextListener);
void registerContextCalculator(ContextCalculator<?> contextCalculator);
/**
* Gets a calculated context instance for the user using the rules of the platform.
@@ -295,7 +270,7 @@ public interface LuckPermsApi {
Optional<Contexts> getContextForUser(User user);
/**
* Gets set of contexts applicable to a player using the platforms {@link IContextCalculator}s.
* Gets set of contexts applicable to a player using the platforms {@link ContextCalculator}s.
*
* @param player the player to calculate for. Must be the player instance for the platform.
* @return a set of contexts.
@@ -37,6 +37,20 @@ import java.util.Set;
*/
public class MetaUtils {
private static String escapeDelimiters(String s, String... delims) {
for (String delim : delims) {
s = s.replace(delim, "\\" + delim);
}
return s;
}
private static String unescapeDelimiters(String s, String... delims) {
for (String delim : delims) {
s = s.replace("\\" + delim, delim);
}
return s;
}
/**
* Escapes special characters used within LuckPerms, so the string can be saved without issues
*
@@ -49,11 +63,7 @@ public class MetaUtils {
throw new NullPointerException();
}
s = s.replace(".", "{SEP}");
s = s.replace("/", "{FSEP}");
s = s.replace("$", "{DSEP}");
return s;
return escapeDelimiters(s, ".", "/", "-", "$");
}
/**
@@ -71,6 +81,7 @@ public class MetaUtils {
s = s.replace("{SEP}", ".");
s = s.replace("{FSEP}", "/");
s = s.replace("{DSEP}", "$");
s = unescapeDelimiters(s, ".", "/", "-", "$");
return s;
}
@@ -133,31 +133,6 @@ public interface Node extends Map.Entry<String, Boolean> {
*/
boolean shouldApplyWithContext(ContextSet context);
/**
* If this node should apply in the given context
*
* @param context the context key value pairs
* @param worldAndServer if world and server contexts should be checked
* @return true if the node should apply
* @deprecated in favour of {@link #shouldApplyWithContext(ContextSet, boolean)}
*/
@Deprecated
default boolean shouldApplyWithContext(Map<String, String> context, boolean worldAndServer) {
return shouldApplyWithContext(ContextSet.fromMap(context), worldAndServer);
}
/**
* If this node should apply in the given context
*
* @param context the context key value pairs
* @return true if the node should apply
* @deprecated in favour of {@link #shouldApplyWithContext(ContextSet)}
*/
@Deprecated
default boolean shouldApplyWithContext(Map<String, String> context) {
return shouldApplyWithContext(ContextSet.fromMap(context));
}
/**
* Similar to {@link #shouldApplyOnServer(String, boolean, boolean)}, except this method accepts a List
*
@@ -227,15 +202,6 @@ public interface Node extends Map.Entry<String, Boolean> {
*/
boolean hasExpired();
/**
* @return the extra contexts required for this node to apply
* @deprecated in favour of {@link #getContexts()}
*/
@Deprecated
default Map<String, String> getExtraContexts() {
return getContexts().toMap();
}
/**
* @return the extra contexts required for this node to apply
* @since 2.13
@@ -25,7 +25,6 @@ package me.lucko.luckperms.api;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
@@ -73,17 +72,6 @@ public interface PermissionHolder {
*/
Set<? extends Node> getTransientPermissions();
/**
* Gets an immutable set of the nodes that this object has and inherits
*
* @return an immutable set of permissions
* @since 2.6
* @deprecated in favour of {@link #getAllNodes(Contexts)}
*/
@Deprecated
Set<Node> getAllNodes();
/**
* Gets a mutable sorted set of the nodes that this object has and inherits, filtered by context
* Unlike {@link #getAllNodesFiltered(Contexts)}, this method will not filter individual nodes. The context is only
@@ -117,15 +105,6 @@ public interface PermissionHolder {
*/
Map<String, Boolean> exportNodes(Contexts contexts, boolean lowerCase);
/**
* Gets an immutable Map of the objects permission nodes
*
* @return an immutable map of permissions
* @deprecated in favour of {@link #getPermissions()}
*/
@Deprecated
Map<String, Boolean> getNodes();
/**
* Removes temporary permissions that have expired
*/
@@ -631,86 +610,4 @@ public interface PermissionHolder {
*/
Set<Node> getTemporaryPermissionNodes();
/**
* Gets the permissions and inherited permissions that apply to a specific server and world
*
* @param server The server to get nodes for
* @param world The world to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @param possibleNodes A list of possible permission nodes for wildcard permission handling
* @return a {@link Map} of the permissions
* @deprecated in favour of {@link #getPermissions(String, String, Map, boolean, List, boolean)}
*/
@Deprecated
Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups, List<String> possibleNodes);
/**
* Gets the permissions and inherited permissions that apply to a specific server and world
*
* @param server The server to get nodes for
* @param world The world to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @return a {@link Map} of the permissions
* @deprecated in favour of {@link #getPermissions(String, String, Map, boolean, List, boolean)}
*/
@Deprecated
Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups);
/**
* Gets the permissions and inherited permissions that apply to a specific server
*
* @param server The server to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @param possibleNodes A list of possible permission nodes for wildcard permission handling
* @return a {@link Map} of the permissions
* @deprecated in favour of {@link #getPermissions(String, String, Map, boolean, List, boolean)}
*/
@Deprecated
Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups, List<String> possibleNodes);
/**
* Gets the permissions and inherited permissions that apply to a specific server
*
* @param server The server to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @return a {@link Map} of the permissions
* @deprecated in favour of {@link #getPermissions(String, String, Map, boolean, List, boolean)}
*/
@Deprecated
Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups);
/**
* Convert the holders nodes into a Map of permissions to be applied on the platform
*
* @param server the server
* @param world the world
* @param extraContext any extra context to filter by
* @param includeGlobal whether to include global nodes
* @param possibleNodes a list of possible permissions for resolving wildcards
* @param applyGroups if inherited group permissions should be included
* @return a map of permissions
* @since 2.6
* @deprecated in favour of {@link #getAllNodesFiltered(Contexts)}
*/
@Deprecated
Map<String, Boolean> getPermissions(String server, String world, Map<String, String> extraContext, boolean includeGlobal, List<String> possibleNodes, boolean applyGroups);
/**
* Processes the nodes and returns the temporary ones.
*
* @return a map of temporary nodes
* @deprecated in favour of {@link #getTemporaryPermissionNodes()}
*/
@Deprecated
Map<Map.Entry<String, Boolean>, Long> getTemporaryNodes();
/**
* Processes the nodes and returns the non-temporary ones.
*
* @return a map of permanent nodes
* @deprecated in favour of {@link #getPermanentPermissionNodes()}
*/
@Deprecated
Map<String, Boolean> getPermanentNodes();
}
@@ -31,12 +31,7 @@ public enum PlatformType {
BUKKIT("Bukkit"),
BUNGEE("Bungee"),
SPONGE("Sponge"),
/**
* @since 2.9
*/
STANDALONE("Standalone");
SPONGE("Sponge");
private final String friendlyName;
@@ -22,55 +22,34 @@
package me.lucko.luckperms.api.context;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A simple implementation of the listener aspects of {@link IContextCalculator}
* Calculates whether contexts are applicable to {@link T}
*
* @param <T> the subject type
* <p>Somewhat inspired by the system used on Sponge.
*
* @param <T> the subject type. Is ALWAYS the player class of the platform.
*/
public abstract class ContextCalculator<T> implements IContextCalculator<T> {
private final List<ContextListener<T>> listeners = new CopyOnWriteArrayList<>();
public interface ContextCalculator<T> {
/**
* Pushes an update to all registered {@link ContextListener}s.
* Make sure any changes are applied internally before this method is called.
* Gives the subject all of the applicable contexts they meet
*
* @param subject the subject that changed
* @param before the context state before the change
* @param current the context state after the change (now)
* @throws NullPointerException if any parameters are null
* @param subject the subject to add contexts to
* @param accumulator a map of contexts to add to
* @return the map
* @since 2.13
*/
protected void pushUpdate(T subject, Map.Entry<String, String> before, Map.Entry<String, String> current) {
if (subject == null) {
throw new NullPointerException("subject");
}
if (before == null) {
throw new NullPointerException("before");
}
if (current == null) {
throw new NullPointerException("current");
}
MutableContextSet giveApplicableContext(T subject, MutableContextSet accumulator);
for (ContextListener<T> listener : listeners) {
try {
listener.onContextChange(subject, before, current);
} catch (Exception e) {
System.out.println("Exception whilst passing context change to listener: " + listener);
e.printStackTrace();
}
}
}
@Override
public void addListener(ContextListener<T> listener) {
if (listener == null) {
throw new NullPointerException("listener");
}
listeners.add(listener);
}
/**
* Checks to see if a context is applicable to a subject
*
* @param subject the subject to check against
* @param context the context to check for
* @return true if met, or false if not. If this calculator does not calculate the given context, return false.
*/
boolean isContextApplicable(T subject, Map.Entry<String, String> context);
}
@@ -1,63 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.context;
import java.util.Map;
/**
* Calculates whether contexts are applicable to {@link T}
*
* <p>Somewhat inspired by the system used on Sponge.
*
* @param <T> the subject type. Is ALWAYS the player class of the platform.
*/
public interface IContextCalculator<T> {
/**
* Gives the subject all of the applicable contexts they meet
*
* @param subject the subject to add contexts to
* @param accumulator a map of contexts to add to
* @return the map
* @since 2.13
*/
MutableContextSet giveApplicableContext(T subject, MutableContextSet accumulator);
/**
* Checks to see if a context is applicable to a subject
*
* @param subject the subject to check against
* @param context the context to check for
* @return true if met, or false if not. If this calculator does not calculate the given context, return false.
*/
boolean isContextApplicable(T subject, Map.Entry<String, String> context);
/**
* Adds a listener to be called whenever a context handled by this calculator changes
*
* @param listener the listener instance
* @throws NullPointerException if listener is null
*/
void addListener(ContextListener<T> listener);
}
@@ -1,78 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.data;
import java.util.function.Consumer;
/**
* A callback used to wait for the completion of asynchronous operations.
* All callbacks are ran on the main server thread.
*
* @param <T> the return type
* @deprecated in favour of {@link Consumer}
*/
@Deprecated
public interface Callback<T> {
static <T> Callback<T> empty() {
return t -> {
};
}
static <T> Callback<T> of(Runnable runnable) {
if (runnable == null) {
throw new NullPointerException("runnable");
}
return t -> runnable.run();
}
static <T> Callback<T> of(Consumer<T> consumer) {
if (consumer == null) {
throw new NullPointerException("consumer");
}
return consumer::accept;
}
/**
* Helper method for converting old {@link Callback}s to use the new {@link me.lucko.luckperms.api.Storage}
* interface.
*
* @param callback the callback to convert
* @param <T> the return type
* @return a consumer instance
* @since 2.14
* @deprecated in favour of just using {@link Consumer}s.
*/
@Deprecated
static <T> Consumer<T> convertToConsumer(Callback<T> callback) {
return callback::onComplete;
}
/**
* Called when the operation completes.
*
* @param t the return value, may be null
*/
void onComplete(T t);
}
@@ -26,8 +26,7 @@ package me.lucko.luckperms.api.data;
* Represents the data section of the main LuckPerms configuration.
* All methods could return null.
*/
@SuppressWarnings("deprecation")
public interface DatastoreConfiguration extends MySQLConfiguration {
public interface DatastoreConfiguration {
String getAddress();
@@ -22,21 +22,18 @@
package me.lucko.luckperms.api.event;
import me.lucko.luckperms.api.User;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Represents an event acting upon a user.
* Represents an event that can be cancelled
*/
public class UserEvent extends LPEvent {
public interface Cancellable {
private final User user;
/**
* Gets an {@link AtomicBoolean} holding the cancellation state of the event
*
* @return the cancellation
*/
AtomicBoolean getCancellationState();
protected UserEvent(String eventName, User user) {
super(eventName);
this.user = user;
}
public User getUser() {
return user;
}
}
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event;
import java.util.Set;
import java.util.function.Consumer;
/**
* The LuckPerms event bus. Used for subscribing (or registering listeners) to events.
*
* @since 3.0
*/
public interface EventBus {
/**
* Subscribe to an event
*
* @param eventClass the event class
* @param handler the event handler
* @param <T> the event class
* @return an event handler instance representing this subscription
*/
<T extends LuckPermsEvent> EventHandler<T> subscribe(Class<T> eventClass, Consumer<T> handler);
/**
* Gets a set of all registered handlers for a given event
*
* @param eventClass the event to find handlers for
* @param <T> the event class
* @return an immutable set of event handlers
*/
<T extends LuckPermsEvent> Set<EventHandler<T>> getHandlers(Class<T> eventClass);
}
@@ -22,41 +22,48 @@
package me.lucko.luckperms.api.event;
import me.lucko.luckperms.api.PermissionHolder;
import java.util.function.Consumer;
import java.util.Optional;
public class AbstractPermissionRemoveEvent extends TargetedEvent<PermissionHolder> {
private final String server;
private final String world;
private final boolean temporary;
protected AbstractPermissionRemoveEvent(String eventName, PermissionHolder target, String server, String world, boolean temporary) {
super(eventName, target);
this.server = server;
this.world = world;
this.temporary = temporary;
}
public Optional<String> getServer() {
return Optional.ofNullable(server);
}
public Optional<String> getWorld() {
return Optional.ofNullable(world);
}
/**
* Represents a handler for a LuckPerms event
*
* @param <T> the event class
*/
public interface EventHandler<T extends LuckPermsEvent> {
/**
* @deprecated use {@link #isTemporary()}
* Gets the class this handler is listening to
*
* @return the event class
*/
@Deprecated
public boolean getTemporary() {
return temporary;
}
Class<T> getEventClass();
public boolean isTemporary() {
return temporary;
}
/**
* Returns true if this handler is active
*
* @return true if this handler is still active
*/
boolean isActive();
/**
* Unregisters this handler from the event bus
*
* @return true if the handler wasn't already unregistered
*/
boolean unregister();
/**
* Gets the event consumer responsible for handling the event
*
* @return the event consumer
*/
Consumer<T> getConsumer();
/**
* Gets the number of times this handler has been called
*
* @return the number of times this handler has been called
*/
int getCallCount();
}
@@ -22,21 +22,20 @@
package me.lucko.luckperms.api.event;
import me.lucko.luckperms.api.LuckPermsApi;
/**
* Represents an event acting upon a target
* The base event interface
*
* @param <T> the target type
* @since 3.0
*/
public class TargetedEvent<T> extends LPEvent {
public interface LuckPermsEvent {
private final T target;
/**
* Get the API instance this event was dispatched from
*
* @return the api instance
*/
LuckPermsApi getApi();
protected TargetedEvent(String eventName, T target) {
super(eventName);
this.target = target;
}
public T getTarget() {
return target;
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.cause;
/**
* The cause of a group/track creation
*/
public enum CreationCause {
/**
* The creation was caused by a command
*/
COMMAND,
/**
* The creation was caused by an API call
*/
API,
/**
* The creation was caused by a LuckPerms internal
*/
INTERNAL;
}
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.cause;
/**
* The cause of a group/track deletion
*/
public enum DeletionCause {
/**
* The deletion was caused by a command
*/
COMMAND,
/**
* The deletion was caused by an API call
*/
API,
/**
* The deletion was caused by a LuckPerms internal
*/
INTERNAL;
}
@@ -1,47 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.events;
import me.lucko.luckperms.api.PermissionHolder;
import me.lucko.luckperms.api.event.AbstractPermissionRemoveEvent;
/**
* Called whenever a user or group is removed from / stops inheriting another group
*/
public class GroupRemoveEvent extends AbstractPermissionRemoveEvent {
/**
* The name of group being removed from the target.
* Be aware that this group may have already been deleted, and and instance may therefore not exist internally.
*/
private final String group;
public GroupRemoveEvent(PermissionHolder target, String group, String server, String world, boolean temporary) {
super("Group Remove Event", target, server, world, temporary);
this.group = group;
}
public String getGroup() {
return group;
}
}
@@ -1,46 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.events;
import me.lucko.luckperms.api.PermissionHolder;
import me.lucko.luckperms.api.event.AbstractPermissionRemoveEvent;
/**
* Called whenever a user or group has a permission unset.
*
* @deprecated in favour of {@link PermissionNodeUnsetEvent}
*/
@Deprecated
public class PermissionUnsetEvent extends AbstractPermissionRemoveEvent {
private final String node;
public PermissionUnsetEvent(PermissionHolder target, String node, String server, String world, boolean temporary) {
super("Permission Unset Event", target, server, world, temporary);
this.node = node;
}
public String getNode() {
return node;
}
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.cause.CreationCause;
/**
* Called when a group is created
*/
public interface GroupCreateEvent extends LuckPermsEvent {
/**
* Gets the new group
*
* @return the new group
*/
Group getGroup();
/**
* Gets the cause of the creation
*
* @return the cause of the creation
*/
CreationCause getCause();
}
@@ -20,19 +20,38 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.events;
package me.lucko.luckperms.api.event.group;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.PermissionHolder;
import me.lucko.luckperms.api.event.AbstractPermissionEvent;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.cause.DeletionCause;
import java.util.Set;
/**
* Called when a permission node is unset from a holder
*
* @since 2.6
* Called when a group is deleted
*/
public class PermissionNodeUnsetEvent extends AbstractPermissionEvent {
public PermissionNodeUnsetEvent(PermissionHolder target, Node node) {
super("Permission Node Unset Event", target, node);
}
public interface GroupDeleteEvent extends LuckPermsEvent {
/**
* Gets the name of the deleted group
*
* @return the name of the deleted group
*/
String getGroupName();
/**
* Gets an immutable copy of the groups existing data
*
* @return a copy of the groups existing data
*/
Set<Node> getExistingData();
/**
* Gets the cause of the deletion
*
* @return the cause of the deletion
*/
DeletionCause getCause();
}
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.group;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* Called when all groups have been loaded in from storage.
*
* <p>Usually only called on startup and in sync tasks.</p>
*/
public interface GroupLoadAllEvent extends LuckPermsEvent {
}
@@ -20,24 +20,23 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event;
package me.lucko.luckperms.api.event.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* Event that allows listeners to set the cancelled state of an event.
* Called when a group is loaded into memory from the storage.
*
* Note that this event is not the same as {@link GroupCreateEvent}
*/
public abstract class CancellableEvent extends LPEvent {
public interface GroupLoadEvent extends LuckPermsEvent {
private boolean cancelled = false;
/**
* Gets the group that was loaded
*
* @return the group that was loaded
*/
Group getGroup();
protected CancellableEvent(String eventName) {
super(eventName);
}
public boolean isCancelled() {
return cancelled;
}
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.log;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* Called when a log entry is about to be sent to notifiable players on the platform
*/
public interface LogBroadcastEvent extends LuckPermsEvent, Cancellable {
/**
* Gets the log entry to be broadcasted
*
* @return the log entry to be broadcasted
*/
LogEntry getEntry();
}
@@ -20,24 +20,22 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event;
package me.lucko.luckperms.api.event.log;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.PermissionHolder;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* @since 2.6
* Called when a log is about to be published to the storage file/table
*/
public class AbstractPermissionEvent extends TargetedEvent<PermissionHolder> {
public interface LogPublishEvent extends LuckPermsEvent, Cancellable {
private final Node node;
/**
* Gets the log entry to be published
*
* @return the log entry to be published
*/
LogEntry getEntry();
protected AbstractPermissionEvent(String eventName, PermissionHolder target, Node node) {
super(eventName, target);
this.node = node;
}
public Node getNode() {
return node;
}
}
@@ -20,19 +20,20 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.data;
package me.lucko.luckperms.api.event.node;
import me.lucko.luckperms.api.Node;
/**
* @deprecated Use {@link DatastoreConfiguration}. This is now used by multiple datastores, not just MySQL.
* Called when a node is added to a holder
*/
@Deprecated
public interface MySQLConfiguration {
public interface NodeAddEvent extends NodeMutateEvent {
String getAddress();
/**
* Gets the node that was added
*
* @return the node that was added
*/
Node getNode();
String getDatabase();
String getUsername();
String getPassword();
}
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.node;
/**
* Called when a holder has their nodes cleared
*/
public interface NodeClearEvent extends NodeMutateEvent {
}
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.node;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.PermissionHolder;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import java.util.Set;
/**
* Called when a node is added to/removed from a user/group
*/
public interface NodeMutateEvent extends LuckPermsEvent {
/**
* Gets the target of the event
*
* @return the event target
*/
PermissionHolder getTarget();
/**
* Gets an immutable copy of the holders data before the change
*
* @return the data before the change
*/
Set<Node> getDataBefore();
/**
* Gets an immutable copy of the holders data after the change
*
* @return the data after the change
*/
Set<Node> getDataAfter();
/**
* Gets whether the target of this event is a {@link me.lucko.luckperms.api.User}
*
* <p>This is equivalent to checking if getTarget() instanceof User</p>
*
* @return if the event is targeting a user
*/
boolean isUser();
/**
* Gets whether the target of this event is a {@link me.lucko.luckperms.api.Group}
*
* <p>This is equivalent to checking if getTarget() instanceof Group</p>
*
* @return if the event is targeting a group
*/
boolean isGroup();
}
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.node;
import me.lucko.luckperms.api.Node;
/**
* Called when a node is removed from a holder
*/
public interface NodeRemoveEvent extends NodeMutateEvent {
/**
* Gets the node that was removed
*
* @return the node that was removed
*/
Node getNode();
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.sync;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* Called when the configuration is reloaded
*/
public interface ConfigReloadEvent extends LuckPermsEvent {
}
@@ -20,17 +20,13 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.events;
package me.lucko.luckperms.api.event.sync;
import me.lucko.luckperms.api.event.LPEvent;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* Called after the sync task has ran.
* Called when an sync task has been completed
*/
public class PostSyncEvent extends LPEvent {
public PostSyncEvent() {
super("Post Sync Event");
}
public interface PostSyncEvent extends LuckPermsEvent {
}
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.sync;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import java.util.UUID;
/**
* Called before a network sync task runs
*/
public interface PreNetworkSyncEvent extends LuckPermsEvent, Cancellable {
/**
* Gets the ID of the sync request
*
* @return the id of the sync request
*/
UUID getSyncId();
}
@@ -20,18 +20,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.events;
package me.lucko.luckperms.api.event.sync;
import me.lucko.luckperms.api.event.CancellableEvent;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* Called before the sync task is about to run.
* Set this event to cancelled to prevent the sync task from running.
* Called before a sync task runs
*/
public class PreSyncEvent extends CancellableEvent {
public PreSyncEvent() {
super("Pre Sync Event");
}
public interface PreSyncEvent extends LuckPermsEvent, Cancellable {
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.track;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.cause.CreationCause;
/**
* Called when a track is created
*/
public interface TrackCreateEvent extends LuckPermsEvent {
/**
* Gets the new track
*
* @return the new track
*/
Track getTrack();
/**
* Gets the cause of the creation
*
* @return the cause of the creation
*/
CreationCause getCause();
}
@@ -20,24 +20,37 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.context;
package me.lucko.luckperms.api.event.track;
import java.util.Map;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.cause.DeletionCause;
import java.util.List;
/**
* Listens to context changes
*
* @param <T> the subject type, Is ALWAYS the player class of the platform.
* Called when a track is deleted
*/
public interface ContextListener<T> {
public interface TrackDeleteEvent extends LuckPermsEvent {
/**
* Called whenever a context changes on the
* Gets the name of the deleted track
*
* @param subject the subject that had context changed
* @param before the context state before the change
* @param current the context state after the change (now)
* @return the name of the deleted track
*/
void onContextChange(T subject, Map.Entry<String, String> before, Map.Entry<String, String> current) throws Exception;
String getTrackName();
/**
* Gets an immutable copy of the tracks existing data
*
* @return a copy of the tracks existing data
*/
List<String> getExistingData();
/**
* Gets the cause of the deletion
*
* @return the cause of the deletion
*/
DeletionCause getCause();
}
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.track;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* Called when all tracks have been loaded in from storage.
*
* <p>Usually only called on startup and in sync tasks.</p>
*/
public interface TrackLoadAllEvent extends LuckPermsEvent {
}
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.track;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* Called when a track is loaded into memory from the storage.
*
* Note that this event is not the same as {@link TrackCreateEvent}
*/
public interface TrackLoadEvent extends LuckPermsEvent {
/**
* Gets the track that was loaded
*
* @return the track that was loaded
*/
Track getTrack();
}
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.track.mutate;
/**
* Called when a group is added to a track
*/
public interface TrackAddGroupEvent extends TrackMutateEvent {
/**
* Gets the group that was added
*
* @return the group that was added
*/
String getGroup();
}
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.track.mutate;
/**
* Called when a track is cleared
*/
public interface TrackClearEvent extends TrackMutateEvent {
}
@@ -20,30 +20,37 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.events;
package me.lucko.luckperms.api.event.track.mutate;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.event.CancellableEvent;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import java.util.List;
/**
* Called before a LogEntry is broadcasted to players only with the notify permission.
* The log entry will still be recorded in the datastore, regardless of the cancellation state of this event.
* Cancelling this event only stops the broadcast.
* Called when a track is changed
*/
public class LogNotifyEvent extends CancellableEvent {
public interface TrackMutateEvent extends LuckPermsEvent {
/**
* The log entry to be broadcasted
* Gets the track that was mutated
*
* @return the track that was mutated
*/
private final LogEntry entry;
Track getTrack();
public LogNotifyEvent(LogEntry entry) {
super("Log Notify Event");
this.entry = entry;
}
/**
* Gets an immutable copy of the tracks data before the change
*
* @return the data before the change
*/
List<String> getDataBefore();
public LogEntry getEntry() {
return entry;
}
/**
* Gets an immutable copy of the tracks data after the change
*
* @return the data after the change
*/
List<String> getDataAfter();
}
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.track.mutate;
/**
* Called when a group is removed from a track
*/
public interface TrackRemoveGroupEvent extends TrackMutateEvent {
/**
* Gets the group that was removed
*
* @return the group that was removed
*/
String getGroup();
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.user;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* Called when a users {@link me.lucko.luckperms.api.caching.UserData} is loaded.
*/
public interface UserCacheLoadEvent extends LuckPermsEvent {
/**
* Gets the user whose data was loaded
*
* @return the user
*/
User getUser();
/**
* Gets the data that was loaded
*
* @return the loaded data
*/
UserData getLoadedData();
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.user;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* Called when a users cached data is refreshed
*/
public interface UserDataRecalculateEvent extends LuckPermsEvent {
/**
* Gets the user whose data was recalculated
*
* @return the user
*/
User getUser();
/**
* Gets the data that was recalculated
*
* @return the data
*/
UserData getData();
}
@@ -20,35 +20,37 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.events;
package me.lucko.luckperms.api.event.user;
import me.lucko.luckperms.api.event.LPEvent;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import java.util.UUID;
/**
* Called when the user logs into the network for the first time. Particularly useful for networks with multiple
* lobbies, who want to welcome a user when they join for the first time.
* Called when the user logs into the network for the first time.
*
* <p>Particularly useful for networks with multiple
* lobbies, who want to welcome a user when they join for the first time.</p>
*
* <p>This event is fired before the player has actually joined the game on the async login / auth event. If you want to
* do something with the user, store the UUID in a set, and then check the set in the PlayerJoinEvent o.e.
* do something with the user, store the UUID in a set, and then check the set in the PlayerJoinEvent o.e.</p>
*
* <p>The users data will not be loaded when this event is called.</p>
*/
public class UserFirstLoginEvent extends LPEvent {
public interface UserFirstLoginEvent extends LuckPermsEvent {
private final UUID uuid;
private final String username;
/**
* Gets the UUID of the user
*
* @return the uuid of the user
*/
UUID getUuid();
public UserFirstLoginEvent(UUID uuid, String username) {
super("User First Join Event");
this.uuid = uuid;
this.username = username;
}
/**
* Gets the username of the user
*
* @return the username of the user
*/
String getUsername();
public UUID getUuid() {
return uuid;
}
public String getUsername() {
return username;
}
}
@@ -20,19 +20,21 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.event.events;
package me.lucko.luckperms.api.event.user;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.event.TrackEvent;
import me.lucko.luckperms.api.event.LuckPermsEvent;
/**
* Called whenever a user is demoted down a track
* Called when a user is loaded into memory from the storage.
*/
public class UserDemoteEvent extends TrackEvent {
public interface UserLoadEvent extends LuckPermsEvent {
public UserDemoteEvent(Track track, User user, String from, String to) {
super("User Demote Event", track, user, from, to);
}
/**
* Gets the user that was loaded
*
* @return the user that was loaded
*/
User getUser();
}
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.user.track;
/**
* Represents the type of action performed in a {@link UserTrackEvent}
*/
public enum TrackAction {
/**
* The user was promoted up a track
*/
PROMOTION,
/**
* The user was demoted down a track
*/
DEMOTION;
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.user.track;
/**
* Called when a user is demoted down a track.
*
* <p>{@link #getAction()} is always {@link TrackAction#DEMOTION}</p>
*/
public interface UserDemoteEvent extends UserTrackEvent {
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.user.track;
/**
* Called when a user is promoted up a track.
*
* <p>{@link #getAction()} is always {@link TrackAction#PROMOTION}</p>
*/
public interface UserPromoteEvent extends UserTrackEvent {
}
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.event.user.track;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import java.util.Optional;
/**
* Called when a user interacts with a track through a promotion or demotion
*/
public interface UserTrackEvent extends LuckPermsEvent {
/**
* Gets the track involved in the event
*
* @return the track involved in the event
*/
Track getTrack();
/**
* Gets the user who was promoted or demoted
*
* @return the user involved in the event
*/
User getUser();
/**
* Gets the action performed
*
* @return the action performed
*/
TrackAction getAction();
/**
* Gets the group the user was promoted/demoted from.
*
* <p>May be {@link Optional#empty()} if the user wasn't already placed on the track.</p>
*
* @return the group the user was promoted/demoted from
*/
Optional<String> getGroupFrom();
/**
* Gets the group the user was promoted/demoted to
*
* @return the group the user was promoted/demoted to
*/
Optional<String> getGroupTo();
}
+10 -22
View File
@@ -5,19 +5,26 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.17-SNAPSHOT</version>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>luckperms-bukkit-legacy</artifactId>
<build>
<defaultGoal>clean package</defaultGoal>
<finalName>LuckPerms-Bukkit-Legacy-${release.version}.${git.closest.tag.commit.count}</finalName>
<finalName>LuckPerms-Bukkit-Legacy-${release.version}.${patch.version}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>../</directory>
<filtering>false</filtering>
<includes>
<include>LICENSE.txt</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
@@ -41,11 +48,7 @@
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<artifactSet>
<excludes>
<exclude>org.xerial:*</exclude>
</excludes>
</artifactSet>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>com.google.common</pattern>
@@ -64,21 +67,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<injectAllReactorProjects>true</injectAllReactorProjects>
</configuration>
</plugin>
</plugins>
</build>
+10 -1
View File
@@ -5,13 +5,22 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.17-SNAPSHOT</version>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>luckperms-bukkit-placeholders</artifactId>
<build>
<finalName>LuckPermsPlaceholderExpansion</finalName>
<resources>
<resource>
<directory>../</directory>
<filtering>false</filtering>
<includes>
<include>LICENSE.txt</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
+17 -17
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.17-SNAPSHOT</version>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,13 +14,20 @@
<build>
<defaultGoal>clean package</defaultGoal>
<finalName>LuckPerms-Bukkit-${release.version}.${git.closest.tag.commit.count}</finalName>
<finalName>LuckPerms-Bukkit-${release.version}.${patch.version}</finalName>
<sourceDirectory>${basedir}/src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>../</directory>
<filtering>false</filtering>
<includes>
<include>LICENSE.txt</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
@@ -44,6 +51,7 @@
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>io.github.mkremins.fanciful</pattern>
@@ -54,21 +62,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<injectAllReactorProjects>true</injectAllReactorProjects>
</configuration>
</plugin>
</plugins>
</build>
@@ -101,6 +94,13 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<!-- LilyPad - used as a messaging service -->
<dependency>
<groupId>lilypad.client.connect</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- HikariCP - needed as source -->
<dependency>
<groupId>com.zaxxer</groupId>
@@ -30,7 +30,7 @@ import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.bukkit.calculators.AttachmentProcessor;
import me.lucko.luckperms.bukkit.calculators.ChildProcessor;
import me.lucko.luckperms.bukkit.calculators.DefaultsProcessor;
import me.lucko.luckperms.bukkit.inject.Injector;
import me.lucko.luckperms.bukkit.model.Injector;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
import me.lucko.luckperms.common.calculators.PermissionCalculator;
@@ -38,6 +38,7 @@ import me.lucko.luckperms.common.calculators.PermissionProcessor;
import me.lucko.luckperms.common.calculators.processors.MapProcessor;
import me.lucko.luckperms.common.calculators.processors.RegexProcessor;
import me.lucko.luckperms.common.calculators.processors.WildcardProcessor;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.core.model.User;
import java.util.UUID;
@@ -57,12 +58,12 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
LPPermissible permissible = Injector.getPermissible(uuid);
return permissible == null ? null : permissible.getAttachmentPermissions();
}));
if (plugin.getConfiguration().isApplyingWildcards()) {
processors.add(new WildcardProcessor());
}
if (plugin.getConfiguration().isApplyingRegex()) {
if (plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) {
processors.add(new RegexProcessor());
}
if (plugin.getConfiguration().get(ConfigKeys.APPLYING_WILDCARDS)) {
processors.add(new WildcardProcessor());
}
processors.add(new DefaultsProcessor(contexts.isOp(), plugin.getDefaultsProvider()));
return registerCalculator(new PermissionCalculator(plugin, user.getName(), processors.build()));
@@ -37,7 +37,7 @@ import org.bukkit.command.TabExecutor;
import java.util.Arrays;
import java.util.List;
class BukkitCommand extends CommandManager implements CommandExecutor, TabExecutor {
public class BukkitCommand extends CommandManager implements CommandExecutor, TabExecutor {
private final LPBukkitPlugin plugin;
BukkitCommand(LPBukkitPlugin plugin) {
@@ -22,6 +22,9 @@
package me.lucko.luckperms.bukkit;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.common.config.AbstractConfiguration;
import org.bukkit.configuration.ConfigurationSection;
@@ -34,48 +37,48 @@ import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
class BukkitConfig extends AbstractConfiguration<LPBukkitPlugin> {
@RequiredArgsConstructor
public class BukkitConfig extends AbstractConfiguration {
@Getter
private final LPBukkitPlugin plugin;
private YamlConfiguration configuration;
BukkitConfig(LPBukkitPlugin plugin) {
super(plugin, "global", true, "sqlite");
}
@SuppressWarnings("ResultOfMethodCallIgnored")
@Override
protected void init() {
File configFile = new File(getPlugin().getDataFolder(), "config.yml");
public void init() {
File configFile = new File(plugin.getDataFolder(), "config.yml");
if (!configFile.exists()) {
configFile.getParentFile().mkdirs();
getPlugin().saveResource("config.yml", false);
plugin.saveResource("config.yml", false);
}
configuration = YamlConfiguration.loadConfiguration(configFile);
}
@Override
protected String getString(String path, String def) {
public String getString(String path, String def) {
return configuration.getString(path, def);
}
@Override
protected int getInt(String path, int def) {
public int getInt(String path, int def) {
return configuration.getInt(path, def);
}
@Override
protected boolean getBoolean(String path, boolean def) {
public boolean getBoolean(String path, boolean def) {
return configuration.getBoolean(path, def);
}
@Override
protected List<String> getList(String path, List<String> def) {
public List<String> getList(String path, List<String> def) {
return Optional.ofNullable(configuration.getStringList(path)).orElse(def);
}
@Override
protected List<String> getObjectList(String path, List<String> def) {
public List<String> getObjectList(String path, List<String> def) {
ConfigurationSection section = configuration.getConfigurationSection(path);
if (section == null) {
return def;
@@ -84,9 +87,8 @@ class BukkitConfig extends AbstractConfiguration<LPBukkitPlugin> {
return Optional.ofNullable(section.getKeys(false).stream().collect(Collectors.toList())).orElse(def);
}
@SuppressWarnings("unchecked")
@Override
protected Map<String, String> getMap(String path, Map<String, String> def) {
public Map<String, String> getMap(String path, Map<String, String> def) {
Map<String, String> map = new HashMap<>();
ConfigurationSection section = configuration.getConfigurationSection(path);
if (section == null) {
@@ -22,8 +22,9 @@
package me.lucko.luckperms.bukkit;
import me.lucko.luckperms.bukkit.inject.Injector;
import me.lucko.luckperms.bukkit.model.Injector;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.core.model.User;
import me.lucko.luckperms.common.utils.AbstractListener;
@@ -33,15 +34,21 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginEnableEvent;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
class BukkitListener extends AbstractListener implements Listener {
private final LPBukkitPlugin plugin;
private final Set<UUID> deniedAsyncLogin = Collections.synchronizedSet(new HashSet<>());
private final Set<UUID> deniedLogin = new HashSet<>();
BukkitListener(LPBukkitPlugin plugin) {
super(plugin);
@@ -50,7 +57,13 @@ class BukkitListener extends AbstractListener implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onPlayerPreLogin(AsyncPlayerPreLoginEvent e) {
if (e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
deniedAsyncLogin.add(e.getUniqueId());
return;
}
if (!plugin.isStarted() || !plugin.getStorage().isAcceptingLogins()) {
deniedAsyncLogin.add(e.getUniqueId());
// The datastore is disabled, prevent players from joining the server
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
@@ -63,6 +76,11 @@ class BukkitListener extends AbstractListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerPreLoginMonitor(AsyncPlayerPreLoginEvent e) {
// If they were denied before/at LOW, then don't bother handling here.
if (deniedAsyncLogin.remove(e.getUniqueId())) {
return;
}
if (plugin.isStarted() && plugin.getStorage().isAcceptingLogins() && e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
// Login event was cancelled by another plugin
@@ -70,12 +88,19 @@ class BukkitListener extends AbstractListener implements Listener {
}
}
@EventHandler(priority = EventPriority.LOWEST)
@EventHandler(priority = EventPriority.LOW)
public void onPlayerLogin(PlayerLoginEvent e) {
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
deniedLogin.add(e.getPlayer().getUniqueId());
return;
}
final Player player = e.getPlayer();
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
if (user == null) {
deniedLogin.add(e.getPlayer().getUniqueId());
// User wasn't loaded for whatever reason.
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
return;
@@ -92,6 +117,8 @@ class BukkitListener extends AbstractListener implements Listener {
t.printStackTrace();
}
plugin.refreshAutoOp(player);
if (player.isOp()) {
// We assume all users are not op, but those who are need extra calculation.
@@ -103,24 +130,27 @@ class BukkitListener extends AbstractListener implements Listener {
public void onPlayerLoginMonitor(PlayerLoginEvent e) {
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
// If they were denied before/at LOW, then don't bother handling here.
if (deniedLogin.remove(e.getPlayer().getUniqueId())) {
return;
}
// The player got denied on sync login.
onLeave(e.getPlayer().getUniqueId());
plugin.getServer().getScheduler().runTaskLater(plugin, () -> onLeave(e.getPlayer().getUniqueId()), 20L);
} else {
plugin.refreshAutoOp(e.getPlayer());
}
}
@EventHandler(priority = EventPriority.MONITOR) // Allow other plugins to see data when this event gets called.
public void onPlayerQuit(PlayerQuitEvent e) {
final Player player = e.getPlayer();
final UUID internal = plugin.getUuidCache().getUUID(player.getUniqueId());
// Remove from World cache
plugin.getWorldCalculator().getWorldCache().remove(internal);
// Remove the custom permissible
Injector.unInject(player, true);
Injector.unInject(player, true, true);
// Handle auto op
if (plugin.getConfiguration().isAutoOp()) {
if (plugin.getConfiguration().get(ConfigKeys.AUTO_OP)) {
player.setOp(false);
}
@@ -130,7 +160,7 @@ class BukkitListener extends AbstractListener implements Listener {
@EventHandler
public void onPlayerCommand(PlayerCommandPreprocessEvent e) {
if (plugin.getConfiguration().isOpsEnabled()) {
if (plugin.getConfiguration().get(ConfigKeys.OPS_ENABLED)) {
return;
}
@@ -152,4 +182,9 @@ class BukkitListener extends AbstractListener implements Listener {
plugin.tryVaultHook(true);
}
}
@EventHandler
public void onWorldChange(PlayerChangedWorldEvent e) {
plugin.refreshAutoOp(e.getPlayer());
}
}
@@ -23,9 +23,9 @@
package me.lucko.luckperms.bukkit;
import me.lucko.luckperms.bukkit.compat.MessageHandler;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.sender.SenderFactory;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -24,52 +24,55 @@ package me.lucko.luckperms.bukkit;
import lombok.Getter;
import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.bukkit.calculators.AutoOPListener;
import me.lucko.luckperms.bukkit.inject.Injector;
import me.lucko.luckperms.bukkit.messaging.BungeeMessagingService;
import me.lucko.luckperms.bukkit.messaging.LilyPadMessagingService;
import me.lucko.luckperms.bukkit.model.ChildPermissionProvider;
import me.lucko.luckperms.bukkit.model.DefaultsProvider;
import me.lucko.luckperms.bukkit.model.Injector;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import me.lucko.luckperms.bukkit.vault.VaultHook;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.api.ApiHandler;
import me.lucko.luckperms.common.api.ApiProvider;
import me.lucko.luckperms.common.caching.handlers.CachedStateManager;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.config.LPConfiguration;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.contexts.ContextManager;
import me.lucko.luckperms.common.contexts.ServerCalculator;
import me.lucko.luckperms.common.core.UuidCache;
import me.lucko.luckperms.common.core.model.User;
import me.lucko.luckperms.common.data.Importer;
import me.lucko.luckperms.common.debug.DebugHandler;
import me.lucko.luckperms.common.dependencies.DependencyManager;
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.managers.GroupManager;
import me.lucko.luckperms.common.managers.TrackManager;
import me.lucko.luckperms.common.managers.UserManager;
import me.lucko.luckperms.common.managers.impl.GenericGroupManager;
import me.lucko.luckperms.common.managers.impl.GenericTrackManager;
import me.lucko.luckperms.common.managers.impl.GenericUserManager;
import me.lucko.luckperms.common.messaging.InternalMessagingService;
import me.lucko.luckperms.common.messaging.RedisMessaging;
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.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.utils.BufferedRequest;
import me.lucko.luckperms.common.utils.DebugHandler;
import me.lucko.luckperms.common.utils.LocaleManager;
import me.lucko.luckperms.common.utils.LogFactory;
import me.lucko.luckperms.common.utils.PermissionCache;
import me.lucko.luckperms.common.utils.LoggerImpl;
import org.bukkit.World;
import org.bukkit.command.PluginCommand;
@@ -87,25 +90,24 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
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.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
@Getter
public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private Set<UUID> ignoringLogs;
private Executor syncExecutor;
private Executor asyncExecutor;
private LPBukkitScheduler scheduler;
private BukkitCommand commandManager;
private VaultHook vaultHook = null;
private LPConfiguration configuration;
private LuckPermsConfiguration configuration;
private UserManager userManager;
private GroupManager groupManager;
private TrackManager trackManager;
private Storage storage;
private RedisMessaging redisMessaging = null;
private InternalMessagingService messagingService = null;
private UuidCache uuidCache;
private BukkitListener listener;
private ApiProvider apiProvider;
@@ -122,23 +124,25 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private boolean started = false;
private DebugHandler debugHandler;
private BukkitSenderFactory senderFactory;
private PermissionCache permissionCache;
private PermissionVault permissionVault;
@Override
public void onEnable() {
// Used whilst the server is still starting
asyncExecutor = Executors.newCachedThreadPool();
syncExecutor = r -> getServer().getScheduler().runTask(this, r);
Executor bukkitAsyncExecutor = r -> getServer().getScheduler().runTaskAsynchronously(this, r);
scheduler = new LPBukkitScheduler(this);
log = LogFactory.wrap(getLogger());
ignoringLogs = ConcurrentHashMap.newKeySet();
debugHandler = new DebugHandler(bukkitAsyncExecutor, getVersion());
localeManager = new NoopLocaleManager();
senderFactory = new BukkitSenderFactory(this);
permissionCache = new PermissionCache(bukkitAsyncExecutor);
log = new LoggerImpl(getConsoleSender());
LuckPermsPlugin.sendStartupBanner(getConsoleSender(), this);
ignoringLogs = ConcurrentHashMap.newKeySet();
debugHandler = new DebugHandler(scheduler.getAsyncBukkitExecutor(), getVersion());
permissionVault = new PermissionVault(scheduler.getAsyncBukkitExecutor());
getLog().info("Loading configuration...");
configuration = new BukkitConfig(this);
configuration.init();
configuration.loadAll();
Set<StorageType> storageTypes = StorageFactory.getRequiredTypes(this, StorageType.H2);
DependencyManager.loadDependencies(this, storageTypes);
@@ -147,29 +151,18 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
defaultsProvider = new DefaultsProvider();
childPermissionProvider = new ChildPermissionProvider();
// give all plugins a chance to load their defaults, then refresh.
getServer().getScheduler().runTaskLater(this, () -> {
// give all plugins a chance to load their permissions, then refresh.
scheduler.doSyncLater(() -> {
defaultsProvider.refresh();
childPermissionProvider.setup();
getServer().getScheduler().runTaskAsynchronously(this, () -> {
for (Map.Entry<String, Boolean> e : defaultsProvider.getOpDefaults().entrySet()) {
permissionCache.offer(e.getKey());
}
for (Map.Entry<String, Boolean> e : defaultsProvider.getNonOpDefaults().entrySet()) {
permissionCache.offer(e.getKey());
}
ImmutableMap<Map.Entry<String, Boolean>, ImmutableMap<String, Boolean>> permissions = childPermissionProvider.getPermissions();
for (Map.Entry<Map.Entry<String, Boolean>, ImmutableMap<String, Boolean>> e : permissions.entrySet()) {
permissionCache.offer(e.getKey().getKey());
for (Map.Entry<String, Boolean> e1 : e.getValue().entrySet()) {
permissionCache.offer(e1.getKey());
}
}
Set<String> perms = new HashSet<>();
getServer().getPluginManager().getPermissions().forEach(p -> {
perms.add(p.getName());
perms.addAll(p.getChildren().keySet());
});
perms.forEach(p -> permissionVault.offer(p));
}, 1L);
// register events
@@ -180,17 +173,43 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
// initialise datastore
storage = StorageFactory.getInstance(this, StorageType.H2);
// initialise redis
if (getConfiguration().isRedisEnabled()) {
// initialise messaging
String messagingType = getConfiguration().get(ConfigKeys.MESSAGING_SERVICE).toLowerCase();
if (messagingType.equals("none") && getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
messagingType = "redis";
}
if (messagingType.equals("redis")) {
getLog().info("Loading redis...");
redisMessaging = new RedisMessaging(this);
try {
redisMessaging.init(getConfiguration().getRedisAddress(), getConfiguration().getRedisPassword());
getLog().info("Loaded redis successfully...");
} catch (Exception e) {
getLog().info("Couldn't load redis...");
e.printStackTrace();
if (getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
RedisMessaging redis = new RedisMessaging(this);
try {
redis.init(getConfiguration().get(ConfigKeys.REDIS_ADDRESS), getConfiguration().get(ConfigKeys.REDIS_PASSWORD));
getLog().info("Loaded redis successfully...");
messagingService = redis;
} catch (Exception e) {
getLog().warn("Couldn't load redis...");
e.printStackTrace();
}
} else {
getLog().warn("Messaging Service was set to redis, but redis is not enabled!");
}
} else if (messagingType.equals("bungee")) {
getLog().info("Loading bungee messaging service...");
BungeeMessagingService bungeeMessaging = new BungeeMessagingService(this);
bungeeMessaging.init();
messagingService = bungeeMessaging;
} else if (messagingType.equals("lilypad")) {
getLog().info("Loading LilyPad messaging service...");
if (getServer().getPluginManager().getPlugin("LilyPad-Connect") == null) {
getLog().warn("LilyPad-Connect plugin not present.");
} else {
LilyPadMessagingService lilyPadMessaging = new LilyPadMessagingService(this);
lilyPadMessaging.init();
messagingService = lilyPadMessaging;
}
} else if (!messagingType.equals("none")) {
getLog().warn("Messaging service '" + messagingType + "' not recognised.");
}
// setup the update task buffer
@@ -203,7 +222,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
};
// load locale
localeManager = new LocaleManager();
localeManager = new SimpleLocaleManager();
File locale = new File(getDataFolder(), "lang.yml");
if (locale.exists()) {
getLog().info("Found locale file. Attempting to load from it.");
@@ -216,7 +235,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
// register commands
getLog().info("Registering commands...");
BukkitCommand commandManager = new BukkitCommand(this);
commandManager = new BukkitCommand(this);
PluginCommand main = getServer().getPluginCommand("luckperms");
main.setExecutor(commandManager);
main.setTabCompleter(commandManager);
@@ -224,24 +243,18 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
// load internal managers
getLog().info("Loading internal permission managers...");
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
uuidCache = new UuidCache(this);
userManager = new GenericUserManager(this);
groupManager = new GenericGroupManager(this);
trackManager = new GenericTrackManager();
trackManager = new GenericTrackManager(this);
importer = new Importer(commandManager);
calculatorFactory = new BukkitCalculatorFactory(this);
cachedStateManager = new CachedStateManager(this);
contextManager = new ContextManager<>();
worldCalculator = new WorldCalculator(this);
pm.registerEvents(worldCalculator, this);
contextManager.registerCalculator(worldCalculator);
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
// handle server operators
if (getConfiguration().isAutoOp()) {
contextManager.registerListener(new AutoOPListener());
}
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration()));
// Provide vault support
tryVaultHook(false);
@@ -254,37 +267,38 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
// schedule update tasks
int mins = getConfiguration().getSyncTime();
int mins = getConfiguration().get(ConfigKeys.SYNC_TIME);
if (mins > 0) {
long ticks = mins * 60 * 20;
getServer().getScheduler().runTaskTimerAsynchronously(this, () -> updateTaskBuffer.request(), 40L, ticks);
scheduler.doAsyncRepeating(() -> updateTaskBuffer.request(), ticks);
}
scheduler.doAsyncLater(() -> updateTaskBuffer.request(), 40L);
// run an update instantly.
updateTaskBuffer.requestDirectly();
// register tasks
getServer().getScheduler().runTaskTimerAsynchronously(this, new ExpireTemporaryTask(this), 60L, 60L);
getServer().getScheduler().runTaskTimerAsynchronously(this, new CacheHousekeepingTask(this), 2400L, 2400L);
scheduler.doAsyncRepeating(new ExpireTemporaryTask(this), 60L);
scheduler.doAsyncRepeating(new CacheHousekeepingTask(this), 2400L);
// register permissions
registerPermissions(getConfiguration().isCommandsAllowOp() ? PermissionDefault.OP : PermissionDefault.FALSE);
if (!getConfiguration().isOpsEnabled()) {
getServer().getScheduler().runTask(this, () -> getServer().getOperators().forEach(o -> o.setOp(false)));
registerPermissions(getConfiguration().get(ConfigKeys.COMMANDS_ALLOW_OP) ? PermissionDefault.OP : PermissionDefault.FALSE);
if (!getConfiguration().get(ConfigKeys.OPS_ENABLED)) {
scheduler.doSync(() -> getServer().getOperators().forEach(o -> o.setOp(false)));
}
// replace the temporary executor when the Bukkit one starts
getServer().getScheduler().runTaskAsynchronously(this, () -> {
asyncExecutor = bukkitAsyncExecutor;
scheduler.setUseBukkitAsync(true);
});
// Load any online users (in the case of a reload)
for (Player player : getServer().getOnlinePlayers()) {
doAsync(() -> {
scheduler.doAsync(() -> {
listener.onAsyncLogin(player.getUniqueId(), player.getName());
User user = getUserManager().get(getUuidCache().getUUID(player.getUniqueId()));
if (user != null) {
doSync(() -> {
scheduler.doSync(() -> {
try {
LPPermissible lpPermissible = new LPPermissible(player, user, this);
Injector.inject(player, lpPermissible);
@@ -302,15 +316,18 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
@Override
public void onDisable() {
// Switch back to the LP executor, the bukkit one won't allow new tasks
scheduler.setUseBukkitAsync(false);
started = false;
defaultsProvider.close();
permissionCache.setShutdown(true);
permissionVault.setShutdown(true);
debugHandler.setShutdown(true);
for (Player player : getServer().getOnlinePlayers()) {
Injector.unInject(player, false);
if (getConfiguration().isAutoOp()) {
Injector.unInject(player, false, false);
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
player.setOp(false);
}
@@ -324,9 +341,9 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
getLog().info("Closing datastore...");
storage.shutdown();
if (redisMessaging != null) {
getLog().info("Closing redis...");
redisMessaging.shutdown();
if (messagingService != null) {
getLog().info("Closing messaging service...");
messagingService.close();
}
getLog().info("Unregistering API...");
@@ -337,21 +354,21 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
vaultHook.unhook(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);
// Null everything
ignoringLogs = null;
syncExecutor = null;
asyncExecutor = null;
vaultHook = null;
configuration = null;
userManager = null;
groupManager = null;
trackManager = null;
storage = null;
redisMessaging = null;
messagingService = null;
uuidCache = null;
listener = null;
apiProvider = null;
@@ -367,7 +384,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
updateTaskBuffer = null;
debugHandler = null;
senderFactory = null;
permissionCache = null;
permissionVault = null;
}
public void tryVaultHook(boolean force) {
@@ -399,19 +416,19 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
}
@Override
public void doAsync(Runnable r) {
asyncExecutor.execute(r);
}
public void refreshAutoOp(Player player) {
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
try {
LPPermissible permissible = Injector.getPermissible(player.getUniqueId());
if (permissible == null) {
return;
}
@Override
public void doSync(Runnable r) {
syncExecutor.execute(r);
}
@Override
public void doAsyncRepeating(Runnable r, long interval) {
getServer().getScheduler().runTaskTimerAsynchronously(this, r, interval, interval);
Map<String, Boolean> backing = permissible.getUser().getUserData().getPermissionData(permissible.calculateContexts()).getImmutableBacking();
boolean op = Optional.ofNullable(backing.get("luckperms.autoop")).orElse(false);
player.setOp(op);
} catch (Exception ignored) {}
}
}
@Override
@@ -420,7 +437,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
@Override
public PlatformType getType() {
public PlatformType getServerType() {
return PlatformType.BUKKIT;
}
@@ -435,8 +452,8 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
@Override
public File getMainDir() {
return getDataFolder();
public File getDataDirectory() {
return super.getDataFolder();
}
@Override
@@ -457,11 +474,11 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
return new Contexts(
getContextManager().getApplicableContext(player),
getConfiguration().isIncludingGlobalPerms(),
getConfiguration().isIncludingGlobalWorldPerms(),
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
true,
getConfiguration().isApplyingGlobalGroups(),
getConfiguration().isApplyingGlobalWorldGroups(),
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
player.isOp()
);
}
@@ -482,12 +499,12 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
@Override
public boolean isOnline(UUID external) {
public boolean isPlayerOnline(UUID external) {
return getServer().getPlayer(external) != null;
}
@Override
public List<Sender> getSenders() {
public List<Sender> getOnlineSenders() {
return getServer().getOnlinePlayers().stream()
.map(p -> getSenderFactory().wrap(p))
.collect(Collectors.toList());
@@ -502,14 +519,14 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
public Set<Contexts> getPreProcessContexts(boolean op) {
Set<ContextSet> c = new HashSet<>();
c.add(ContextSet.empty());
c.add(ContextSet.singleton("server", getConfiguration().getServer()));
c.add(ContextSet.singleton("server", getConfiguration().get(ConfigKeys.SERVER)));
// Pre process all worlds
c.addAll(getServer().getWorlds().stream()
.map(World::getName)
.map(s -> {
MutableContextSet set = MutableContextSet.create();
set.add("server", getConfiguration().getServer());
set.add("server", getConfiguration().get(ConfigKeys.SERVER));
set.add("world", s);
return set.makeImmutable();
})
@@ -517,13 +534,13 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
);
// Pre process the separate Vault server, if any
if (!getConfiguration().getServer().equals(getConfiguration().getVaultServer())) {
c.add(ContextSet.singleton("server", getConfiguration().getVaultServer()));
if (!getConfiguration().get(ConfigKeys.SERVER).equals(getConfiguration().get(ConfigKeys.VAULT_SERVER))) {
c.add(ContextSet.singleton("server", getConfiguration().get(ConfigKeys.VAULT_SERVER)));
c.addAll(getServer().getWorlds().stream()
.map(World::getName)
.map(s -> {
MutableContextSet set = MutableContextSet.create();
set.add("server", getConfiguration().getVaultServer());
set.add("server", getConfiguration().get(ConfigKeys.VAULT_SERVER));
set.add("world", s);
return set.makeImmutable();
})
@@ -537,25 +554,25 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
contexts.addAll(c.stream()
.map(set -> new Contexts(
set,
getConfiguration().isIncludingGlobalPerms(),
getConfiguration().isIncludingGlobalWorldPerms(),
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
true,
getConfiguration().isApplyingGlobalGroups(),
getConfiguration().isApplyingGlobalWorldGroups(),
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
op
))
.collect(Collectors.toSet())
);
// Check for and include varying Vault config options
boolean vaultDiff = getConfiguration().isVaultIncludingGlobal() != getConfiguration().isIncludingGlobalPerms() ||
!getConfiguration().isIncludingGlobalWorldPerms() ||
!getConfiguration().isApplyingGlobalGroups() ||
!getConfiguration().isApplyingGlobalWorldGroups();
boolean vaultDiff = getConfiguration().get(ConfigKeys.VAULT_INCLUDING_GLOBAL) != getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS) ||
!getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS) ||
!getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS) ||
!getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS);
if (vaultDiff) {
contexts.addAll(c.stream()
.map(map -> new Contexts(map, getConfiguration().isVaultIncludingGlobal(), true, true, true, true, op))
.map(map -> new Contexts(map, getConfiguration().get(ConfigKeys.VAULT_INCLUDING_GLOBAL), true, true, true, true, op))
.collect(Collectors.toSet())
);
}
@@ -567,33 +584,22 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
public LinkedHashMap<String, Object> getExtraInfo() {
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("Vault Enabled", vaultHook != null);
map.put("Vault Server", configuration.getVaultServer());
map.put("Vault Server", configuration.get(ConfigKeys.VAULT_SERVER));
map.put("Bukkit Defaults count", defaultsProvider.size());
map.put("Bukkit Child Permissions count", childPermissionProvider.getPermissions().size());
map.put("World Cache size", worldCalculator.getWorldCache().size());
map.put("Vault Including Global", configuration.isVaultIncludingGlobal());
map.put("Vault Ignoring World", configuration.isVaultIgnoreWorld());
map.put("Vault Primary Group Overrides", configuration.isVaultPrimaryGroupOverrides());
map.put("Vault Debug", configuration.isVaultDebug());
map.put("OPs Enabled", configuration.isOpsEnabled());
map.put("Auto OP", configuration.isAutoOp());
map.put("Commands Allow OPs", configuration.isCommandsAllowOp());
map.put("Vault Including Global", configuration.get(ConfigKeys.VAULT_INCLUDING_GLOBAL));
map.put("Vault Ignoring World", configuration.get(ConfigKeys.VAULT_IGNORE_WORLD));
map.put("Vault Primary Group Overrides", configuration.get(ConfigKeys.VAULT_PRIMARY_GROUP_OVERRIDES));
map.put("Vault Debug", configuration.get(ConfigKeys.VAULT_DEBUG));
map.put("OPs Enabled", configuration.get(ConfigKeys.OPS_ENABLED));
map.put("Auto OP", configuration.get(ConfigKeys.AUTO_OP));
map.put("Commands Allow OPs", configuration.get(ConfigKeys.COMMANDS_ALLOW_OP));
return map;
}
@Override
public Object getPlugin(String name) {
return getServer().getPluginManager().getPlugin(name);
}
@Override
public Object getService(Class clazz) {
return getServer().getServicesManager().load(clazz);
}
@SuppressWarnings("deprecation")
@Override
public UUID getUUID(String playerName) {
public UUID getUuidFromUsername(String playerName) {
try {
return getServer().getOfflinePlayer(playerName).getUniqueId();
} catch (Exception e) {
@@ -601,11 +607,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
}
@Override
public boolean isPluginLoaded(String name) {
return getServer().getPluginManager().isPluginEnabled(name);
}
private void registerPermissions(PermissionDefault def) {
PluginManager pm = getServer().getPluginManager();
@@ -0,0 +1,116 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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 lombok.Getter;
import lombok.Setter;
import me.lucko.luckperms.common.plugin.LuckPermsScheduler;
import org.bukkit.scheduler.BukkitTask;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class LPBukkitScheduler implements LuckPermsScheduler {
private final LPBukkitPlugin plugin;
@Getter
private ExecutorService asyncLpExecutor;
@Getter
private Executor asyncBukkitExecutor;
private Executor syncExecutor;
@Getter
@Setter
private boolean useBukkitAsync = false;
private Set<BukkitTask> tasks = ConcurrentHashMap.newKeySet();
public LPBukkitScheduler(LPBukkitPlugin plugin) {
this.plugin = plugin;
this.asyncLpExecutor = Executors.newCachedThreadPool();
this.asyncBukkitExecutor = r -> plugin.getServer().getScheduler().runTaskAsynchronously(plugin, r);
this.syncExecutor = r -> plugin.getServer().getScheduler().runTask(plugin, r);
}
@Override
public Executor getAsyncExecutor() {
return useBukkitAsync ? asyncBukkitExecutor : asyncLpExecutor;
}
@Override
public Executor getSyncExecutor() {
return syncExecutor;
}
@Override
public void doAsync(Runnable r) {
getAsyncExecutor().execute(r);
}
@Override
public void doSync(Runnable r) {
getSyncExecutor().execute(r);
}
@Override
public void doAsyncRepeating(Runnable r, long interval) {
BukkitTask task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, r, interval, interval);
tasks.add(task);
}
@Override
public void doSyncRepeating(Runnable r, long interval) {
BukkitTask task = plugin.getServer().getScheduler().runTaskTimer(plugin, r, interval, interval);
tasks.add(task);
}
@Override
public void doAsyncLater(Runnable r, long delay) {
plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, r, delay);
}
@Override
public void doSyncLater(Runnable r, long delay) {
plugin.getServer().getScheduler().runTaskLater(plugin, r, delay);
}
@Override
public void shutdown() {
tasks.forEach(BukkitTask::cancel);
// wait for executor
asyncLpExecutor.shutdown();
try {
asyncLpExecutor.awaitTermination(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@@ -22,35 +22,25 @@
package me.lucko.luckperms.bukkit;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import com.google.common.collect.Maps;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@RequiredArgsConstructor
public class WorldCalculator extends ContextCalculator<Player> implements Listener {
public class WorldCalculator implements ContextCalculator<Player> {
private static final String WORLD_KEY = "world";
private final LuckPermsPlugin plugin;
@Getter
private final Map<UUID, String> worldCache = new ConcurrentHashMap<>();
@Override
public MutableContextSet giveApplicableContext(Player subject, MutableContextSet accumulator) {
String world = getWorld(subject);
@@ -73,34 +63,7 @@ public class WorldCalculator extends ContextCalculator<Player> implements Listen
}
private String getWorld(Player player) {
UUID internal = plugin.getUuidCache().getUUID(player.getUniqueId());
String world = worldCache.get(internal);
if (world == null) {
return null;
}
return plugin.getConfiguration().getWorldRewrites().getOrDefault(world, world);
}
@EventHandler(priority = EventPriority.LOW)
public void onPlayerJoin(PlayerLoginEvent e) {
UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
worldCache.put(internal, e.getPlayer().getWorld().getName());
pushUpdate(
e.getPlayer(),
Maps.immutableEntry(WORLD_KEY, null),
Maps.immutableEntry(WORLD_KEY, e.getPlayer().getWorld().getName())
);
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerChangedWorld(PlayerChangedWorldEvent e) {
UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
worldCache.put(internal, e.getPlayer().getWorld().getName());
pushUpdate(
e.getPlayer(),
Maps.immutableEntry(WORLD_KEY, e.getFrom().getName()),
Maps.immutableEntry(WORLD_KEY, e.getPlayer().getWorld().getName())
);
String world = player.getWorld().getName();
return plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(world, world);
}
}
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.messaging;
import com.google.common.collect.Iterables;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.messaging.AbstractMessagingService;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Collection;
/**
* An implementation of {@link me.lucko.luckperms.api.MessagingService} using the plugin messaging channels.
*/
public class BungeeMessagingService extends AbstractMessagingService implements PluginMessageListener {
private final LPBukkitPlugin plugin;
public BungeeMessagingService(LPBukkitPlugin plugin) {
super(plugin, "Bungee");
this.plugin = plugin;
}
public void init() {
plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, CHANNEL);
plugin.getServer().getMessenger().registerIncomingPluginChannel(plugin, CHANNEL, this);
}
@Override
public void close() {
plugin.getServer().getMessenger().unregisterIncomingPluginChannel(plugin, CHANNEL);
plugin.getServer().getMessenger().unregisterOutgoingPluginChannel(plugin, CHANNEL);
}
@Override
protected void sendMessage(String channel, String message) {
new BukkitRunnable() {
@Override
public void run() {
Collection<? extends Player> players = plugin.getServer().getOnlinePlayers();
if (players.isEmpty()) {
return;
}
Player p = Iterables.getFirst(players, null);
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF(message);
byte[] data = out.toByteArray();
p.sendPluginMessage(plugin, channel, data);
cancel();
}
}.runTaskTimer(plugin, 1L, 100L);
}
@Override
public void onPluginMessageReceived(String s, Player player, byte[] bytes) {
if (!s.equals(CHANNEL)) {
return;
}
ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
String msg = in.readUTF();
onMessage(s, msg, null);
}
}
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.messaging;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.messaging.AbstractMessagingService;
import lilypad.client.connect.api.Connect;
import lilypad.client.connect.api.event.EventListener;
import lilypad.client.connect.api.event.MessageEvent;
import lilypad.client.connect.api.request.RequestException;
import lilypad.client.connect.api.request.impl.MessageRequest;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
/**
* An implementation of {@link me.lucko.luckperms.api.MessagingService} using LilyPad.
*/
public class LilyPadMessagingService extends AbstractMessagingService {
private final LPBukkitPlugin plugin;
private Connect connect;
public LilyPadMessagingService(LPBukkitPlugin plugin) {
super(plugin, "LilyPad");
this.plugin = plugin;
}
public void init() {
connect = plugin.getServer().getServicesManager().getRegistration(Connect.class).getProvider();
connect.registerEvents(this);
}
@Override
public void close() {
connect.unregisterEvents(this);
}
@Override
protected void sendMessage(String channel, String message) {
MessageRequest request;
try {
request = new MessageRequest(Collections.emptyList(), channel, message);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return;
}
try {
connect.request(request);
} catch (RequestException e) {
e.printStackTrace();
}
}
@EventListener
public void onMessage(MessageEvent event) {
plugin.doAsync(() -> {
try {
String channel = event.getChannel();
String message = event.getMessageAsString();
onMessage(channel, message, null);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
@@ -29,19 +29,17 @@ import de.bananaco.bpermissions.api.Permission;
import de.bananaco.bpermissions.api.World;
import de.bananaco.bpermissions.api.WorldManager;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.core.model.PermissionHolder;
import me.lucko.luckperms.common.core.model.User;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.common.utils.ProgressLogger;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -50,6 +48,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import static me.lucko.luckperms.common.constants.Permission.MIGRATION;
@@ -67,6 +66,101 @@ public class MigrationBPermissions extends SubCommand<Object> {
}
}
public MigrationBPermissions() {
super("bpermissions", "Migration from bPermissions", MIGRATION, Predicates.alwaysFalse(), null);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) throws CommandException {
ProgressLogger log = new ProgressLogger("bPermissions");
log.addListener(plugin.getConsoleSender());
log.addListener(sender);
log.log("Starting.");
WorldManager worldManager = WorldManager.getInstance();
if (worldManager == null) {
log.logErr("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
log.log("Forcing the plugin to load all data. This could take a while.");
for (World world : worldManager.getAllWorlds()) {
log.log("Loading users in world " + world.getName());
Set<String> users = getUsers(world);
if (users == null) {
log.logErr("Couldn't get a list of users.");
return CommandResult.FAILURE;
}
AtomicInteger userLoadCount = new AtomicInteger(0);
users.forEach(s -> {
world.loadOne(s, CalculableType.USER);
log.logProgress("Forcefully loaded {} users so far.", userLoadCount.incrementAndGet());
});
}
log.log("Forcefully loaded all users.");
// Migrate one world at a time.
log.log("Starting world migration.");
for (World world : worldManager.getAllWorlds()) {
log.log("Migrating world: " + world.getName());
// Migrate all groups
log.log("Starting group migration in world " + world.getName() + ".");
AtomicInteger groupCount = new AtomicInteger(0);
for (Calculable group : world.getAll(CalculableType.GROUP)) {
String groupName = group.getName().toLowerCase();
if (group.getName().equalsIgnoreCase(world.getDefaultGroup())) {
groupName = "default";
}
// Make a LuckPerms group for the one being migrated.
plugin.getStorage().createAndLoadGroup(groupName, CreationCause.INTERNAL).join();
me.lucko.luckperms.common.core.model.Group lpGroup = plugin.getGroupManager().getIfLoaded(groupName);
migrateHolder(log, world, group, lpGroup);
plugin.getStorage().saveGroup(lpGroup);
log.logAllProgress("Migrated {} groups so far.", groupCount.incrementAndGet());
}
log.log("Migrated " + groupCount.get() + " groups in world " + world.getName() + ".");
// Migrate all users
log.log("Starting user migration in world " + world.getName() + ".");
AtomicInteger userCount = new AtomicInteger(0);
for (Calculable user : world.getAll(CalculableType.USER)) {
// There is no mention of UUIDs in the API. I assume that name = uuid. idk?
UUID uuid;
try {
uuid = UUID.fromString(user.getName());
} catch (IllegalArgumentException e) {
uuid = plugin.getUuidFromUsername(user.getName());
}
if (uuid == null) {
log.logErr("Unable to migrate user " + user.getName() + ". Cannot to get UUID.");
continue;
}
// Make a LuckPerms user for the one being migrated.
plugin.getStorage().loadUser(uuid, "null").join();
User lpUser = plugin.getUserManager().get(uuid);
migrateHolder(log, world, user, lpUser);
plugin.getStorage().saveUser(lpUser);
plugin.getUserManager().cleanup(lpUser);
log.logProgress("Migrated {} users so far.", userCount.incrementAndGet());
}
log.log("Migrated " + userCount.get() + " users in world " + world.getName() + ".");
}
log.log("Success! Migration complete.");
return CommandResult.SUCCESS;
}
@SuppressWarnings("unchecked")
private static Set<String> getUsers(World world) {
try {
@@ -93,33 +187,21 @@ public class MigrationBPermissions extends SubCommand<Object> {
}
}
private static void migrateHolder(LuckPermsPlugin plugin, World world, Calculable c, PermissionHolder holder) {
private static void migrateHolder(ProgressLogger log, World world, Calculable c, PermissionHolder holder) {
// Migrate the groups permissions in this world
for (Permission p : c.getPermissions()) {
try {
holder.setPermission(p.name(), p.isTrue(), "global", world.getName());
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(holder).action("set " + p.name() + " " + p.isTrue() + " global " + world.getName())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
// Include any child permissions
for (Map.Entry<String, Boolean> child : p.getChildren().entrySet()) {
try {
holder.setPermission(child.getKey(), child.getValue(), "global", world.getName());
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(holder).action("set " + child.getKey() + " " + child.getValue() + " global " + world.getName())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
}
@@ -128,14 +210,8 @@ public class MigrationBPermissions extends SubCommand<Object> {
for (Group parent : c.getGroups()) {
try {
holder.setPermission("group." + parent.getName(), true, "global", world.getName());
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(holder).action("setinherit " + parent.getName() + " global " + world.getName())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -145,121 +221,18 @@ public class MigrationBPermissions extends SubCommand<Object> {
String chatMeta = MetaUtils.escapeCharacters(meta.getValue());
try {
holder.setPermission(meta.getKey().toLowerCase() + "." + c.getPriority() + "." + chatMeta, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(holder).action("set " + meta.getKey().toLowerCase() + "." + c.getPriority() + "." + chatMeta + " true")
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
continue;
}
try {
holder.setPermission("meta." + meta.getKey() + "." + meta.getValue(), true, "global", world.getName());
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(holder).action("set meta." + meta.getKey() + "." + meta.getValue() + " true global " + world.getName())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
}
public MigrationBPermissions() {
super("bpermissions", "Migration from bPermissions", MIGRATION, Predicates.alwaysFalse(), null);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) throws CommandException {
final Logger log = plugin.getLog();
WorldManager worldManager = WorldManager.getInstance();
if (worldManager == null) {
log.severe("bPermissions Migration: Error -> bPermissions is not loaded.");
return CommandResult.STATE_ERROR;
}
log.info("bPermissions Migration: Forcing the plugin to load all data. This could take a while.");
for (World world : worldManager.getAllWorlds()) {
Set<String> users = getUsers(world);
if (users == null) {
log.severe("bPermissions Migration: Couldn't get a list of users.");
return CommandResult.FAILURE;
}
users.forEach(s -> world.loadOne(s, CalculableType.USER));
}
// Migrate one world at a time.
log.info("bPermissions Migration: Starting world migration.");
for (World world : worldManager.getAllWorlds()) {
log.info("bPermissions Migration: Migrating world: " + world.getName());
// Migrate all groups
log.info("bPermissions Migration: Starting group migration in world " + world.getName() + ".");
int groupCount = 0;
for (Calculable group : world.getAll(CalculableType.GROUP)) {
groupCount++;
String groupName = group.getName().toLowerCase();
if (group.getName().equalsIgnoreCase(world.getDefaultGroup())) {
groupName = "default";
}
// Make a LuckPerms group for the one being migrated.
plugin.getStorage().createAndLoadGroup(groupName).join();
me.lucko.luckperms.common.core.model.Group lpGroup = plugin.getGroupManager().getIfLoaded(groupName);
try {
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpGroup).action("create")
.build().submit(plugin);
} catch (Exception ex) {
ex.printStackTrace();
}
migrateHolder(plugin, world, group, lpGroup);
plugin.getStorage().saveGroup(lpGroup);
}
log.info("bPermissions Migration: Migrated " + groupCount + " groups in world " + world.getName() + ".");
// Migrate all users
log.info("bPermissions Migration: Starting user migration in world " + world.getName() + ".");
int userCount = 0;
for (Calculable user : world.getAll(CalculableType.USER)) {
userCount++;
// There is no mention of UUIDs in the API. I assume that name = uuid. idk?
UUID uuid;
try {
uuid = UUID.fromString(user.getName());
} catch (IllegalArgumentException e) {
uuid = plugin.getUUID(user.getName());
}
if (uuid == null) {
log.info("bPermissions Migration: Unable to migrate user " + user.getName() + ". Unable to get UUID.");
continue;
}
// Make a LuckPerms user for the one being migrated.
plugin.getStorage().loadUser(uuid, "null").join();
User lpUser = plugin.getUserManager().get(uuid);
migrateHolder(plugin, world, user, lpUser);
plugin.getStorage().saveUser(lpUser);
plugin.getUserManager().cleanup(lpUser);
}
log.info("bPermissions Migration: Migrated " + userCount + " users in world " + world.getName() + ".");
}
log.info("bPermissions Migration: Success! Completed without any errors.");
return CommandResult.SUCCESS;
}
}
@@ -22,18 +22,18 @@
package me.lucko.luckperms.bukkit.migration;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.common.LuckPermsPlugin;
import com.google.common.collect.Maps;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.ProgressLogger;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
@@ -43,50 +43,56 @@ import org.anjocaido.groupmanager.data.Group;
import org.anjocaido.groupmanager.data.User;
import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
import org.anjocaido.groupmanager.dataholder.worlds.WorldsHolder;
import org.bukkit.Bukkit;
import org.bukkit.World;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
public class MigrationGroupManager extends SubCommand<Object> {
public MigrationGroupManager() {
super("groupmanager", "Migration from GroupManager", Permission.MIGRATION, Predicates.is(0),
Arg.list(Arg.create("world names...", false, "a list of worlds to migrate permissions from"))
Arg.list(Arg.create("migrate as global", true, "if world permissions should be ignored, and just migrated as global"))
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) throws CommandException {
final Logger log = plugin.getLog();
if (!plugin.isPluginLoaded("GroupManager")) {
log.severe("GroupManager Migration: Error -> GroupManager is not loaded.");
ProgressLogger log = new ProgressLogger("GroupManager");
log.addListener(plugin.getConsoleSender());
log.addListener(sender);
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.");
return CommandResult.STATE_ERROR;
}
boolean migrateAsGlobal = Boolean.parseBoolean(args.get(0));
final Function<String, String> worldMappingFunc = s -> migrateAsGlobal ? "" : s;
if (!Bukkit.getPluginManager().isPluginEnabled("GroupManager")) {
log.logErr("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
final List<String> worlds = args.stream()
.map(String::toLowerCase)
.collect(Collectors.toList());
List<String> worlds = Bukkit.getWorlds().stream().map(World::getName).map(String::toLowerCase).collect(Collectors.toList());
GroupManager gm = (GroupManager) plugin.getPlugin("GroupManager");
GroupManager gm = (GroupManager) Bukkit.getPluginManager().getPlugin("GroupManager");
// Migrate Global Groups
log.info("GroupManager Migration: Starting Global Group migration.");
log.log("Starting global group migration.");
GlobalGroups gg = GroupManager.getGlobalGroups();
AtomicInteger globalGroupCount = new AtomicInteger(0);
for (Group g : gg.getGroupList()) {
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase()).join();
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase(), CreationCause.INTERNAL).join();
me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(g.getName().toLowerCase());
try {
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("create")
.build().submit(plugin);
} catch (Exception ex) {
ex.printStackTrace();
}
for (String node : g.getPermissionList()) {
boolean value = true;
@@ -100,47 +106,45 @@ public class MigrationGroupManager extends SubCommand<Object> {
try {
group.setPermission(node, value);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("set " + node + " " + value)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
for (String s : g.getInherits()) {
try {
group.setPermission("group." + s.toLowerCase(), true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("setinherit " + s.toLowerCase())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
plugin.getStorage().saveGroup(group);
log.logAllProgress("Migrated {} groups so far.", globalGroupCount.incrementAndGet());
}
log.log("Migrated " + globalGroupCount.get() + " global groups");
// Collect data
// UUID --> Map<Entry<String, String>, Boolean> where k=world, v = node
Map<UUID, Map<Map.Entry<String, String>, Boolean>> users = new HashMap<>();
// UUID --> primary group name
Map<UUID, String> primaryGroups = new HashMap<>();
// String --> Map<Entry<String, String>, Boolean> where k=world, v = node
Map<String, Map<Map.Entry<String, String>, Boolean>> groups = new HashMap<>();
WorldsHolder wh = gm.getWorldsHolder();
// Collect data for all users and groups.
log.info("GroupManager Migration: Starting user and group migration.");
log.log("Collecting user and group data.");
for (String world : worlds) {
world = world.toLowerCase();
log.log("Querying world " + world);
WorldDataHolder wdh = wh.getWorldData(world);
AtomicInteger groupWorldCount = new AtomicInteger(0);
for (Group g : wdh.getGroupList()) {
groups.putIfAbsent(g.getName().toLowerCase(), new HashMap<>());
@@ -154,19 +158,23 @@ public class MigrationGroupManager extends SubCommand<Object> {
value = true;
}
groups.get(g.getName().toLowerCase()).put(new AbstractMap.SimpleEntry<>(world, node), value);
groups.get(g.getName().toLowerCase()).put(Maps.immutableEntry(worldMappingFunc.apply(world), node), value);
}
for (String s : g.getInherits()) {
groups.get(g.getName().toLowerCase()).put(new AbstractMap.SimpleEntry<>(world, "group." + s.toLowerCase()), true);
groups.get(g.getName().toLowerCase()).put(Maps.immutableEntry(worldMappingFunc.apply(world), "group." + s.toLowerCase()), true);
}
log.logAllProgress("Migrated {} groups so far in world " + world, groupWorldCount.incrementAndGet());
}
log.log("Migrated " + groupWorldCount.get() + " groups in world " + world);
AtomicInteger userWorldCount = new AtomicInteger(0);
for (User user : wdh.getUserList()) {
UUID uuid;
try {
uuid = UUID.fromString(user.getUUID());
} catch (IllegalArgumentException e) {
log.logErr("Could not parse UUID for user: " + user.getUUID());
continue;
}
@@ -182,66 +190,56 @@ public class MigrationGroupManager extends SubCommand<Object> {
value = true;
}
users.get(uuid).put(new AbstractMap.SimpleEntry<>(world, node), value);
users.get(uuid).put(Maps.immutableEntry(worldMappingFunc.apply(world), node), value);
}
String finalWorld = world;
String finalWorld = worldMappingFunc.apply(world);
// Collect sub groups
users.get(uuid).putAll(user.subGroupListStringCopy().stream()
.map(n -> "group." + n)
.map(n -> new AbstractMap.SimpleEntry<>(finalWorld, n))
.map(n -> Maps.immutableEntry(finalWorld, n))
.collect(Collectors.toMap(n -> n, n -> true))
);
primaryGroups.put(uuid, user.getGroupName());
log.logProgress("Migrated {} users so far in world " + world, userWorldCount.incrementAndGet());
}
log.log("Migrated " + userWorldCount.get() + " users in world " + world);
}
log.info("GroupManager Migration: All existing GroupManager data has been processed. Now beginning the import process.");
log.info("GroupManager Migration: Found a total of " + users.size() + " users and " + groups.size() + " groups.");
log.log("All data has now been processed, now starting the import process.");
log.log("Found a total of " + users.size() + " users and " + groups.size() + " groups.");
log.log("Starting group migration.");
AtomicInteger groupCount = new AtomicInteger(0);
for (Map.Entry<String, Map<Map.Entry<String, String>, Boolean>> e : groups.entrySet()) {
plugin.getStorage().createAndLoadGroup(e.getKey()).join();
plugin.getStorage().createAndLoadGroup(e.getKey(), CreationCause.INTERNAL).join();
me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(e.getKey());
try {
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("create")
.build().submit(plugin);
} catch (Exception ex) {
ex.printStackTrace();
}
for (Map.Entry<Map.Entry<String, String>, Boolean> n : e.getValue().entrySet()) {
// n.key.key = world
// n.key.value = node
// n.value = true/false
try {
group.setPermission(NodeFactory.fromSerialisedNode("global-" + n.getKey().getKey() + "/" + n.getKey().getValue(), n.getValue()));
if (n.getKey().getValue().startsWith("group.")) {
String groupName = n.getKey().getValue().substring(6);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("setinherit " + groupName + " global " + n.getKey().getKey())
.build().submit(plugin);
if (n.getKey().getKey().equals("")) {
group.setPermission(n.getKey().getValue(), n.getValue());
} else {
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("set " + n.getKey().getValue() + " " + n.getValue() + " global " + n.getKey().getKey())
.build().submit(plugin);
group.setPermission(n.getKey().getValue(), n.getValue(), "global", n.getKey().getKey());
}
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
plugin.getStorage().saveGroup(group);
log.logAllProgress("Migrated {} groups so far.", groupCount.incrementAndGet());
}
log.log("Migrated " + groupCount.get() + " groups");
log.log("Starting user migration.");
AtomicInteger userCount = new AtomicInteger(0);
for (Map.Entry<UUID, Map<Map.Entry<String, String>, Boolean>> e : users.entrySet()) {
plugin.getStorage().loadUser(e.getKey(), "null").join();
me.lucko.luckperms.common.core.model.User user = plugin.getUserManager().get(e.getKey());
@@ -251,25 +249,13 @@ public class MigrationGroupManager extends SubCommand<Object> {
// n.key.value = node
// n.value = true/false
try {
user.setPermission(NodeFactory.fromSerialisedNode("global-" + n.getKey().getKey() + "/" + n.getKey().getValue(), n.getValue()));
if (n.getKey().getValue().startsWith("group.")) {
String group = n.getKey().getValue().substring(6);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("addgroup " + group + " global " + n.getKey().getKey())
.build().submit(plugin);
if (n.getKey().getKey().equals("")) {
user.setPermission(n.getKey().getValue(), n.getValue());
} else {
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("set " + n.getKey().getValue() + " " + n.getValue() + " global " + n.getKey().getKey())
.build().submit(plugin);
user.setPermission(n.getKey().getValue(), n.getValue(), "global", n.getKey().getKey());
}
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -277,20 +263,20 @@ public class MigrationGroupManager extends SubCommand<Object> {
if (primaryGroup != null) {
try {
user.setPermission("group." + primaryGroup, true);
} catch (ObjectAlreadyHasException ignored) {
}
} catch (ObjectAlreadyHasException ignored) {}
user.setPrimaryGroup(primaryGroup);
try {
user.unsetPermission("group.default");
} catch (ObjectLacksException ignored) {
}
} catch (ObjectLacksException ignored) {}
}
plugin.getStorage().saveUser(user);
plugin.getUserManager().cleanup(user);
log.logProgress("Migrated {} users so far.", userCount.incrementAndGet());
}
log.info("GroupManager Migration: Success! Completed without any errors.");
log.log("Migrated " + userCount.get() + " users.");
log.log("Success! Migration complete.");
return CommandResult.SUCCESS;
}
}
@@ -22,22 +22,23 @@
package me.lucko.luckperms.bukkit.migration;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.model.Group;
import me.lucko.luckperms.common.core.model.User;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.ProgressLogger;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import org.bukkit.Bukkit;
import org.bukkit.World;
import ru.tehkode.permissions.NativeInterface;
import ru.tehkode.permissions.PermissionGroup;
@@ -48,35 +49,31 @@ import ru.tehkode.permissions.bukkit.PermissionsEx;
import java.lang.reflect.Field;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class MigrationPermissionsEx extends SubCommand<Object> {
public MigrationPermissionsEx() {
super("permissionsex", "Migration from PermissionsEx", Permission.MIGRATION, Predicates.alwaysFalse(),
Arg.list(Arg.create("world names...", false, "a list of worlds to migrate permissions from"))
);
super("permissionsex", "Migration from PermissionsEx", Permission.MIGRATION, Predicates.alwaysFalse(), null);
}
@SuppressWarnings("deprecation")
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) throws CommandException {
final Logger log = plugin.getLog();
if (!plugin.isPluginLoaded("PermissionsEx")) {
log.severe("PermissionsEx Migration: Error -> PermissionsEx is not loaded.");
ProgressLogger log = new ProgressLogger("PermissionsEx");
log.addListener(plugin.getConsoleSender());
log.addListener(sender);
log.log("Starting.");
if (!Bukkit.getPluginManager().isPluginEnabled("PermissionsEx")) {
log.logErr("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
if (plugin.getType() != PlatformType.BUKKIT) {
// Sponge uses a completely different version of PEX.
log.severe("PEX import is not supported on this platform.");
return CommandResult.STATE_ERROR;
}
List<String> worlds = Bukkit.getWorlds().stream().map(World::getName).map(String::toLowerCase).collect(Collectors.toList());
final List<String> worlds = args.stream()
.map(String::toLowerCase)
.collect(Collectors.toList());
PermissionsEx pex = (PermissionsEx) plugin.getPlugin("PermissionsEx");
PermissionsEx pex = (PermissionsEx) Bukkit.getPluginManager().getPlugin("PermissionsEx");
PermissionManager manager = pex.getPermissionsManager();
NativeInterface ni;
@@ -89,28 +86,22 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
return CommandResult.FAILURE;
}
// Migrate all groups.
log.info("PermissionsEx Migration: Starting group migration.");
int maxGroupWeight = 0;
int groupCount = 0;
log.log("Calculating group weightings.");
int maxWeight = 0;
for (PermissionGroup group : manager.getGroupList()) {
int groupWeight = group.getWeight() * -1;
groupCount++;
maxGroupWeight = Math.max(maxGroupWeight, groupWeight);
maxWeight = Math.max(maxWeight, group.getRank());
}
maxWeight += 5;
// Migrate all groups.
log.log("Starting group migration.");
AtomicInteger groupCount = new AtomicInteger(0);
for (PermissionGroup group : manager.getGroupList()) {
int groupWeight = maxWeight - group.getRank();
final String name = group.getName().toLowerCase();
plugin.getStorage().createAndLoadGroup(name).join();
plugin.getStorage().createAndLoadGroup(name, CreationCause.INTERNAL).join();
Group lpGroup = plugin.getGroupManager().getIfLoaded(name);
try {
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpGroup).action("create")
.build().submit(plugin);
} catch (Exception ex) {
ex.printStackTrace();
}
try {
for (String node : group.getOwnPermissions(null)) {
@@ -122,40 +113,26 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
try {
lpGroup.setPermission(node, value);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpGroup).action("set " + node + " " + value)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
} catch (NullPointerException ignored) {
// Probably won't happen. I have no API docs on getOwnPermissions#null though.
// No docs on if #getOwnPermissions(null) is ok. Should be fine though.
}
if (worlds != null && !worlds.isEmpty()) {
for (String world : worlds) {
for (String node : group.getOwnPermissions(world)) {
boolean value = true;
if (node.startsWith("-")) {
node = node.substring(1);
value = false;
}
for (String world : worlds) {
for (String node : group.getOwnPermissions(world)) {
boolean value = true;
if (node.startsWith("-")) {
node = node.substring(1);
value = false;
}
try {
lpGroup.setPermission(node, value, "global", world);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpGroup).action("set " + node + " " + value + " global " + world)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
try {
lpGroup.setPermission(node, value, "global", world.toLowerCase());
} catch (Exception ex) {
log.handleException(ex);
}
}
}
@@ -163,31 +140,17 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
for (PermissionGroup g : group.getParents()) {
try {
lpGroup.setPermission("group." + g.getName().toLowerCase(), true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpGroup).action("setinherit " + g.getName().toLowerCase())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
if (worlds != null && !worlds.isEmpty()) {
for (String world : worlds) {
for (PermissionGroup g : group.getParents(world)) {
try {
lpGroup.setPermission("group." + g.getName().toLowerCase(), true, "global", world);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpGroup).action("setinherit " + g.getName().toLowerCase() + " global " + world)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
for (String world : worlds) {
for (PermissionGroup g : group.getParents(world)) {
try {
lpGroup.setPermission("group." + g.getName().toLowerCase(), true, "global", world.toLowerCase());
} catch (Exception ex) {
log.handleException(ex);
}
}
}
@@ -199,14 +162,8 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
prefix = MetaUtils.escapeCharacters(prefix);
try {
lpGroup.setPermission("prefix." + groupWeight + "." + prefix, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpGroup).action("set prefix." + groupWeight + "." + prefix + " true")
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -214,45 +171,39 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
suffix = MetaUtils.escapeCharacters(suffix);
try {
lpGroup.setPermission("suffix." + groupWeight + "." + suffix, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpGroup).action("set suffix." + groupWeight + "." + suffix + " true")
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
plugin.getStorage().saveGroup(lpGroup);
log.logAllProgress("Migrated {} groups so far.", groupCount.incrementAndGet());
}
log.info("PermissionsEx Migration: Migrated " + groupCount + " groups");
log.log("Migrated " + groupCount.get() + " groups");
// Migrate all users
log.info("PermissionsEx Migration: Starting user migration.");
int userCount = 0;
maxGroupWeight++;
for (PermissionUser user : manager.getUsers()) {
UUID u = null;
log.log("Starting user migration.");
AtomicInteger userCount = new AtomicInteger(0);
// Increment the max weight from the group migrations. All user meta should override.
maxWeight += 5;
for (PermissionUser user : manager.getUsers()) {
UUID u;
try {
u = UUID.fromString(user.getIdentifier());
} catch (IllegalArgumentException e) {
u = ni.nameToUUID(user.getIdentifier());
if (u == null) {
u = plugin.getUUID(user.getIdentifier());
u = plugin.getUuidFromUsername(user.getIdentifier());
}
}
if (u == null) {
log.severe("Unable to get a UUID for user identifier: " + user.getIdentifier());
log.logErr("Unable to get a UUID for user identifier: " + user.getIdentifier());
continue;
}
userCount++;
plugin.getStorage().loadUser(u, user.getName()).join();
User lpUser = plugin.getUserManager().get(u);
@@ -266,40 +217,26 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
try {
lpUser.setPermission(node, value);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpUser).action("set " + node + " " + value)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
} catch (NullPointerException ignored) {
// Probably won't happen. I have no API docs on getOwnPermissions#null though.
// No docs on if #getOwnPermissions(null) is ok. Should be fine though.
}
if (worlds != null && !worlds.isEmpty()) {
for (String world : worlds) {
for (String node : user.getOwnPermissions(world)) {
boolean value = true;
if (node.startsWith("-")) {
node = node.substring(1);
value = false;
}
for (String world : worlds) {
for (String node : user.getOwnPermissions(world)) {
boolean value = true;
if (node.startsWith("-")) {
node = node.substring(1);
value = false;
}
try {
lpUser.setPermission(node, value, "global", world);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpUser).action("set " + node + " " + value + " global " + world)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
try {
lpUser.setPermission(node, value, "global", world.toLowerCase());
} catch (Exception ex) {
log.handleException(ex);
}
}
}
@@ -307,31 +244,17 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
for (String s : user.getGroupNames()) {
try {
lpUser.setPermission("group." + s.toLowerCase(), true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpUser).action("addgroup " + s.toLowerCase())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
if (worlds != null && !worlds.isEmpty()) {
for (String world : worlds) {
for (String s : user.getGroupNames(world)) {
try {
lpUser.setPermission("group." + s.toLowerCase(), true, "global", world);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpUser).action("addgroup " + s.toLowerCase() + " global " + world)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
for (String world : worlds) {
for (String s : user.getGroupNames(world)) {
try {
lpUser.setPermission("group." + s.toLowerCase(), true, "global", world.toLowerCase());
} catch (Exception ex) {
log.handleException(ex);
}
}
}
@@ -342,56 +265,48 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
if (prefix != null && !prefix.equals("")) {
prefix = MetaUtils.escapeCharacters(prefix);
try {
lpUser.setPermission("prefix." + maxGroupWeight + "." + prefix, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpUser).action("set prefix." + maxGroupWeight + "." + prefix + " true")
.build().submit(plugin);
lpUser.setPermission("prefix." + maxWeight + "." + prefix, true);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
if (suffix != null && !suffix.equals("")) {
suffix = MetaUtils.escapeCharacters(suffix);
try {
lpUser.setPermission("suffix." + maxGroupWeight + "." + suffix, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(lpUser).action("set suffix." + maxGroupWeight + "." + suffix + " true")
.build().submit(plugin);
lpUser.setPermission("suffix." + maxWeight + "." + suffix, true);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
// Lowest rank is the highest group #logic
String primary = null;
int weight = -100;
int weight = Integer.MAX_VALUE;
for (PermissionGroup group : user.getOwnParents()) {
if (group.getRank() > weight) {
if (group.getRank() < weight) {
primary = group.getName();
weight = group.getWeight();
weight = group.getRank();
}
}
if (primary != null) {
if (primary != null && !primary.equalsIgnoreCase("default")) {
try {
lpUser.setPermission("group." + primary.toLowerCase(), true);
} catch (ObjectAlreadyHasException ignored) {
}
} catch (ObjectAlreadyHasException ignored) {}
lpUser.setPrimaryGroup(primary);
try {
lpUser.unsetPermission("group.default");
} catch (ObjectLacksException ignored) {}
}
plugin.getUserManager().cleanup(lpUser);
plugin.getStorage().saveUser(lpUser);
log.logProgress("Migrated {} users so far.", userCount.incrementAndGet());
}
log.info("PermissionsEx Migration: Migrated " + userCount + " users.");
log.info("PermissionsEx Migration: Success! Completed without any errors.");
log.log("Migrated " + userCount.get() + " users.");
log.log("Success! Migration complete.");
return CommandResult.SUCCESS;
}
}
@@ -22,8 +22,6 @@
package me.lucko.luckperms.bukkit.migration;
import lombok.Cleanup;
import com.github.cheesesoftware.PowerfulPermsAPI.CachedGroup;
import com.github.cheesesoftware.PowerfulPermsAPI.Group;
import com.github.cheesesoftware.PowerfulPermsAPI.Permission;
@@ -33,21 +31,20 @@ import com.github.cheesesoftware.PowerfulPermsAPI.ResultRunnable;
import com.google.common.util.concurrent.ListenableFuture;
import com.zaxxer.hikari.HikariDataSource;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.bukkit.migration.utils.LPResultRunnable;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.core.model.PermissionHolder;
import me.lucko.luckperms.common.core.model.User;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.common.utils.ProgressLogger;
import org.bukkit.Bukkit;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -64,25 +61,18 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import static me.lucko.luckperms.common.constants.Permission.MIGRATION;
@SuppressWarnings("unchecked")
public class MigrationPowerfulPerms extends SubCommand<Object> {
/* <sadness>
The PowerfulPerms API is a complete joke. Seriously, it would probably be easier reflecting into the actual plugin.
Methods move about randomly every version...
What kind of API requires reflection to function with multiple versions...
Doesn't that just defeat the whole god damn point of having an API in the first place?
Whatever happened to depreciation?
</sadness> */
private static Method getPlayerPermissionsMethod = null;
private static Method getPlayerGroupsMethod = null;
private static Method getGroupMethod = null;
// lol
// lol, nice "api"
private static boolean superLegacy = false;
private static boolean legacy = false;
@@ -90,29 +80,25 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
try {
Class.forName("com.github.cheesesoftware.PowerfulPermsAPI.ResponseRunnable");
legacy = true;
} catch (ClassNotFoundException ignored) {
}
} catch (ClassNotFoundException ignored) {}
if (legacy) {
try {
getPlayerPermissionsMethod = PermissionManager.class.getMethod("getPlayerOwnPermissions", UUID.class, ResultRunnable.class);
getPlayerPermissionsMethod.setAccessible(true);
} catch (NoSuchMethodException ignored) {
}
} catch (NoSuchMethodException ignored) {}
} else {
try {
getPlayerPermissionsMethod = PermissionManager.class.getMethod("getPlayerOwnPermissions", UUID.class);
getPlayerPermissionsMethod.setAccessible(true);
} catch (NoSuchMethodException ignored) {
}
} catch (NoSuchMethodException ignored) {}
}
try {
getGroupMethod = CachedGroup.class.getMethod("getGroup");
getGroupMethod.setAccessible(true);
superLegacy = true;
} catch (NoSuchMethodException ignored) {
}
} catch (NoSuchMethodException ignored) {}
if (!legacy) {
try {
@@ -136,42 +122,6 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
}
}
private static void getPlayerPermissions(PermissionManager manager, UUID uuid, Callback<List<Permission>> callback) {
if (legacy) {
try {
getPlayerPermissionsMethod.invoke(manager, uuid, new LPResultRunnable<List<Permission>>() {
@Override
public void run() {
callback.onComplete(getResult());
}
});
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
} else {
try {
ListenableFuture<List<Permission>> lf = (ListenableFuture<List<Permission>>) getPlayerPermissionsMethod.invoke(manager, uuid);
try {
if (lf.isDone()) {
callback.onComplete(lf.get());
} else {
lf.addListener(() -> {
try {
callback.onComplete(lf.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}, Runnable::run);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
public MigrationPowerfulPerms() {
super("powerfulperms", "Migration from PowerfulPerms", MIGRATION, Predicates.not(5),
Arg.list(
@@ -187,17 +137,22 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) throws CommandException {
try {
return run(plugin, args);
return run(plugin, sender, args);
} catch (Throwable t) {
t.printStackTrace();
return CommandResult.FAILURE;
}
}
private CommandResult run(LuckPermsPlugin plugin, List<String> args) {
final Logger log = plugin.getLog();
if (!plugin.isPluginLoaded("PowerfulPerms")) {
log.severe("PowerfulPerms Migration: Error -> PowerfulPerms is not loaded.");
private CommandResult run(LuckPermsPlugin plugin, Sender sender, List<String> args) {
ProgressLogger log = new ProgressLogger("PowerfulPerms");
log.addListener(plugin.getConsoleSender());
log.addListener(sender);
log.log("Starting.");
if (!Bukkit.getPluginManager().isPluginEnabled("PowerfulPerms")) {
log.logErr("PowerfulPerms is not loaded.");
return CommandResult.STATE_ERROR;
}
@@ -208,100 +163,90 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
final String dbTable = args.get(4);
// Find a list of UUIDs
log.info("PowerfulPerms Migration: Getting a list of UUIDs to migrate.");
@Cleanup HikariDataSource hikari = new HikariDataSource();
hikari.setMaximumPoolSize(2);
hikari.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
hikari.addDataSourceProperty("serverName", address.split(":")[0]);
hikari.addDataSourceProperty("port", address.split(":")[1]);
hikari.addDataSourceProperty("databaseName", database);
hikari.addDataSourceProperty("user", username);
hikari.addDataSourceProperty("password", password);
log.log("Getting a list of UUIDs to migrate.");
Set<UUID> uuids = new HashSet<>();
try {
@Cleanup Connection connection = hikari.getConnection();
DatabaseMetaData meta = connection.getMetaData();
try (HikariDataSource hikari = new HikariDataSource()) {
hikari.setMaximumPoolSize(2);
hikari.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
hikari.addDataSourceProperty("serverName", address.split(":")[0]);
hikari.addDataSourceProperty("port", address.split(":")[1]);
hikari.addDataSourceProperty("databaseName", database);
hikari.addDataSourceProperty("user", username);
hikari.addDataSourceProperty("password", password);
@Cleanup ResultSet tables = meta.getTables(null, null, dbTable, null);
if (!tables.next()) {
log.severe("PowerfulPerms Migration: Error - Couldn't find table.");
return CommandResult.FAILURE;
try (Connection c = hikari.getConnection()) {
DatabaseMetaData meta = c.getMetaData();
} else {
@Cleanup PreparedStatement columnPs = connection.prepareStatement("SELECT COLUMN_NAME, COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=?");
columnPs.setString(1, dbTable);
@Cleanup ResultSet columnRs = columnPs.executeQuery();
log.info("Found table: " + dbTable);
while (columnRs.next()) {
log.info("" + columnRs.getString("COLUMN_NAME") + " - " + columnRs.getString("COLUMN_TYPE"));
}
@Cleanup PreparedStatement preparedStatement = connection.prepareStatement("SELECT `uuid` FROM " + dbTable);
@Cleanup ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
uuids.add(UUID.fromString(resultSet.getString("uuid")));
try (ResultSet rs = meta.getTables(null, null, dbTable, null)) {
if (!rs.next()) {
log.log("Error - Couldn't find table.");
return CommandResult.FAILURE;
}
}
}
try (Connection c = hikari.getConnection()) {
try (PreparedStatement ps = c.prepareStatement("SELECT COLUMN_NAME, COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=?")) {
ps.setString(1, dbTable);
try (ResultSet rs = ps.executeQuery()) {
log.log("Found table: " + dbTable);
while (rs.next()) {
log.log("" + rs.getString("COLUMN_NAME") + " - " + rs.getString("COLUMN_TYPE"));
}
}
}
try (PreparedStatement ps = c.prepareStatement("SELECT `uuid` FROM " + dbTable)) {
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
uuids.add(UUID.fromString(rs.getString("uuid")));
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
return CommandResult.FAILURE;
}
if (uuids.isEmpty()) {
log.severe("PowerfulPerms Migration: Error - Unable to find any UUIDs to migrate.");
log.logErr("Unable to find any UUIDs to migrate.");
return CommandResult.FAILURE;
}
log.info("PowerfulPerms Migration: Found " + uuids.size() + " uuids. Starting migration.");
log.log("Found " + uuids.size() + " uuids. Starting migration.");
PowerfulPermsPlugin ppPlugin = (PowerfulPermsPlugin) plugin.getPlugin("PowerfulPerms");
PowerfulPermsPlugin ppPlugin = (PowerfulPermsPlugin) Bukkit.getPluginManager().getPlugin("PowerfulPerms");
PermissionManager pm = ppPlugin.getPermissionManager();
// Groups first.
log.info("PowerfulPerms Migration: Starting group migration.");
log.log("Starting group migration.");
AtomicInteger groupCount = new AtomicInteger(0);
Map<Integer, Group> groups = pm.getGroups(); // All versions
for (Group g : groups.values()) {
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase()).join();
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase(), CreationCause.INTERNAL).join();
final me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(g.getName().toLowerCase());
try {
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("create")
.build().submit(plugin);
} catch (Exception ex) {
ex.printStackTrace();
}
for (Permission p : g.getOwnPermissions()) { // All versions
applyPerm(group, p, plugin);
applyPerm(group, p, log);
}
for (Group parent : g.getParents()) { // All versions
try {
group.setPermission("group." + parent.getName().toLowerCase(), true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("setinherit " + parent.getName().toLowerCase()) // All versions
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
plugin.getStorage().saveGroup(group);
log.logAllProgress("Migrated {} groups so far.", groupCount.incrementAndGet());
}
log.info("PowerfulPerms Migration: Group migration complete.");
log.log("Migrated " + groupCount.get() + " groups");
// Now users.
log.info("PowerfulPerms Migration: Starting user migration.");
log.log("Starting user migration.");
final Map<UUID, CountDownLatch> progress = new HashMap<>();
// Migrate all users and their groups
@@ -314,7 +259,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
// Get a list of Permissions held by the user from the PP API.
getPlayerPermissions(pm, uuid, perms -> { // Changes each version
perms.forEach(p -> applyPerm(user, p, plugin));
perms.forEach(p -> applyPerm(user, p, log));
// Update the progress so the user can be saved and unloaded.
synchronized (progress) {
@@ -327,7 +272,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
});
// Migrate the user's groups to LuckPerms from PP.
Callback<Map<String, List<CachedGroup>>> callback = groups1 -> {
Consumer<Map<String, List<CachedGroup>>> callback = groups1 -> {
for (Map.Entry<String, List<CachedGroup>> e : groups1.entrySet()) {
final String server;
if (e.getKey() != null && (e.getKey().equals("") || e.getKey().equalsIgnoreCase("all"))) {
@@ -352,26 +297,14 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
if (server == null) {
try {
user.setPermission("group." + g.getName().toLowerCase(), true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("addgroup " + g.getName().toLowerCase())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
} else {
try {
user.setPermission("group." + g.getName().toLowerCase(), true, server);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("addgroup " + g.getName().toLowerCase() + " " + server)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
}
@@ -385,26 +318,14 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
if (server == null) {
try {
user.setPermission("group." + group.getName().toLowerCase(), true, g.getExpirationDate().getTime() / 1000L);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("addtempgroup " + group.getName().toLowerCase() + " " + g.getExpirationDate().getTime() / 1000L)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
} else {
try {
user.setPermission("group." + group.getName().toLowerCase(), true, server, g.getExpirationDate().getTime() / 1000L);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("addtempgroup " + group.getName().toLowerCase() + " " + g.getExpirationDate().getTime() / 1000L + " " + server)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -412,26 +333,14 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
if (server == null) {
try {
user.setPermission("group." + group.getName().toLowerCase(), true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("addgroup " + group.getName().toLowerCase())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
} else {
try {
user.setPermission("group." + group.getName().toLowerCase(), true, server);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("addgroup " + group.getName().toLowerCase() + " " + server)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
}
@@ -454,11 +363,11 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
ListenableFuture<LinkedHashMap<String, List<CachedGroup>>> future = (ListenableFuture<LinkedHashMap<String, List<CachedGroup>>>) getPlayerGroupsMethod.invoke(pm, uuid);
try {
if (future.isDone()) {
callback.onComplete(future.get());
callback.accept(future.get());
} else {
future.addListener(() -> {
try {
callback.onComplete(future.get());
callback.accept(future.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
@@ -468,7 +377,6 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
e.printStackTrace();
}
} catch (IllegalAccessException | InvocationTargetException e) {
log.info("PowerfulPerms Migration: Error");
e.printStackTrace();
}
} else {
@@ -476,11 +384,10 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
getPlayerGroupsMethod.invoke(pm, uuid, new LPResultRunnable<LinkedHashMap<String, List<CachedGroup>>>() {
@Override
public void run() {
callback.onComplete(getResult());
callback.accept(getResult());
}
});
} catch (IllegalAccessException | InvocationTargetException e) {
log.info("PowerfulPerms Migration: Error");
e.printStackTrace();
}
}
@@ -488,7 +395,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
// All groups are migrated, but there may still be some users being migrated.
// This block will wait for all users to be completed.
log.info("PowerfulPerms Migration: Waiting for user migration to complete. This may take some time");
log.log("Waiting for user migration to complete. This may take some time");
boolean sleep = true;
while (sleep) {
sleep = false;
@@ -511,11 +418,11 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
}
// We done.
log.info("PowerfulPerms Migration: Success! Completed without any errors.");
log.log("Success! Migration complete.");
return CommandResult.SUCCESS;
}
private void applyPerm(PermissionHolder holder, Permission p, LuckPermsPlugin plugin) {
private void applyPerm(PermissionHolder holder, Permission p, ProgressLogger log) {
String node = p.getPermissionString();
boolean value = true;
if (node.startsWith("!")) {
@@ -548,26 +455,14 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
if (expireAt == 0L) {
try {
holder.setPermission(node, value, server, world);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(holder).action("set " + node + " " + value + " " + server + " " + world)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
} else {
try {
holder.setPermission(node, value, server, world, expireAt);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(holder).action("settemp " + node + " " + value + " " + expireAt + " " + server + " " + world)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -575,54 +470,66 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
if (expireAt == 0L) {
try {
holder.setPermission(node, value, server);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(holder).action("set " + node + " " + value + " " + server)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
} else {
try {
holder.setPermission(node, value, server, expireAt);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(holder).action("settemp " + node + " " + value + " " + expireAt + " " + server)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
} else {
if (expireAt == 0L) {
try {
holder.setPermission(node, value);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(holder).action("set " + node + " " + value)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
} else {
try {
holder.setPermission(node, value, expireAt);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(holder).action("settemp " + node + " " + value + " " + expireAt)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
}
}
private static void getPlayerPermissions(PermissionManager manager, UUID uuid, Consumer<List<Permission>> callback) {
if (legacy) {
try {
getPlayerPermissionsMethod.invoke(manager, uuid, new LPResultRunnable<List<Permission>>() {
@Override
public void run() {
callback.accept(getResult());
}
});
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
} else {
try {
ListenableFuture<List<Permission>> lf = (ListenableFuture<List<Permission>>) getPlayerPermissionsMethod.invoke(manager, uuid);
try {
if (lf.isDone()) {
callback.accept(lf.get());
} else {
lf.addListener(() -> {
try {
callback.accept(lf.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}, Runnable::run);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
@@ -22,8 +22,7 @@
package me.lucko.luckperms.bukkit.migration;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
@@ -34,9 +33,12 @@ import me.lucko.luckperms.common.core.model.Group;
import me.lucko.luckperms.common.core.model.PermissionHolder;
import me.lucko.luckperms.common.core.model.Track;
import me.lucko.luckperms.common.core.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.ProgressLogger;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import org.bukkit.Bukkit;
import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
import org.tyrannyofheaven.bukkit.zPermissions.dao.PermissionService;
import org.tyrannyofheaven.bukkit.zPermissions.model.EntityMetadata;
@@ -48,29 +50,34 @@ import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity;
import java.lang.reflect.Field;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
public class MigrationZPermissions extends SubCommand<Object> {
public MigrationZPermissions() {
super("zpermissions", "Migration from zPermissions", Permission.MIGRATION, Predicates.alwaysFalse(), null);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) throws CommandException {
final Logger log = plugin.getLog();
if (!plugin.isPluginLoaded("zPermissions")) {
log.severe("zPermissions Migration: Error -> zPermissions is not loaded.");
ProgressLogger log = new ProgressLogger("PermissionManager");
log.addListener(plugin.getConsoleSender());
log.addListener(sender);
log.log("Starting.");
if (!Bukkit.getPluginManager().isPluginEnabled("zPermissions")) {
log.logErr("zPermissions is not loaded.");
return CommandResult.STATE_ERROR;
}
ZPermissionsService service = (ZPermissionsService) plugin.getService(ZPermissionsService.class);
if (service == null) {
log.severe("zPermissions Migration: Error -> zPermissions is not loaded.");
if (!Bukkit.getServicesManager().isProvidedFor(ZPermissionsService.class)) {
log.logErr("zPermissions is not loaded.");
return CommandResult.STATE_ERROR;
}
ZPermissionsService service = Bukkit.getServicesManager().getRegistration(ZPermissionsService.class).getProvider();
PermissionService internalService;
try {
Field psField = service.getClass().getDeclaredField("permissionService");
psField.setAccessible(true);
@@ -81,28 +88,35 @@ public class MigrationZPermissions extends SubCommand<Object> {
}
// Migrate all groups
log.info("zPermissions Migration: Starting group migration.");
log.log("Starting group migration.");
AtomicInteger groupCount = new AtomicInteger(0);
for (String g : service.getAllGroups()) {
plugin.getStorage().createAndLoadGroup(g.toLowerCase()).join();
plugin.getStorage().createAndLoadGroup(g.toLowerCase(), CreationCause.INTERNAL).join();
Group group = plugin.getGroupManager().getIfLoaded(g.toLowerCase());
PermissionEntity entity = internalService.getEntity(g, null, true);
migrateEntity(group, entity, null);
plugin.getStorage().saveGroup(group);
log.logAllProgress("Migrated {} groups so far.", groupCount.incrementAndGet());
}
log.log("Migrated " + groupCount.get() + " groups");
// Migrate all tracks
log.info("zPermissions Migration: Starting track migration.");
log.log("Starting track migration.");
AtomicInteger trackCount = new AtomicInteger(0);
for (String t : service.getAllTracks()) {
plugin.getStorage().createAndLoadTrack(t.toLowerCase()).join();
plugin.getStorage().createAndLoadTrack(t.toLowerCase(), CreationCause.INTERNAL).join();
Track track = plugin.getTrackManager().getIfLoaded(t.toLowerCase());
track.setGroups(service.getTrackGroups(t));
plugin.getStorage().saveTrack(track);
log.logAllProgress("Migrated {} tracks so far.", trackCount.incrementAndGet());
}
log.log("Migrated " + trackCount.get() + " tracks");
// Migrate all users.
log.info("zPermissions Migration: Starting user migration.");
log.log("Starting user migration.");
AtomicInteger userCount = new AtomicInteger(0);
for (UUID u : service.getAllPlayersUUID()) {
plugin.getStorage().loadUser(u, "null").join();
User user = plugin.getUserManager().get(u);
@@ -118,9 +132,11 @@ public class MigrationZPermissions extends SubCommand<Object> {
plugin.getUserManager().cleanup(user);
plugin.getStorage().saveUser(user);
log.logProgress("Migrated {} users so far.", userCount.incrementAndGet());
}
log.info("zPermissions Migration: Success! Completed without any errors.");
log.log("Migrated " + userCount.get() + " users.");
log.log("Success! Migration complete.");
return CommandResult.SUCCESS;
}
@@ -129,13 +145,11 @@ public class MigrationZPermissions extends SubCommand<Object> {
if (e.getWorld() != null) {
try {
group.setPermission(e.getPermission(), true, "global", e.getWorld().getName());
} catch (ObjectAlreadyHasException ignored) {
}
} catch (ObjectAlreadyHasException ignored) {}
} else {
try {
group.setPermission(e.getPermission(), true); // TODO handle negated.
} catch (ObjectAlreadyHasException ignored) {
}
} catch (ObjectAlreadyHasException ignored) {}
}
}
@@ -145,16 +159,14 @@ public class MigrationZPermissions extends SubCommand<Object> {
if (!inheritance.getParent().getName().equals(group.getObjectName())) {
group.setPermission("group." + inheritance.getParent().getName(), true);
}
} catch (ObjectAlreadyHasException ignored) {
}
} catch (ObjectAlreadyHasException ignored) {}
}
} else {
// entity.getMemberships() doesn't work (always returns 0 records)
for (Membership membership : memberships) {
try {
group.setPermission("group." + membership.getGroup().getDisplayName(), true);
} catch (ObjectAlreadyHasException ignored) {
}
} catch (ObjectAlreadyHasException ignored) {}
}
}
@@ -36,6 +36,33 @@ import java.util.Map;
public class ChildPermissionProvider {
@Getter
private ImmutableMap<Map.Entry<String, Boolean>, ImmutableMap<String, Boolean>> permissions = ImmutableMap.of();
public void setup() {
ImmutableMap.Builder<Map.Entry<String, Boolean>, ImmutableMap<String, Boolean>> permissions = ImmutableMap.builder();
for (Permission permission : Bukkit.getServer().getPluginManager().getPermissions()) {
// handle true
Map<String, Boolean> trueChildren = new HashMap<>();
resolveChildren(trueChildren, Collections.singletonMap(permission.getName(), true), false);
trueChildren.remove(permission.getName(), true);
if (!trueChildren.isEmpty()) {
permissions.put(Maps.immutableEntry(permission.getName().toLowerCase(), true), ImmutableMap.copyOf(trueChildren));
}
// handle false
Map<String, Boolean> falseChildren = new HashMap<>();
resolveChildren(falseChildren, Collections.singletonMap(permission.getName(), false), false);
falseChildren.remove(permission.getName(), false);
if (!falseChildren.isEmpty()) {
permissions.put(Maps.immutableEntry(permission.getName().toLowerCase(), false), ImmutableMap.copyOf(falseChildren));
}
}
this.permissions = permissions.build();
}
private static void resolveChildren(Map<String, Boolean> accumulator, Map<String, Boolean> children, boolean invert) {
for (Map.Entry<String, Boolean> e : children.entrySet()) {
if (accumulator.containsKey(e.getKey())) {
@@ -53,25 +80,4 @@ public class ChildPermissionProvider {
}
}
}
@Getter
private ImmutableMap<Map.Entry<String, Boolean>, ImmutableMap<String, Boolean>> permissions = ImmutableMap.of();
public void setup() {
Map<Map.Entry<String, Boolean>, ImmutableMap<String, Boolean>> permissions = new HashMap<>();
for (Permission permission : Bukkit.getServer().getPluginManager().getPermissions()) {
// handle true
Map<String, Boolean> children = new HashMap<>();
resolveChildren(children, Collections.singletonMap(permission.getName(), true), false);
permissions.put(Maps.immutableEntry(permission.getName().toLowerCase(), true), ImmutableMap.copyOf(children));
// handle false
Map<String, Boolean> nChildren = new HashMap<>();
resolveChildren(nChildren, Collections.singletonMap(permission.getName(), false), false);
permissions.put(Maps.immutableEntry(permission.getName().toLowerCase(), false), ImmutableMap.copyOf(nChildren));
}
this.permissions = ImmutableMap.copyOf(permissions);
}
}
@@ -22,7 +22,6 @@
package me.lucko.luckperms.bukkit.model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import com.google.common.collect.ImmutableMap;
@@ -30,57 +29,14 @@ import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.api.Tristate;
import org.bukkit.Bukkit;
import org.bukkit.permissions.Permissible;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class DefaultsProvider {
private static void unregisterDefaults(Map<String, Boolean> map, DummyPermissible p) {
Set<String> perms = map.keySet();
for (String name : perms) {
Bukkit.getServer().getPluginManager().unsubscribeFromPermission(name, p);
}
Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(false, p);
Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(true, p);
}
private static void calculateDefaults(Map<String, Boolean> map, DummyPermissible p, boolean op) {
Set<Permission> defaults = Bukkit.getServer().getPluginManager().getDefaultPermissions(op);
Bukkit.getServer().getPluginManager().subscribeToDefaultPerms(op, p);
for (Permission perm : defaults) {
String name = perm.getName().toLowerCase();
map.put(name, true);
Bukkit.getServer().getPluginManager().subscribeToPermission(name, p);
calculateChildPermissions(map, p, perm.getChildren(), false);
}
}
private static void calculateChildPermissions(Map<String, Boolean> map, DummyPermissible p, Map<String, Boolean> children, boolean invert) {
for (Map.Entry<String, Boolean> e : children.entrySet()) {
Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey());
boolean value = e.getValue() ^ invert;
String lName = e.getKey().toLowerCase();
map.put(lName, value);
Bukkit.getServer().getPluginManager().subscribeToPermission(e.getKey(), p);
if (perm != null) {
calculateChildPermissions(map, p, perm.getChildren(), !value);
}
}
}
@Getter
private Map<String, Boolean> opDefaults = ImmutableMap.of();
private final DummyPermissible opDummy = new DummyPermissible(this::refreshOp);
@@ -128,73 +84,41 @@ public class DefaultsProvider {
return opDefaults.size() + nonOpDefaults.size();
}
@AllArgsConstructor
private static class DummyPermissible implements Permissible {
private final Runnable onRefresh;
private static void unregisterDefaults(Map<String, Boolean> map, DummyPermissible p) {
Set<String> perms = map.keySet();
@Override
public void recalculatePermissions() {
onRefresh.run();
for (String name : perms) {
Bukkit.getServer().getPluginManager().unsubscribeFromPermission(name, p);
}
@Override
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
return Collections.emptySet();
Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(false, p);
Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(true, p);
}
private static void calculateDefaults(Map<String, Boolean> map, DummyPermissible p, boolean op) {
Set<Permission> defaults = Bukkit.getServer().getPluginManager().getDefaultPermissions(op);
Bukkit.getServer().getPluginManager().subscribeToDefaultPerms(op, p);
for (Permission perm : defaults) {
String name = perm.getName().toLowerCase();
map.put(name, true);
Bukkit.getServer().getPluginManager().subscribeToPermission(name, p);
calculateChildPermissions(map, p, perm.getChildren(), false);
}
}
@Override
public boolean isPermissionSet(String name) {
return false;
}
private static void calculateChildPermissions(Map<String, Boolean> map, DummyPermissible p, Map<String, Boolean> children, boolean invert) {
for (Map.Entry<String, Boolean> e : children.entrySet()) {
Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey());
boolean value = e.getValue() ^ invert;
String lName = e.getKey().toLowerCase();
@Override
public boolean isPermissionSet(Permission perm) {
return false;
}
@Override
public boolean hasPermission(String name) {
return false;
}
@Override
public boolean hasPermission(Permission perm) {
return false;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
return null;
}
@Override
public void removeAttachment(PermissionAttachment attachment) {
}
@Override
public boolean isOp() {
return false;
}
@Override
public void setOp(boolean value) {
map.put(lName, value);
Bukkit.getServer().getPluginManager().subscribeToPermission(e.getKey(), p);
if (perm != null) {
calculateChildPermissions(map, p, perm.getChildren(), !value);
}
}
}
@@ -0,0 +1,104 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.model;
import lombok.AllArgsConstructor;
import org.bukkit.permissions.Permissible;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
import java.util.Collections;
import java.util.Set;
@AllArgsConstructor
public class DummyPermissible implements Permissible {
private final Runnable onRefresh;
@Override
public void recalculatePermissions() {
onRefresh.run();
}
@Override
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
return Collections.emptySet();
}
@Override
public boolean isPermissionSet(String name) {
return false;
}
@Override
public boolean isPermissionSet(Permission perm) {
return false;
}
@Override
public boolean hasPermission(String name) {
return false;
}
@Override
public boolean hasPermission(Permission perm) {
return false;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
return null;
}
@Override
public void removeAttachment(PermissionAttachment attachment) {
}
@Override
public boolean isOp() {
return false;
}
@Override
public void setOp(boolean value) {
}
}
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit.inject;
package me.lucko.luckperms.bukkit.model;
import org.bukkit.permissions.PermissibleBase;
import org.bukkit.permissions.Permission;
@@ -20,12 +20,10 @@
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit.inject;
package me.lucko.luckperms.bukkit.model;
import lombok.experimental.UtilityClass;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.permissions.PermissibleBase;
@@ -88,13 +86,16 @@ public class Injector {
}
}
public static boolean unInject(Player player, boolean dummy) {
public static boolean unInject(Player player, boolean dummy, boolean unsubscribe) {
try {
PermissibleBase permissible = (PermissibleBase) HUMAN_ENTITY_FIELD.get(player);
if (permissible instanceof LPPermissible) {
permissible.clearPermissions();
((LPPermissible) permissible).unsubscribeFromAllAsync();
if (unsubscribe) {
((LPPermissible) permissible).unsubscribeFromAllAsync();
}
if (dummy) {
HUMAN_ENTITY_FIELD.set(player, new DummyPermissibleBase());
@@ -29,6 +29,8 @@ import lombok.Setter;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.caching.UserCache;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.core.model.User;
import org.bukkit.Bukkit;
@@ -53,28 +55,19 @@ import java.util.stream.Collectors;
/**
* Modified PermissibleBase for LuckPerms
*/
@Getter
public class LPPermissible extends PermissibleBase {
@Getter
private final User user;
@Getter
private final Player parent;
@Getter
private final LPBukkitPlugin plugin;
@Getter
private final SubscriptionManager subscriptions;
@Getter
@Setter
private PermissibleBase oldPermissible = null;
// Attachment stuff.
@Getter
private final Map<String, PermissionAttachmentInfo> attachmentPermissions = new ConcurrentHashMap<>();
@Getter
private final List<PermissionAttachment> attachments = Collections.synchronizedList(new LinkedList<>());
public LPPermissible(@NonNull Player parent, User user, LPBukkitPlugin plugin) {
@@ -84,7 +77,7 @@ public class LPPermissible extends PermissibleBase {
this.plugin = plugin;
this.subscriptions = new SubscriptionManager(this);
recalculatePermissions();
// recalculatePermissions();
}
public void updateSubscriptionsAsync() {
@@ -92,7 +85,12 @@ public class LPPermissible extends PermissibleBase {
}
public void updateSubscriptions() {
Set<String> ent = new HashSet<>(user.getUserData().getPermissionData(calculateContexts()).getImmutableBacking().keySet());
UserCache cache = user.getUserData();
if (cache == null) {
return;
}
Set<String> ent = new HashSet<>(cache.getPermissionData(calculateContexts()).getImmutableBacking().keySet());
if (parent.isOp()) {
ent.addAll(plugin.getDefaultsProvider().getOpDefaults().keySet());
@@ -120,11 +118,11 @@ public class LPPermissible extends PermissibleBase {
public Contexts calculateContexts() {
return new Contexts(
plugin.getContextManager().getApplicableContext(parent),
plugin.getConfiguration().isIncludingGlobalPerms(),
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
true,
plugin.getConfiguration().isApplyingGlobalGroups(),
plugin.getConfiguration().isApplyingGlobalWorldGroups(),
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
parent.isOp()
);
}
@@ -287,8 +285,8 @@ public class LPPermissible extends PermissibleBase {
Bukkit.getServer().getPluginManager().unsubscribeFromPermission(name, parent);
}
Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(false, parent);
Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(true, parent);
// Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(false, parent);
// Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(true, parent);
attachmentPermissions.clear();
}
@@ -27,10 +27,20 @@ import lombok.RequiredArgsConstructor;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import org.bukkit.permissions.Permission;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Handles permission subscriptions with Bukkits plugin manager, for a given LPPermissible.
*
* Bukkit for some reason sometimes uses subscription status to determine whether a permissible has a given node, instead
* of checking directly with {@link org.bukkit.permissions.Permissible#hasPermission(Permission)}.
*
* {@link org.bukkit.Bukkit#broadcast(String, String)} is a good example of this.
*/
@RequiredArgsConstructor
public class SubscriptionManager {
@@ -40,6 +50,8 @@ public class SubscriptionManager {
public synchronized void subscribe(Set<String> perms) {
Set<String> newPerms = ImmutableSet.copyOf(perms);
// we compare changes to avoid unnecessary time wasted on the main thread mutating this data.
// the changes can be calculated here async, and then only the needed changes can be applied.
Map.Entry<Set<String>, Set<String>> changes = compareSets(newPerms, currentSubscriptions);
Set<String> toAdd = changes.getKey();
@@ -28,7 +28,7 @@ import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.caching.MetaData;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.caching.MetaHolder;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.model.Group;
import me.lucko.luckperms.common.core.model.PermissionHolder;
@@ -48,20 +48,8 @@ import static me.lucko.luckperms.api.MetaUtils.escapeCharacters;
import static me.lucko.luckperms.api.MetaUtils.unescapeCharacters;
/**
* Provides the Vault Chat service through the use of normal permission nodes.
*
* Prefixes / Suffixes:
* Normal inheritance rules apply.
* Permission Nodes = prefix.priority.value OR suffix.priority.value
* If a user/group has / inherits multiple prefixes and suffixes, the one with the highest priority is the one that
* will apply.
*
* Meta:
* Normal inheritance rules DO NOT apply.
* Permission Nodes = meta.node.value
*
* Note that special characters used within LuckPerms are escaped:
* See {@link me.lucko.luckperms.api.MetaUtils#unescapeCharacters(String)}
* LuckPerms Vault Chat implementation
* All user lookups are cached.
*/
public class VaultChatHook extends Chat {
private final VaultPermissionHook perms;
@@ -94,22 +82,20 @@ public class VaultChatHook extends Chat {
toRemove.forEach(n -> {
try {
holder.unsetPermission(n);
} catch (ObjectLacksException ignored) {
}
} catch (ObjectLacksException ignored) {}
});
Node.Builder metaNode = NodeFactory.makeMetaNode(node, value).setValue(true);
if (!perms.getServer().equalsIgnoreCase("global")) {
metaNode.setServer(perms.getServer());
}
if (finalWorld != null && !finalWorld.equals("")) {
metaNode.setServer(perms.getServer()).setWorld(finalWorld);
if (finalWorld != null && !finalWorld.equals("") && !finalWorld.equals("global")) {
metaNode.setWorld(finalWorld);
}
try {
holder.setPermission(metaNode.build());
} catch (ObjectAlreadyHasException ignored) {
}
} catch (ObjectAlreadyHasException ignored) {}
perms.save(holder);
});
@@ -123,20 +109,34 @@ public class VaultChatHook extends Chat {
perms.log("Setting " + (prefix ? "prefix" : "suffix") + " for " + holder.getObjectName() + " on world " + world + ", server " + perms.getServer());
perms.getScheduler().execute(() -> {
Node.Builder node = new NodeBuilder((prefix ? "prefix" : "suffix") + ".1000." + escapeCharacters(value));
node.setValue(true);
if (!perms.getServer().equalsIgnoreCase("global")) {
node.setServer(perms.getServer());
}
if (finalWorld != null && !finalWorld.equals("")) {
node.setServer(perms.getServer()).setWorld(finalWorld);
// remove all prefixes/suffixes directly set on the user/group
List<Node> toRemove = holder.getNodes().stream()
.filter(n -> prefix ? n.isPrefix() : n.isSuffix())
.collect(Collectors.toList());
toRemove.forEach(n -> {
try {
holder.unsetPermission(n);
} catch (ObjectLacksException ignored) {}
});
// find the max inherited priority & add 10
MetaHolder metaHolder = holder.accumulateMeta(null, null, ExtractedContexts.generate(perms.createContextForWorld(finalWorld)));
int priority = (prefix ? metaHolder.getPrefixes() : metaHolder.getSuffixes()).keySet().stream()
.mapToInt(e -> e).max().orElse(0) + 10;
Node.Builder chatMetaNode = NodeFactory.makeChatMetaNode(prefix, priority, value);
if (!perms.getServer().equalsIgnoreCase("global")) {
chatMetaNode.setServer(perms.getServer());
}
if (finalWorld != null && !finalWorld.equals("") && !finalWorld.equals("global")) {
chatMetaNode.setWorld(finalWorld);
}
try {
holder.setPermission(node.build());
} catch (ObjectAlreadyHasException ignored) {
}
holder.setPermission(chatMetaNode.build());
} catch (ObjectAlreadyHasException ignored) {}
perms.save(holder);
});
@@ -153,7 +153,12 @@ public class VaultChatHook extends Chat {
return defaultValue;
}
return unescapeCharacters(user.getUserData().getMetaData(perms.createContextForWorld(world)).getMeta().getOrDefault(node, defaultValue));
String ret = user.getUserData().getMetaData(perms.createContextForWorld(world)).getMeta().get(node);
if (ret == null) {
return defaultValue;
} else {
return unescapeCharacters(ret);
}
}
private String getUserChatMeta(boolean prefix, User user, String world) {
@@ -180,21 +185,10 @@ public class VaultChatHook extends Chat {
perms.log("Getting meta: '" + node + "' for group " + group.getName() + " on world " + world + ", server " + perms.getServer());
for (Node n : group.getPermissions(true)) {
if (!n.getValue()) {
continue;
}
if (!n.isMeta()) {
continue;
}
if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) {
continue;
}
if (!n.shouldApplyOnWorld(world, perms.isIncludeGlobal(), false)) {
continue;
}
if (!n.getValue()) continue;
if (!n.isMeta()) continue;
if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) continue;
if (!n.shouldApplyOnWorld(world, perms.isIncludeGlobal(), false)) continue;
Map.Entry<String, String> meta = n.getMeta();
if (meta.getKey().equalsIgnoreCase(node)) {
@@ -222,21 +216,10 @@ public class VaultChatHook extends Chat {
ExtractedContexts ec = ExtractedContexts.generate(new Contexts(ContextSet.fromMap(context), perms.isIncludeGlobal(), true, true, true, true, false));
for (Node n : group.getAllNodes(null, ec)) {
if (!n.getValue()) {
continue;
}
if (prefix ? !n.isPrefix() : !n.isSuffix()) {
continue;
}
if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) {
continue;
}
if (!n.shouldApplyOnWorld(world, perms.isIncludeGlobal(), false)) {
continue;
}
if (!n.getValue()) continue;
if (prefix ? !n.isPrefix() : !n.isSuffix()) continue;
if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) continue;
if (!n.shouldApplyOnWorld(world, perms.isIncludeGlobal(), false)) continue;
Map.Entry<Integer, String> value = prefix ? n.getPrefix() : n.getSuffix();
if (value.getKey() > priority) {
@@ -248,46 +231,55 @@ public class VaultChatHook extends Chat {
return meta == null ? "" : unescapeCharacters(meta);
}
@Override
public String getPlayerPrefix(String world, @NonNull String player) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
return getUserChatMeta(true, user, world);
}
@Override
public void setPlayerPrefix(String world, @NonNull String player, @NonNull String prefix) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
setChatMeta(true, user, prefix, world);
}
@Override
public String getPlayerSuffix(String world, @NonNull String player) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
return getUserChatMeta(false, user, world);
}
@Override
public void setPlayerSuffix(String world, @NonNull String player, @NonNull String suffix) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
setChatMeta(false, user, suffix, world);
}
@Override
public String getGroupPrefix(String world, @NonNull String group) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
return getGroupChatMeta(true, g, world);
}
@Override
public void setGroupPrefix(String world, @NonNull String group, @NonNull String prefix) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
setChatMeta(true, g, prefix, world);
}
@Override
public String getGroupSuffix(String world, @NonNull String group) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
return getGroupChatMeta(false, g, world);
}
@Override
public void setGroupSuffix(String world, @NonNull String group, @NonNull String suffix) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
setChatMeta(false, g, suffix, world);
}
@Override
public int getPlayerInfoInteger(String world, @NonNull String player, @NonNull String node, int defaultValue) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
try {
@@ -297,11 +289,13 @@ public class VaultChatHook extends Chat {
}
}
@Override
public void setPlayerInfoInteger(String world, @NonNull String player, @NonNull String node, int value) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
setMeta(user, world, node, String.valueOf(value));
}
@Override
public int getGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int defaultValue) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
try {
@@ -311,11 +305,13 @@ public class VaultChatHook extends Chat {
}
}
@Override
public void setGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int value) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
setMeta(g, world, node, String.valueOf(value));
}
@Override
public double getPlayerInfoDouble(String world, @NonNull String player, @NonNull String node, double defaultValue) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
try {
@@ -325,11 +321,13 @@ public class VaultChatHook extends Chat {
}
}
@Override
public void setPlayerInfoDouble(String world, @NonNull String player, @NonNull String node, double value) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
setMeta(user, world, node, String.valueOf(value));
}
@Override
public double getGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double defaultValue) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
try {
@@ -339,11 +337,13 @@ public class VaultChatHook extends Chat {
}
}
@Override
public void setGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double value) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
setMeta(g, world, node, String.valueOf(value));
}
@Override
public boolean getPlayerInfoBoolean(String world, @NonNull String player, @NonNull String node, boolean defaultValue) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
String s = getUserMeta(user, world, node, String.valueOf(defaultValue));
@@ -353,11 +353,13 @@ public class VaultChatHook extends Chat {
return Boolean.parseBoolean(s);
}
@Override
public void setPlayerInfoBoolean(String world, @NonNull String player, @NonNull String node, boolean value) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
setMeta(user, world, node, String.valueOf(value));
}
@Override
public boolean getGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean defaultValue) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
String s = getGroupMeta(g, world, node, String.valueOf(defaultValue));
@@ -367,26 +369,31 @@ public class VaultChatHook extends Chat {
return Boolean.parseBoolean(s);
}
@Override
public void setGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean value) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
setMeta(g, world, node, String.valueOf(value));
}
@Override
public String getPlayerInfoString(String world, @NonNull String player, @NonNull String node, String defaultValue) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
return getUserMeta(user, world, node, defaultValue);
}
@Override
public void setPlayerInfoString(String world, @NonNull String player, @NonNull String node, String value) {
final User user = perms.getPlugin().getUserManager().getByUsername(player);
setMeta(user, world, node, value);
}
@Override
public String getGroupInfoString(String world, @NonNull String group, @NonNull String node, String defaultValue) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
return getGroupMeta(g, world, node, defaultValue);
}
@Override
public void setGroupInfoString(String world, @NonNull String group, @NonNull String node, String value) {
final Group g = perms.getPlugin().getGroupManager().getIfLoaded(group);
setMeta(g, world, node, value);
@@ -32,6 +32,7 @@ import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.caching.PermissionData;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.core.model.Group;
import me.lucko.luckperms.common.core.model.PermissionHolder;
import me.lucko.luckperms.common.core.model.User;
@@ -46,7 +47,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
/**
* The LuckPerms Vault Permission implementation
* LuckPerms Vault Permission implementation
* Most lookups are cached.
*/
@Getter
@@ -56,34 +57,16 @@ public class VaultPermissionHook extends Permission {
private final String name = "LuckPerms";
private String server = "global";
private boolean includeGlobal = true;
private boolean ignoreWorld = false;
private boolean pgo = false;
private boolean pgoCheckInherited = false;
private boolean pgoCheckExists = true;
private boolean pgoCheckMemberOf = true;
private Function<String, String> WORLD_CORRECTION_FUNCTION = s -> ignoreWorld ? null : s;
private Function<String, String> worldCorrectionFunction = s -> isIgnoreWorld() ? null : s;
public VaultPermissionHook(LPBukkitPlugin plugin) {
this.plugin = plugin;
this.scheduler = new VaultScheduler(plugin);
super.plugin = plugin;
// Config options
this.server = plugin.getConfiguration().getVaultServer();
this.includeGlobal = plugin.getConfiguration().isVaultIncludingGlobal();
this.ignoreWorld = plugin.getConfiguration().isVaultIgnoreWorld();
this.pgo = plugin.getConfiguration().isVaultPrimaryGroupOverrides();
this.pgoCheckInherited = plugin.getConfiguration().isVaultPrimaryGroupOverridesCheckInherited();
this.pgoCheckExists = plugin.getConfiguration().isVaultPrimaryGroupOverridesCheckExists();
this.pgoCheckMemberOf = plugin.getConfiguration().isVaultPrimaryGroupOverridesCheckMemberOf();
}
public void log(String s) {
if (plugin.getConfiguration().isVaultDebug()) {
if (plugin.getConfiguration().get(ConfigKeys.VAULT_DEBUG)) {
plugin.getLog().info("[VAULT] " + s);
}
}
@@ -109,9 +92,9 @@ public class VaultPermissionHook extends Permission {
return CompletableFuture.runAsync(() -> {
try {
if (world != null && !world.equals("") && !world.equalsIgnoreCase("global")) {
holder.setPermission(permission, true, server, world);
holder.setPermission(permission, true, getServer(), world);
} else {
holder.setPermission(permission, true, server);
holder.setPermission(permission, true, getServer());
}
save(holder);
@@ -130,9 +113,9 @@ public class VaultPermissionHook extends Permission {
return CompletableFuture.runAsync(() -> {
try {
if (world != null && !world.equals("") && !world.equalsIgnoreCase("global")) {
holder.unsetPermission(permission, server, world);
holder.unsetPermission(permission, getServer(), world);
} else {
holder.unsetPermission(permission, server);
holder.unsetPermission(permission, getServer());
}
save(holder);
@@ -148,27 +131,27 @@ public class VaultPermissionHook extends Permission {
public void save(PermissionHolder holder) {
if (holder instanceof User) {
User u = (User) holder;
plugin.getStorage().saveUser(u).thenRunAsync(() -> u.getRefreshBuffer().request(), plugin.getAsyncExecutor());
plugin.getStorage().saveUser(u).thenRunAsync(() -> u.getRefreshBuffer().request(), plugin.getScheduler().getAsyncExecutor());
}
if (holder instanceof Group) {
Group g = (Group) holder;
plugin.getStorage().saveGroup(g).thenRunAsync(() -> plugin.getUpdateTaskBuffer().request(), plugin.getAsyncExecutor());
plugin.getStorage().saveGroup(g).thenRunAsync(() -> plugin.getUpdateTaskBuffer().request(), plugin.getScheduler().getAsyncExecutor());
}
}
public Contexts createContextForWorld(String world) {
Map<String, String> context = new HashMap<>();
if (world != null && !world.equals("")) {
if (world != null && !world.equals("") && !world.equalsIgnoreCase("global")) {
context.put("world", world);
}
context.put("server", server);
context.put("server", getServer());
return new Contexts(ContextSet.fromMap(context), isIncludeGlobal(), true, true, true, true, false);
}
@Override
public boolean playerHas(String world, @NonNull String player, @NonNull String permission) {
world = WORLD_CORRECTION_FUNCTION.apply(world);
log("Checking if player " + player + " has permission: " + permission + " on world " + world + ", server " + server);
world = worldCorrectionFunction.apply(world);
log("Checking if player " + player + " has permission: " + permission + " on world " + world + ", server " + getServer());
User user = plugin.getUserManager().getByUsername(player);
if (user == null) return false;
@@ -183,8 +166,8 @@ public class VaultPermissionHook extends Permission {
@Override
public boolean playerAdd(String world, @NonNull String player, @NonNull String permission) {
world = WORLD_CORRECTION_FUNCTION.apply(world);
log("Adding permission to player " + player + ": '" + permission + "' on world " + world + ", server " + server);
world = worldCorrectionFunction.apply(world);
log("Adding permission to player " + player + ": '" + permission + "' on world " + world + ", server " + getServer());
final User user = plugin.getUserManager().getByUsername(player);
if (user == null) return false;
@@ -195,8 +178,8 @@ public class VaultPermissionHook extends Permission {
@Override
public boolean playerRemove(String world, @NonNull String player, @NonNull String permission) {
world = WORLD_CORRECTION_FUNCTION.apply(world);
log("Removing permission from player " + player + ": '" + permission + "' on world " + world + ", server " + server);
world = worldCorrectionFunction.apply(world);
log("Removing permission from player " + player + ": '" + permission + "' on world " + world + ", server " + getServer());
final User user = plugin.getUserManager().getByUsername(player);
if (user == null) return false;
@@ -207,8 +190,8 @@ public class VaultPermissionHook extends Permission {
@Override
public boolean groupHas(String world, @NonNull String groupName, @NonNull String permission) {
world = WORLD_CORRECTION_FUNCTION.apply(world);
log("Checking if group " + groupName + " has permission: " + permission + " on world " + world + ", server " + server);
world = worldCorrectionFunction.apply(world);
log("Checking if group " + groupName + " has permission: " + permission + " on world " + world + ", server " + getServer());
final Group group = plugin.getGroupManager().getIfLoaded(groupName);
if (group == null) return false;
@@ -220,8 +203,8 @@ public class VaultPermissionHook extends Permission {
@Override
public boolean groupAdd(String world, @NonNull String groupName, @NonNull String permission) {
world = WORLD_CORRECTION_FUNCTION.apply(world);
log("Adding permission to group " + groupName + ": '" + permission + "' on world " + world + ", server " + server);
world = worldCorrectionFunction.apply(world);
log("Adding permission to group " + groupName + ": '" + permission + "' on world " + world + ", server " + getServer());
final Group group = plugin.getGroupManager().getIfLoaded(groupName);
if (group == null) return false;
@@ -232,8 +215,8 @@ public class VaultPermissionHook extends Permission {
@Override
public boolean groupRemove(String world, @NonNull String groupName, @NonNull String permission) {
world = WORLD_CORRECTION_FUNCTION.apply(world);
log("Removing permission from group " + groupName + ": '" + permission + "' on world " + world + ", server " + server);
world = worldCorrectionFunction.apply(world);
log("Removing permission from group " + groupName + ": '" + permission + "' on world " + world + ", server " + getServer());
final Group group = plugin.getGroupManager().getIfLoaded(groupName);
if (group == null) return false;
@@ -244,8 +227,8 @@ public class VaultPermissionHook extends Permission {
@Override
public boolean playerInGroup(String world, @NonNull String player, @NonNull String group) {
world = WORLD_CORRECTION_FUNCTION.apply(world);
log("Checking if player " + player + " is in group: " + group + " on world " + world + ", server " + server);
world = worldCorrectionFunction.apply(world);
log("Checking if player " + player + " is in group: " + group + " on world " + world + ", server " + getServer());
final User user = plugin.getUserManager().getByUsername(player);
if (user == null) return false;
@@ -253,7 +236,7 @@ public class VaultPermissionHook extends Permission {
String w = world; // screw effectively final
return user.getNodes().stream()
.filter(Node::isGroupNode)
.filter(n -> n.shouldApplyOnServer(server, isIncludeGlobal(), false))
.filter(n -> n.shouldApplyOnServer(getServer(), isIncludeGlobal(), false))
.filter(n -> n.shouldApplyOnWorld(w, true, false))
.map(Node::getGroupName)
.anyMatch(s -> s.equalsIgnoreCase(group));
@@ -261,8 +244,8 @@ public class VaultPermissionHook extends Permission {
@Override
public boolean playerAddGroup(String world, @NonNull String player, @NonNull String groupName) {
world = WORLD_CORRECTION_FUNCTION.apply(world);
log("Adding player " + player + " to group: '" + groupName + "' on world " + world + ", server " + server);
world = worldCorrectionFunction.apply(world);
log("Adding player " + player + " to group: '" + groupName + "' on world " + world + ", server " + getServer());
final User user = plugin.getUserManager().getByUsername(player);
if (user == null) return false;
@@ -274,9 +257,9 @@ public class VaultPermissionHook extends Permission {
scheduler.execute(() -> {
try {
if (w != null && !w.equals("") && !w.equalsIgnoreCase("global")) {
user.setInheritGroup(group, server, w);
user.setInheritGroup(group, getServer(), w);
} else {
user.setInheritGroup(group, server);
user.setInheritGroup(group, getServer());
}
save(user);
@@ -287,8 +270,8 @@ public class VaultPermissionHook extends Permission {
@Override
public boolean playerRemoveGroup(String world, @NonNull String player, @NonNull String groupName) {
world = WORLD_CORRECTION_FUNCTION.apply(world);
log("Removing player " + player + " from group: '" + groupName + "' on world " + world + ", server " + server);
world = worldCorrectionFunction.apply(world);
log("Removing player " + player + " from group: '" + groupName + "' on world " + world + ", server " + getServer());
final User user = plugin.getUserManager().getByUsername(player);
if (user == null) return false;
@@ -300,9 +283,9 @@ public class VaultPermissionHook extends Permission {
scheduler.execute(() -> {
try {
if (w != null && !w.equals("") && !w.equalsIgnoreCase("global")) {
user.unsetInheritGroup(group, server, w);
user.unsetInheritGroup(group, getServer(), w);
} else {
user.unsetInheritGroup(group, server);
user.unsetInheritGroup(group, getServer());
}
save(user);
@@ -313,8 +296,8 @@ public class VaultPermissionHook extends Permission {
@Override
public String[] getPlayerGroups(String world, @NonNull String player) {
world = WORLD_CORRECTION_FUNCTION.apply(world);
log("Getting groups of player: " + player + ", on world " + world + ", server " + server);
world = worldCorrectionFunction.apply(world);
log("Getting groups of player: " + player + ", on world " + world + ", server " + getServer());
User user = plugin.getUserManager().getByUsername(player);
if (user == null) return new String[0];
@@ -322,7 +305,7 @@ public class VaultPermissionHook extends Permission {
String w = world; // screw effectively final
return user.getNodes().stream()
.filter(Node::isGroupNode)
.filter(n -> n.shouldApplyOnServer(server, isIncludeGlobal(), false))
.filter(n -> n.shouldApplyOnServer(getServer(), isIncludeGlobal(), false))
.filter(n -> n.shouldApplyOnWorld(w, true, false))
.map(Node::getGroupName)
.toArray(String[]::new);
@@ -330,7 +313,7 @@ public class VaultPermissionHook extends Permission {
@Override
public String getPrimaryGroup(String world, @NonNull String player) {
world = WORLD_CORRECTION_FUNCTION.apply(world);
world = worldCorrectionFunction.apply(world);
log("Getting primary group of player: " + player);
final User user = plugin.getUserManager().getByUsername(player);
@@ -338,30 +321,28 @@ public class VaultPermissionHook extends Permission {
return null;
}
if (!pgo) {
// nothing special, just return the value.
if (!isPgo()) {
String g = user.getPrimaryGroup();
return plugin.getConfiguration().getGroupNameRewrites().getOrDefault(g, g);
return plugin.getConfiguration().get(ConfigKeys.GROUP_NAME_REWRITES).getOrDefault(g, g);
}
if (pgoCheckInherited) {
// we need to do the complex PGO checking. (it's been enabled in the config.)
if (isPgoCheckInherited()) {
// we can just check the cached data
PermissionData data = user.getUserData().getPermissionData(createContextForWorld(world));
for (Map.Entry<String, Boolean> e : data.getImmutableBacking().entrySet()) {
if (!e.getValue()) {
continue;
}
if (!e.getKey().toLowerCase().startsWith("vault.primarygroup.")) {
continue;
}
if (!e.getValue()) continue;
if (!e.getKey().toLowerCase().startsWith("vault.primarygroup.")) continue;
String group = e.getKey().substring("vault.primarygroup.".length());
if (pgoCheckExists) {
if (isPgoCheckExists()) {
if (!plugin.getGroupManager().isLoaded(group)) {
continue;
}
}
if (pgoCheckMemberOf) {
if (isPgoCheckMemberOf()) {
if (data.getPermissionValue("group." + group) != Tristate.TRUE) {
continue;
}
@@ -370,32 +351,22 @@ public class VaultPermissionHook extends Permission {
return group;
}
} else {
// we need to check the users permissions only
for (LocalizedNode node : user.getPermissions(true)) {
if (!node.getValue()) {
continue;
}
if (!node.getPermission().toLowerCase().startsWith("vault.primarygroup.")) {
continue;
}
if (!node.shouldApplyOnServer(server, isIncludeGlobal(), false)) {
continue;
}
if (!node.shouldApplyOnWorld(world, true, false)) {
continue;
}
if (!node.getValue()) continue;
if (!node.getPermission().toLowerCase().startsWith("vault.primarygroup.")) continue;
if (!node.shouldApplyOnServer(getServer(), isIncludeGlobal(), false)) continue;
if (!node.shouldApplyOnWorld(world, true, false)) continue;
String group = node.getPermission().substring("vault.primarygroup.".length());
if (pgoCheckExists) {
if (isPgoCheckExists()) {
if (!plugin.getGroupManager().isLoaded(group)) {
continue;
}
}
if (pgoCheckMemberOf) {
if (!user.getLocalGroups(server, world, isIncludeGlobal()).contains(group.toLowerCase())) {
if (isPgoCheckMemberOf()) {
if (!user.getLocalGroups(getServer(), world, isIncludeGlobal()).contains(group.toLowerCase())) {
continue;
}
}
@@ -406,7 +377,7 @@ public class VaultPermissionHook extends Permission {
// Fallback
String g = user.getPrimaryGroup();
return plugin.getConfiguration().getGroupNameRewrites().getOrDefault(g, g);
return plugin.getConfiguration().get(ConfigKeys.GROUP_NAME_REWRITES).getOrDefault(g, g);
}
@Override
@@ -418,4 +389,32 @@ public class VaultPermissionHook extends Permission {
public boolean hasGroupSupport() {
return true;
}
String getServer() {
return plugin.getConfiguration().get(ConfigKeys.VAULT_SERVER);
}
boolean isIncludeGlobal() {
return plugin.getConfiguration().get(ConfigKeys.VAULT_INCLUDING_GLOBAL);
}
boolean isIgnoreWorld() {
return plugin.getConfiguration().get(ConfigKeys.VAULT_IGNORE_WORLD);
}
private boolean isPgo() {
return plugin.getConfiguration().get(ConfigKeys.VAULT_PRIMARY_GROUP_OVERRIDES);
}
private boolean isPgoCheckInherited() {
return plugin.getConfiguration().get(ConfigKeys.VAULT_PRIMARY_GROUP_OVERRIDES_CHECK_INHERITED);
}
private boolean isPgoCheckExists() {
return plugin.getConfiguration().get(ConfigKeys.VAULT_PRIMARY_GROUP_OVERRIDES_CHECK_EXISTS);
}
private boolean isPgoCheckMemberOf() {
return plugin.getConfiguration().get(ConfigKeys.VAULT_PRIMARY_GROUP_OVERRIDES_CHECK_MEMBER_OF);
}
}
+52 -4
View File
@@ -46,6 +46,14 @@ online-mode: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# 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
temporary-add-behaviour: deny
@@ -75,6 +83,38 @@ group-weight:
# +------------------------------------------------------------------------+ #
# | Meta Formatting & Stacking | #
# +------------------------------------------------------------------------+ #
# Allows you to setup prefix/suffix stacking options.
#
# Available formats:
# - highest
# - lowest
# - highest_own
# - lowest_own
# - highest_on_track_<track>
# - lowest_on_track_<track>
#
# Each element is added in the order listed.
meta-formatting:
prefix:
format:
- "highest"
start-spacer: ""
middle-spacer: " "
end-spacer: ""
suffix:
format:
- "highest"
start-spacer: ""
middle-spacer: " "
end-spacer: ""
# +------------------------------------------------------------------------+ #
# | OP (Server Operator) Settings | #
# +------------------------------------------------------------------------+ #
@@ -181,15 +221,23 @@ data:
# e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources.
sync-minutes: 3
# Settings for Redis.
# Settings for the messaging service
#
# If enabled and configured, LuckPerms will use the Redis PubSub system to inform other
# 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 on redis. It is only used as a messaging platform.
# 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
# Settings for Redis.
# Port 6379 is used by default; set address to "host:port" if differs
redis:
enabled: false
@@ -229,7 +277,7 @@ redis:
#
# Within conditions, permission nodes MUST be escaped using "<" and ">". See the example below.
#
# Explaination of the examples below: (they're just to demonstrate the features & use cases)
# Explanation of the examples below: (they're just to demonstrate the features & use cases)
#
# rule1:
# If a user is either in the vip or vip+ group, and they have the "titles.titlecollector" permission set to true, and the
+2 -1
View File
@@ -1,5 +1,5 @@
name: LuckPerms
version: ${release.version}.${git.closest.tag.commit.count}
version: ${release.version}.${patch.version}
description: A permissions plugin
author: Luck
website: https://github.com/lucko/LuckPerms
@@ -11,6 +11,7 @@ load: STARTUP
# It in turn fixes issues where plugins using Vault cache the provided instance when their plugin enables, or
# when they check for the presence of a service provider, before LuckPerms has enabled.
loadbefore: [Vault]
softdepend: [LilyPad-Connect]
commands:
luckperms:
+10 -17
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.17-SNAPSHOT</version>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,13 +14,20 @@
<build>
<defaultGoal>clean package</defaultGoal>
<finalName>LuckPerms-Bungee-${release.version}.${git.closest.tag.commit.count}</finalName>
<finalName>LuckPerms-Bungee-${release.version}.${patch.version}</finalName>
<sourceDirectory>${basedir}/src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>../</directory>
<filtering>false</filtering>
<includes>
<include>LICENSE.txt</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
@@ -44,6 +51,7 @@
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>io.github.mkremins.fanciful</pattern>
@@ -54,21 +62,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<injectAllReactorProjects>true</injectAllReactorProjects>
</configuration>
</plugin>
</plugins>
</build>
@@ -28,13 +28,10 @@ import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.MutableContextSet;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerSwitchEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import java.util.Map;
public class BackendServerCalculator extends ContextCalculator<ProxiedPlayer> implements Listener {
public class BackendServerCalculator implements ContextCalculator<ProxiedPlayer> {
private static final String WORLD_KEY = "world";
private static String getServer(ProxiedPlayer player) {
@@ -61,9 +58,4 @@ public class BackendServerCalculator extends ContextCalculator<ProxiedPlayer> im
String server = getServer(subject);
return server != null && server.equals(context.getValue());
}
@EventHandler
public void onPlayerServerSwitch(ServerSwitchEvent e) {
pushUpdate(e.getPlayer(), Maps.immutableEntry("null", "null"), Maps.immutableEntry(WORLD_KEY, getServer(e.getPlayer())));
}
}
@@ -33,6 +33,7 @@ import me.lucko.luckperms.common.calculators.PermissionProcessor;
import me.lucko.luckperms.common.calculators.processors.MapProcessor;
import me.lucko.luckperms.common.calculators.processors.RegexProcessor;
import me.lucko.luckperms.common.calculators.processors.WildcardProcessor;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.core.model.User;
@AllArgsConstructor
@@ -43,12 +44,12 @@ public class BungeeCalculatorFactory extends AbstractCalculatorFactory {
public PermissionCalculator build(Contexts contexts, User user) {
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
processors.add(new MapProcessor());
if (plugin.getConfiguration().isApplyingWildcards()) {
processors.add(new WildcardProcessor());
}
if (plugin.getConfiguration().isApplyingRegex()) {
if (plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) {
processors.add(new RegexProcessor());
}
if (plugin.getConfiguration().get(ConfigKeys.APPLYING_WILDCARDS)) {
processors.add(new WildcardProcessor());
}
return registerCalculator(new PermissionCalculator(plugin, user.getName(), processors.build()));
}
@@ -40,7 +40,7 @@ class BungeeCommand extends Command implements TabExecutor {
private final CommandManager manager;
BungeeCommand(LPBungeePlugin plugin, CommandManager manager) {
super("luckpermsbungee", null, "bperms", "lpb", "bpermissions", "bp", "bperm");
super("luckpermsbungee", null, "bperms", "lpb", "bpermissions", "bperm");
this.plugin = plugin;
this.manager = manager;
}
@@ -49,7 +49,7 @@ class BungeeCommand extends Command implements TabExecutor {
public void execute(CommandSender sender, String[] args) {
manager.onCommand(
plugin.getSenderFactory().wrap(sender),
"bperms",
"lpb",
Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(Joiner.on(' ').join(args)))
);
}
@@ -22,6 +22,9 @@
package me.lucko.luckperms.bungee;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.common.config.AbstractConfiguration;
import net.md_5.bungee.config.Configuration;
@@ -38,20 +41,21 @@ import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
class BungeeConfig extends AbstractConfiguration<LPBungeePlugin> {
private Configuration configuration;
@RequiredArgsConstructor
public class BungeeConfig extends AbstractConfiguration {
BungeeConfig(LPBungeePlugin plugin) {
super(plugin, "bungee", false, "flatfile");
}
@Getter
private final LPBungeePlugin plugin;
private Configuration configuration;
@SuppressWarnings("ResultOfMethodCallIgnored")
private File makeFile(String file) throws IOException {
File cfg = new File(getPlugin().getDataFolder(), file);
File cfg = new File(plugin.getDataFolder(), file);
if (!cfg.exists()) {
getPlugin().getDataFolder().mkdir();
try (InputStream is = getPlugin().getResourceAsStream(file)) {
plugin.getDataFolder().mkdir();
try (InputStream is = plugin.getResourceAsStream(file)) {
Files.copy(is, cfg.toPath());
}
}
@@ -60,7 +64,7 @@ class BungeeConfig extends AbstractConfiguration<LPBungeePlugin> {
}
@Override
protected void init() {
public void init() {
try {
configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(makeFile("config.yml"));
} catch (IOException e) {
@@ -69,27 +73,27 @@ class BungeeConfig extends AbstractConfiguration<LPBungeePlugin> {
}
@Override
protected String getString(String path, String def) {
public String getString(String path, String def) {
return configuration.getString(path, def);
}
@Override
protected int getInt(String path, int def) {
public int getInt(String path, int def) {
return configuration.getInt(path, def);
}
@Override
protected boolean getBoolean(String path, boolean def) {
public boolean getBoolean(String path, boolean def) {
return configuration.getBoolean(path, def);
}
@Override
protected List<String> getList(String path, List<String> def) {
public List<String> getList(String path, List<String> def) {
return Optional.ofNullable(configuration.getStringList(path)).orElse(def);
}
@Override
protected List<String> getObjectList(String path, List<String> def) {
public List<String> getObjectList(String path, List<String> def) {
Configuration section = configuration.getSection(path);
if (section == null) {
return def;
@@ -99,7 +103,7 @@ class BungeeConfig extends AbstractConfiguration<LPBungeePlugin> {
}
@Override
protected Map<String, String> getMap(String path, Map<String, String> def) {
public Map<String, String> getMap(String path, Map<String, String> def) {
Map<String, String> map = new HashMap<>();
Configuration section = configuration.getSection(path);
if (section == null) {
@@ -23,7 +23,7 @@
package me.lucko.luckperms.bungee;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.event.events.UserFirstLoginEvent;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.core.UuidCache;
import me.lucko.luckperms.common.core.model.User;
@@ -75,11 +75,11 @@ public class BungeeListener extends AbstractListener implements Listener {
Contexts contexts = new Contexts(
plugin.getContextManager().getApplicableContext(player),
plugin.getConfiguration().isIncludingGlobalPerms(),
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
plugin.getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
true,
plugin.getConfiguration().isApplyingGlobalGroups(),
plugin.getConfiguration().isApplyingGlobalWorldGroups(),
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
plugin.getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
false
);
@@ -97,20 +97,20 @@ public class BungeeListener extends AbstractListener implements Listener {
final UuidCache cache = plugin.getUuidCache();
final PendingConnection c = e.getConnection();
if (!cache.isOnlineMode()) {
if (!plugin.getConfiguration().get(ConfigKeys.ONLINE_MODE)) {
UUID uuid = plugin.getStorage().getUUID(c.getName()).join();
if (uuid != null) {
cache.addToCache(c.getUniqueId(), uuid);
} else {
// No previous data for this player
plugin.getApiProvider().fireEventAsync(new UserFirstLoginEvent(c.getUniqueId(), c.getName()));
plugin.getApiProvider().getEventFactory().handleUserFirstLogin(c.getUniqueId(), c.getName());
cache.addToCache(c.getUniqueId(), c.getUniqueId());
plugin.getStorage().force().saveUUIDData(c.getName(), c.getUniqueId()).join();
}
} else {
String name = plugin.getStorage().getName(c.getUniqueId()).join();
if (name == null) {
plugin.getApiProvider().fireEventAsync(new UserFirstLoginEvent(c.getUniqueId(), c.getName()));
plugin.getApiProvider().getEventFactory().handleUserFirstLogin(c.getUniqueId(), c.getName());
}
// Online mode, no cache needed. This is just for name -> uuid lookup.
@@ -126,7 +126,7 @@ public class BungeeListener extends AbstractListener implements Listener {
} else {
// Setup defaults for the user
boolean save = false;
for (Rule rule : plugin.getConfiguration().getDefaultAssignments()) {
for (Rule rule : plugin.getConfiguration().get(ConfigKeys.DEFAULT_ASSIGNMENTS)) {
if (rule.apply(user)) {
save = true;
}
@@ -22,9 +22,9 @@
package me.lucko.luckperms.bungee;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.sender.SenderFactory;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent;
@@ -29,38 +29,44 @@ import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.bungee.messaging.BungeeMessagingService;
import me.lucko.luckperms.common.api.ApiHandler;
import me.lucko.luckperms.common.api.ApiProvider;
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.LPConfiguration;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
import me.lucko.luckperms.common.contexts.ContextManager;
import me.lucko.luckperms.common.contexts.ServerCalculator;
import me.lucko.luckperms.common.core.UuidCache;
import me.lucko.luckperms.common.core.model.User;
import me.lucko.luckperms.common.data.Importer;
import me.lucko.luckperms.common.debug.DebugHandler;
import me.lucko.luckperms.common.dependencies.DependencyManager;
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.managers.GroupManager;
import me.lucko.luckperms.common.managers.TrackManager;
import me.lucko.luckperms.common.managers.UserManager;
import me.lucko.luckperms.common.managers.impl.GenericGroupManager;
import me.lucko.luckperms.common.managers.impl.GenericTrackManager;
import me.lucko.luckperms.common.managers.impl.GenericUserManager;
import me.lucko.luckperms.common.messaging.InternalMessagingService;
import me.lucko.luckperms.common.messaging.RedisMessaging;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.plugin.LuckPermsScheduler;
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.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.utils.BufferedRequest;
import me.lucko.luckperms.common.utils.DebugHandler;
import me.lucko.luckperms.common.utils.LocaleManager;
import me.lucko.luckperms.common.utils.LogFactory;
import me.lucko.luckperms.common.utils.PermissionCache;
import me.lucko.luckperms.common.utils.LoggerImpl;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
@@ -73,20 +79,18 @@ import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Getter
public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private Executor executor;
private LPConfiguration configuration;
private LuckPermsScheduler scheduler;
private LuckPermsConfiguration configuration;
private UserManager userManager;
private GroupManager groupManager;
private TrackManager trackManager;
private Storage storage;
private RedisMessaging redisMessaging = null;
private InternalMessagingService messagingService = null;
private UuidCache uuidCache;
private ApiProvider apiProvider;
private Logger log;
@@ -98,18 +102,22 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
private BufferedRequest<Void> updateTaskBuffer;
private DebugHandler debugHandler;
private BungeeSenderFactory senderFactory;
private PermissionCache permissionCache;
private PermissionVault permissionVault;
@Override
public void onEnable() {
executor = r -> getProxy().getScheduler().runAsync(this, r);
log = LogFactory.wrap(getLogger());
debugHandler = new DebugHandler(executor, getVersion());
scheduler = new LPBungeeScheduler(this);
localeManager = new NoopLocaleManager();
senderFactory = new BungeeSenderFactory(this);
permissionCache = new PermissionCache(executor);
log = new LoggerImpl(getConsoleSender());
LuckPermsPlugin.sendStartupBanner(getConsoleSender(), this);
debugHandler = new DebugHandler(scheduler.getAsyncExecutor(), getVersion());
permissionVault = new PermissionVault(scheduler.getAsyncExecutor());
getLog().info("Loading configuration...");
configuration = new BungeeConfig(this);
configuration.init();
configuration.loadAll();
Set<StorageType> storageTypes = StorageFactory.getRequiredTypes(this, StorageType.H2);
DependencyManager.loadDependencies(this, storageTypes);
@@ -120,17 +128,34 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
// initialise datastore
storage = StorageFactory.getInstance(this, StorageType.H2);
// initialise redis
if (getConfiguration().isRedisEnabled()) {
// initialise messaging
String messagingType = getConfiguration().get(ConfigKeys.MESSAGING_SERVICE).toLowerCase();
if (messagingType.equals("none") && getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
messagingType = "redis";
}
if (messagingType.equals("redis")) {
getLog().info("Loading redis...");
redisMessaging = new RedisMessaging(this);
try {
redisMessaging.init(getConfiguration().getRedisAddress(), getConfiguration().getRedisPassword());
getLog().info("Loaded redis successfully...");
} catch (Exception e) {
getLog().info("Couldn't load redis...");
e.printStackTrace();
if (getConfiguration().get(ConfigKeys.REDIS_ENABLED)) {
RedisMessaging redis = new RedisMessaging(this);
try {
redis.init(getConfiguration().get(ConfigKeys.REDIS_ADDRESS), getConfiguration().get(ConfigKeys.REDIS_PASSWORD));
getLog().info("Loaded redis successfully...");
messagingService = redis;
} catch (Exception e) {
getLog().warn("Couldn't load redis...");
e.printStackTrace();
}
} else {
getLog().warn("Messaging Service was set to redis, but redis is not enabled!");
}
} else if (messagingType.equals("bungee")) {
getLog().info("Loading bungee messaging service...");
BungeeMessagingService bungeeMessaging = new BungeeMessagingService(this);
bungeeMessaging.init();
messagingService = bungeeMessaging;
} else if (!messagingType.equals("none")) {
getLog().warn("Messaging service '" + messagingType + "' not recognised.");
}
// setup the update task buffer
@@ -143,7 +168,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
};
// load locale
localeManager = new LocaleManager();
localeManager = new SimpleLocaleManager();
File locale = new File(getDataFolder(), "lang.yml");
if (locale.exists()) {
getLog().info("Found locale file. Attempting to load from it.");
@@ -164,19 +189,18 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
// load internal managers
getLog().info("Loading internal permission managers...");
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
uuidCache = new UuidCache(this);
userManager = new GenericUserManager(this);
groupManager = new GenericGroupManager(this);
trackManager = new GenericTrackManager();
trackManager = new GenericTrackManager(this);
importer = new Importer(commandManager);
calculatorFactory = new BungeeCalculatorFactory(this);
cachedStateManager = new CachedStateManager(this);
contextManager = new ContextManager<>();
BackendServerCalculator serverCalculator = new BackendServerCalculator();
getProxy().getPluginManager().registerListener(this, serverCalculator);
contextManager.registerCalculator(serverCalculator);
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
contextManager.registerCalculator(new ServerCalculator<>(configuration));
// register with the LP API
getLog().info("Registering API...");
@@ -184,17 +208,19 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
ApiHandler.registerProvider(apiProvider);
// schedule update tasks
int mins = getConfiguration().getSyncTime();
int mins = getConfiguration().get(ConfigKeys.SYNC_TIME);
if (mins > 0) {
getProxy().getScheduler().schedule(this, new UpdateTask(this), mins, mins, TimeUnit.MINUTES);
long ticks = mins * 60 * 20;
scheduler.doAsyncRepeating(() -> updateTaskBuffer.request(), ticks);
}
scheduler.doAsyncLater(() -> updateTaskBuffer.request(), 40L);
// run an update instantly.
updateTaskBuffer.requestDirectly();
// register tasks
getProxy().getScheduler().schedule(this, new ExpireTemporaryTask(this), 3L, 3L, TimeUnit.SECONDS);
getProxy().getScheduler().schedule(this, new CacheHousekeepingTask(this), 2L, 2L, TimeUnit.MINUTES);
scheduler.doAsyncRepeating(new ExpireTemporaryTask(this), 60L);
scheduler.doAsyncRepeating(new CacheHousekeepingTask(this), 2400L);
getLog().info("Successfully loaded.");
}
@@ -204,13 +230,16 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
getLog().info("Closing datastore...");
storage.shutdown();
if (redisMessaging != null) {
getLog().info("Closing redis...");
redisMessaging.shutdown();
if (messagingService != null) {
getLog().info("Closing messaging service...");
messagingService.close();
}
getLog().info("Unregistering API...");
ApiHandler.unregisterProvider();
getProxy().getScheduler().cancel(this);
getProxy().getPluginManager().unregisterListeners(this);
}
@Override
@@ -219,7 +248,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
}
@Override
public PlatformType getType() {
public PlatformType getServerType() {
return PlatformType.BUNGEE;
}
@@ -234,8 +263,8 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
}
@Override
public File getMainDir() {
return getDataFolder();
public File getDataDirectory() {
return super.getDataFolder();
}
@Override
@@ -256,11 +285,11 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
}
return new Contexts(
getContextManager().getApplicableContext(player),
getConfiguration().isIncludingGlobalPerms(),
getConfiguration().isIncludingGlobalWorldPerms(),
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
true,
getConfiguration().isApplyingGlobalGroups(),
getConfiguration().isApplyingGlobalWorldGroups(),
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
false
);
}
@@ -281,12 +310,12 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
}
@Override
public boolean isOnline(UUID external) {
public boolean isPlayerOnline(UUID external) {
return getProxy().getPlayer(external) != null;
}
@Override
public List<Sender> getSenders() {
public List<Sender> getOnlineSenders() {
return getProxy().getPlayers().stream()
.map(p -> getSenderFactory().wrap(p))
.collect(Collectors.toList());
@@ -301,12 +330,12 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
public Set<Contexts> getPreProcessContexts(boolean op) {
Set<ContextSet> c = new HashSet<>();
c.add(ContextSet.empty());
c.add(ContextSet.singleton("server", getConfiguration().getServer()));
c.add(ContextSet.singleton("server", getConfiguration().get(ConfigKeys.SERVER)));
c.addAll(getProxy().getServers().values().stream()
.map(ServerInfo::getName)
.map(s -> {
MutableContextSet set = MutableContextSet.create();
set.add("server", getConfiguration().getServer());
set.add("server", getConfiguration().get(ConfigKeys.SERVER));
set.add("world", s);
return set.makeImmutable();
})
@@ -316,62 +345,18 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
return c.stream()
.map(set -> new Contexts(
set,
getConfiguration().isIncludingGlobalPerms(),
getConfiguration().isIncludingGlobalWorldPerms(),
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_PERMS),
getConfiguration().get(ConfigKeys.INCLUDING_GLOBAL_WORLD_PERMS),
true,
getConfiguration().isApplyingGlobalGroups(),
getConfiguration().isApplyingGlobalWorldGroups(),
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_GROUPS),
getConfiguration().get(ConfigKeys.APPLYING_GLOBAL_WORLD_GROUPS),
false
))
.collect(Collectors.toSet());
}
@Override
public Object getPlugin(String name) {
return getProxy().getPluginManager().getPlugin(name);
}
@Override
public Object getService(Class clazz) {
return null;
}
@Override
public UUID getUUID(String playerName) {
public UUID getUuidFromUsername(String playerName) {
return null; // Not needed on Bungee
}
@Override
public boolean isPluginLoaded(String name) {
return getProxy().getPluginManager().getPlugins().stream()
.filter(p -> p.getDescription().getName().equalsIgnoreCase(name))
.findAny()
.isPresent();
}
@Override
public void doAsync(Runnable r) {
getProxy().getScheduler().runAsync(this, r);
}
@Override
public void doSync(Runnable r) {
doAsync(r);
}
@Override
public Executor getSyncExecutor() {
return executor;
}
@Override
public Executor getAsyncExecutor() {
return executor;
}
@Override
public void doAsyncRepeating(Runnable r, long interval) {
long millis = interval * 50L; // convert from ticks to milliseconds
getProxy().getScheduler().schedule(this, r, millis, millis, TimeUnit.MILLISECONDS);
}
}
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.plugin.LuckPermsScheduler;
import net.md_5.bungee.api.scheduler.ScheduledTask;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
public class LPBungeeScheduler implements LuckPermsScheduler {
private final LPBungeePlugin plugin;
private Executor asyncExecutor;
private Set<ScheduledTask> tasks = ConcurrentHashMap.newKeySet();
public LPBungeeScheduler(LPBungeePlugin plugin) {
this.plugin = plugin;
this.asyncExecutor = r -> plugin.getProxy().getScheduler().runAsync(plugin, r);
}
@Override
public Executor getAsyncExecutor() {
return asyncExecutor;
}
@Override
public Executor getSyncExecutor() {
return asyncExecutor;
}
@Override
public void doAsync(Runnable r) {
asyncExecutor.execute(r);
}
@Override
public void doSync(Runnable r) {
doAsync(r);
}
@Override
public void doAsyncRepeating(Runnable r, long interval) {
long millis = interval * 50L; // convert from ticks to milliseconds
ScheduledTask task = plugin.getProxy().getScheduler().schedule(plugin, r, millis, millis, TimeUnit.MILLISECONDS);
tasks.add(task);
}
@Override
public void doSyncRepeating(Runnable r, long interval) {
doAsyncRepeating(r, interval);
}
@Override
public void doAsyncLater(Runnable r, long delay) {
long millis = delay * 50L; // convert from ticks to milliseconds
plugin.getProxy().getScheduler().schedule(plugin, r, millis, TimeUnit.MILLISECONDS);
}
@Override
public void doSyncLater(Runnable r, long delay) {
doAsyncLater(r, delay);
}
@Override
public void shutdown() {
tasks.forEach(ScheduledTask::cancel);
}
}
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.messaging;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import me.lucko.luckperms.bungee.LPBungeePlugin;
import me.lucko.luckperms.common.messaging.AbstractMessagingService;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
/**
* An implementation of {@link me.lucko.luckperms.api.MessagingService} using the plugin messaging channels.
*/
public class BungeeMessagingService extends AbstractMessagingService implements Listener {
private final LPBungeePlugin plugin;
public BungeeMessagingService(LPBungeePlugin plugin) {
super(plugin, "Bungee");
this.plugin = plugin;
}
public void init() {
plugin.getProxy().getPluginManager().registerListener(plugin, this);
plugin.getProxy().registerChannel(CHANNEL);
}
@Override
public void close() {
plugin.getProxy().unregisterChannel(CHANNEL);
}
@Override
protected void sendMessage(String channel, String message) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF(message);
byte[] data = out.toByteArray();
for (ServerInfo server : plugin.getProxy().getServers().values()) {
server.sendData(channel, data, true);
}
}
@EventHandler
public void onPluginMessage(PluginMessageEvent e) {
if (!e.getTag().equals(CHANNEL)) {
return;
}
e.setCancelled(true);
if (e.getSender() instanceof ProxiedPlayer) {
return;
}
ByteArrayDataInput in = ByteStreams.newDataInput(e.getData());
String msg = in.readUTF();
onMessage(e.getTag(), msg, u -> {
// Forward to other servers
plugin.doAsync(() -> sendMessage(CHANNEL, "update:" + u.toString()));
});
}
}
@@ -22,18 +22,16 @@
package me.lucko.luckperms.bungee.migration;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.common.utils.ProgressLogger;
import net.alpenblock.bungeeperms.BungeePerms;
import net.alpenblock.bungeeperms.Group;
@@ -43,10 +41,8 @@ import net.alpenblock.bungeeperms.World;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* BungeePerms is actually pretty nice. huh.
*/
public class MigrationBungeePerms extends SubCommand<Object> {
public MigrationBungeePerms() {
super("bungeeperms", "Migration from BungeePerms", Permission.MIGRATION, Predicates.alwaysFalse(), null);
@@ -54,45 +50,34 @@ public class MigrationBungeePerms extends SubCommand<Object> {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) throws CommandException {
final Logger log = plugin.getLog();
ProgressLogger log = new ProgressLogger("BungeePerms");
log.addListener(plugin.getConsoleSender());
log.addListener(sender);
log.log("Starting.");
// Get BungeePerms instance
BungeePerms bp = BungeePerms.getInstance();
if (bp == null) {
log.severe("BungeePerms Migration: Error -> BungeePerms is not loaded.");
log.logErr("Plugin not loaded.");
return CommandResult.STATE_ERROR;
}
// Migrate all groups.
log.info("BungeePerms Migration: Starting group migration.");
int groupCount = 0;
log.log("Starting group migration.");
AtomicInteger groupCount = new AtomicInteger(0);
for (Group g : bp.getPermissionsManager().getBackEnd().loadGroups()) {
groupCount++;
// Make a LuckPerms group for the one being migrated
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase()).join();
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase(), CreationCause.INTERNAL).join();
me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(g.getName().toLowerCase());
try {
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("create")
.build().submit(plugin);
} catch (Exception ex) {
ex.printStackTrace();
}
// Migrate global perms
for (String perm : g.getPerms()) {
try {
group.setPermission(perm, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("set " + perm + " true")
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -101,14 +86,8 @@ public class MigrationBungeePerms extends SubCommand<Object> {
for (String perm : e.getValue().getPerms()) {
try {
group.setPermission(perm, true, e.getKey());
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("set " + perm + " true " + e.getKey())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -117,14 +96,8 @@ public class MigrationBungeePerms extends SubCommand<Object> {
for (String perm : we.getValue().getPerms()) {
try {
group.setPermission(perm, true, e.getKey(), we.getKey());
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("set " + perm + " true " + e.getKey() + " " + we.getKey())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
}
@@ -134,14 +107,8 @@ public class MigrationBungeePerms extends SubCommand<Object> {
for (String inherit : g.getInheritances()) {
try {
group.setPermission("group." + inherit, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("setinherit " + group)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -153,14 +120,8 @@ public class MigrationBungeePerms extends SubCommand<Object> {
prefix = MetaUtils.escapeCharacters(prefix);
try {
group.setPermission("prefix.50." + prefix, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("set prefix.50." + prefix + " true")
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -168,29 +129,25 @@ public class MigrationBungeePerms extends SubCommand<Object> {
suffix = MetaUtils.escapeCharacters(suffix);
try {
group.setPermission("suffix.50." + suffix, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(group).action("set suffix.50." + suffix + " true")
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
plugin.getStorage().saveGroup(group);
}
log.info("BungeePerms Migration: Migrated " + groupCount + " groups");
log.logAllProgress("Migrated {} groups so far.", groupCount.incrementAndGet());
}
log.log("Migrated " + groupCount.get() + " groups");
// Migrate all users.
log.info("BungeePerms Migration: Starting user migration.");
int userCount = 0;
log.log("Starting user migration.");
AtomicInteger userCount = new AtomicInteger(0);
for (User u : bp.getPermissionsManager().getBackEnd().loadUsers()) {
if (u.getUUID() == null) continue;
userCount++;
if (u.getUUID() == null) {
log.logErr("Could not parse UUID for user: " + u.getName());
continue;
}
// Make a LuckPerms user for the one being migrated.
plugin.getStorage().loadUser(u.getUUID(), "null").join();
@@ -200,14 +157,8 @@ public class MigrationBungeePerms extends SubCommand<Object> {
for (String perm : u.getPerms()) {
try {
user.setPermission(perm, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("set " + perm + " true")
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -216,14 +167,8 @@ public class MigrationBungeePerms extends SubCommand<Object> {
for (String perm : e.getValue().getPerms()) {
try {
user.setPermission(perm, true, e.getKey());
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("set " + perm + " true " + e.getKey())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -232,14 +177,8 @@ public class MigrationBungeePerms extends SubCommand<Object> {
for (String perm : we.getValue().getPerms()) {
try {
user.setPermission(perm, true, e.getKey(), we.getKey());
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("set " + perm + " true " + e.getKey() + " " + we.getKey())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
}
@@ -249,14 +188,8 @@ public class MigrationBungeePerms extends SubCommand<Object> {
for (String group : u.getGroupsString()) {
try {
user.setPermission("group." + group, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("addgroup " + group)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -268,14 +201,8 @@ public class MigrationBungeePerms extends SubCommand<Object> {
prefix = MetaUtils.escapeCharacters(prefix);
try {
user.setPermission("prefix.100." + prefix, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("set prefix.100." + prefix + " true")
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
@@ -283,23 +210,19 @@ public class MigrationBungeePerms extends SubCommand<Object> {
suffix = MetaUtils.escapeCharacters(suffix);
try {
user.setPermission("suffix.100." + suffix, true);
LogEntry.build()
.actor(Constants.CONSOLE_UUID).actorName(Constants.CONSOLE_NAME)
.acted(user).action("set suffix.100." + suffix + " true")
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
log.handleException(ex);
}
}
plugin.getStorage().saveUser(user);
plugin.getUserManager().cleanup(user);
log.logProgress("Migrated {} users so far.", userCount.incrementAndGet());
}
log.info("BungeePerms Migration: Migrated " + userCount + " users.");
log.info("BungeePerms Migration: Success! Completed without any errors.");
log.log("Migrated " + userCount.get() + " users.");
log.log("Success! Migration complete.");
return CommandResult.SUCCESS;
}
}
+51 -4
View File
@@ -56,6 +56,14 @@ world-rewrite:
group-name-rewrite:
# default: Member
# 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
temporary-add-behaviour: deny
@@ -85,6 +93,38 @@ group-weight:
# +------------------------------------------------------------------------+ #
# | Meta Formatting & Stacking | #
# +------------------------------------------------------------------------+ #
# Allows you to setup prefix/suffix stacking options.
#
# Available formats:
# - highest
# - lowest
# - highest_own
# - lowest_own
# - highest_on_track_<track>
# - lowest_on_track_<track>
#
# Each element is added in the order listed.
meta-formatting:
prefix:
format:
- "highest"
start-spacer: ""
middle-spacer: " "
end-spacer: ""
suffix:
format:
- "highest"
start-spacer: ""
middle-spacer: " "
end-spacer: ""
# +------------------------------------------------------------------------+ #
# | Storage | #
# +------------------------------------------------------------------------+ #
@@ -123,15 +163,22 @@ data:
# e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources.
sync-minutes: 3
# Settings for Redis.
# Settings for the messaging service
#
# If enabled and configured, LuckPerms will use the Redis PubSub system to inform other
# 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 on redis. It is only used as a messaging platform.
# 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.
# redis ==> uses redis pub sub to push changes. Your redis server must be configured below.
# none ==> nothing
messaging-service: none
# Settings for Redis.
# Port 6379 is used by default; set address to "host:port" if differs
redis:
enabled: false
@@ -171,7 +218,7 @@ redis:
#
# Within conditions, permission nodes MUST be escaped using "<" and ">". See the example below.
#
# Explaination of the examples below: (they're just to demonstrate the features & use cases)
# Explanation of the examples below: (they're just to demonstrate the features & use cases)
#
# rule1:
# If a user is either in the vip or vip+ group, and they have the "titles.titlecollector" permission set to true, and the
+1 -1
View File
@@ -1,5 +1,5 @@
name: LuckPerms
version: ${release.version}.${git.closest.tag.commit.count}
version: ${release.version}.${patch.version}
description: A permissions plugin
author: Luck
main: me.lucko.luckperms.bungee.LPBungeePlugin
+3 -3
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.17-SNAPSHOT</version>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -57,7 +57,7 @@
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
<version>2.9.1-shaded</version>
<scope>provided</scope>
</dependency>
<!-- SQLite -->
@@ -88,7 +88,7 @@
<version>3.3.0</version>
<scope>provided</scope>
</dependency>
<!-- slf4j library -->
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
@@ -22,13 +22,10 @@
package me.lucko.luckperms.common.api;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import com.google.common.eventbus.EventBus;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Datastore;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.LPConfiguration;
import me.lucko.luckperms.api.Logger;
@@ -41,50 +38,37 @@ import me.lucko.luckperms.api.Storage;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.UuidCache;
import me.lucko.luckperms.api.context.ContextListener;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.IContextCalculator;
import me.lucko.luckperms.api.event.LPEvent;
import me.lucko.luckperms.api.event.LPListener;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.api.delegate.DatastoreDelegate;
import me.lucko.luckperms.common.api.delegate.GroupDelegate;
import me.lucko.luckperms.common.api.delegate.LPConfigurationDelegate;
import me.lucko.luckperms.common.api.delegate.NodeFactoryDelegate;
import me.lucko.luckperms.common.api.delegate.StorageDelegate;
import me.lucko.luckperms.common.api.delegate.TrackDelegate;
import me.lucko.luckperms.common.api.delegate.UserDelegate;
import me.lucko.luckperms.common.api.delegate.UuidCacheDelegate;
import me.lucko.luckperms.common.api.delegates.NodeFactoryDelegate;
import me.lucko.luckperms.common.api.delegates.UserDelegate;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.UserIdentifier;
import me.lucko.luckperms.common.event.EventFactory;
import me.lucko.luckperms.common.event.LuckPermsEventBus;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import static me.lucko.luckperms.common.api.ApiUtils.checkNode;
/**
* Implements the LuckPerms API using the plugin instance
*/
@AllArgsConstructor
public class ApiProvider implements LuckPermsApi {
private final LuckPermsPlugin plugin;
private final EventBus eventBus = new EventBus("LuckPerms");
public void fireEventAsync(LPEvent event) {
plugin.doAsync(() -> fireEvent(event));
}
@Getter
private final LuckPermsEventBus eventBus;
public void fireEvent(LPEvent event) {
try {
event.setApi(this);
eventBus.post(event);
} catch (Exception e) {
getLogger().severe("Couldn't fire LuckPerms Event: " + event.getEventName());
e.printStackTrace();
}
@Getter
private final EventFactory eventFactory;
public ApiProvider(LuckPermsPlugin plugin) {
this.plugin = plugin;
this.eventBus = new LuckPermsEventBus(plugin);
this.eventFactory = new EventFactory(eventBus);
}
@Override
@@ -94,7 +78,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public double getApiVersion() {
return 2.17;
return 3.0;
}
@Override
@@ -104,43 +88,27 @@ public class ApiProvider implements LuckPermsApi {
@Override
public PlatformType getPlatformType() {
return plugin.getType();
}
@Override
public void registerListener(@NonNull LPListener listener) {
eventBus.register(listener);
}
@Override
public void unregisterListener(@NonNull LPListener listener) {
eventBus.unregister(listener);
return plugin.getServerType();
}
@Override
public LPConfiguration getConfiguration() {
return new LPConfigurationDelegate(plugin.getConfiguration());
return plugin.getConfiguration().getDelegate();
}
@Override
public Storage getStorage() {
return new StorageDelegate(plugin, plugin.getStorage());
}
@SuppressWarnings("deprecation")
@Override
public Datastore getDatastore() {
return new DatastoreDelegate(plugin, plugin.getStorage());
return plugin.getStorage().getDelegate();
}
@Override
public Optional<MessagingService> getMessagingService() {
return Optional.ofNullable(plugin.getRedisMessaging());
return Optional.ofNullable(plugin.getMessagingService());
}
@Override
public UuidCache getUuidCache() {
return new UuidCacheDelegate(plugin.getUuidCache());
return plugin.getUuidCache().getDelegate();
}
@Override
@@ -151,7 +119,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public User getUser(@NonNull UUID uuid) {
final me.lucko.luckperms.common.core.model.User user = plugin.getUserManager().get(uuid);
return user == null ? null : new UserDelegate(user);
return user == null ? null : user.getDelegate();
}
@Override
@@ -162,7 +130,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public User getUser(@NonNull String name) {
final me.lucko.luckperms.common.core.model.User user = plugin.getUserManager().getByUsername(name);
return user == null ? null : new UserDelegate(user);
return user == null ? null : user.getDelegate();
}
@Override
@@ -172,7 +140,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Set<User> getUsers() {
return plugin.getUserManager().getAll().values().stream().map(UserDelegate::new).collect(Collectors.toSet());
return plugin.getUserManager().getAll().values().stream().map(u -> u.getDelegate()).collect(Collectors.toSet());
}
@Override
@@ -189,7 +157,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Group getGroup(@NonNull String name) {
final me.lucko.luckperms.common.core.model.Group group = plugin.getGroupManager().getIfLoaded(name);
return group == null ? null : new GroupDelegate(group);
return group == null ? null : group.getDelegate();
}
@Override
@@ -199,7 +167,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Set<Group> getGroups() {
return plugin.getGroupManager().getAll().values().stream().map(GroupDelegate::new).collect(Collectors.toSet());
return plugin.getGroupManager().getAll().values().stream().map(g -> g.getDelegate()).collect(Collectors.toSet());
}
@Override
@@ -210,7 +178,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Track getTrack(@NonNull String name) {
final me.lucko.luckperms.common.core.model.Track track = plugin.getTrackManager().getIfLoaded(name);
return track == null ? null : new TrackDelegate(track);
return track == null ? null : track.getDelegate();
}
@Override
@@ -220,7 +188,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Set<Track> getTracks() {
return plugin.getTrackManager().getAll().values().stream().map(TrackDelegate::new).collect(Collectors.toSet());
return plugin.getTrackManager().getAll().values().stream().map(t -> t.getDelegate()).collect(Collectors.toSet());
}
@Override
@@ -235,21 +203,15 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Node.Builder buildNode(@NonNull String permission) throws IllegalArgumentException {
return new NodeBuilder(checkNode(permission));
return new NodeBuilder(permission);
}
@SuppressWarnings("unchecked")
@Override
public void registerContextCalculator(IContextCalculator<?> contextCalculator) {
public void registerContextCalculator(ContextCalculator<?> contextCalculator) {
plugin.getContextManager().registerCalculator(contextCalculator);
}
@SuppressWarnings("unchecked")
@Override
public void registerContextListener(ContextListener<?> contextListener) {
plugin.getContextManager().registerListener(contextListener);
}
@Override
public Optional<Contexts> getContextForUser(User user) {
ApiUtils.checkUser(user);
@@ -29,9 +29,9 @@ import com.google.common.base.Preconditions;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.common.api.delegate.GroupDelegate;
import me.lucko.luckperms.common.api.delegate.TrackDelegate;
import me.lucko.luckperms.common.api.delegate.UserDelegate;
import me.lucko.luckperms.common.api.delegates.GroupDelegate;
import me.lucko.luckperms.common.api.delegates.TrackDelegate;
import me.lucko.luckperms.common.api.delegates.UserDelegate;
import me.lucko.luckperms.common.utils.ArgumentChecker;
@UtilityClass
@@ -65,22 +65,6 @@ public class ApiUtils {
return s.toLowerCase();
}
public static String checkServer(String s) {
Preconditions.checkArgument(
!ArgumentChecker.checkServer(s),
"Invalid server entry '" + s + "'. Server names can only contain alphanumeric characters."
);
return s;
}
public static String checkNode(String s) {
Preconditions.checkArgument(
!ArgumentChecker.checkNode(s),
"Invalid node entry '" + s + "'. Nodes cannot contain '/' or '$' characters."
);
return s;
}
public static long checkTime(long l) {
Preconditions.checkArgument(!ArgumentChecker.checkTime(l), "Unix time '" + l + "' is invalid, as it has already passed.");
return l;
@@ -1,439 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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.delegate;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.api.Datastore;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.Log;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.Storage;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import static me.lucko.luckperms.common.api.ApiUtils.checkGroup;
import static me.lucko.luckperms.common.api.ApiUtils.checkName;
import static me.lucko.luckperms.common.api.ApiUtils.checkTrack;
import static me.lucko.luckperms.common.api.ApiUtils.checkUser;
import static me.lucko.luckperms.common.api.ApiUtils.checkUsername;
@SuppressWarnings("deprecation")
public class DatastoreDelegate implements Datastore {
private final LuckPermsPlugin plugin;
private final Storage master;
private final Async async;
private final Sync sync;
private final Future future;
public DatastoreDelegate(@NonNull LuckPermsPlugin plugin, @NonNull Storage master) {
this.plugin = plugin;
this.master = master;
this.async = new Async(master);
this.sync = new Sync(master);
this.future = new Future(master);
}
private <T> void registerCallback(CompletableFuture<T> fut, Callback<T> c) {
if (c != null) {
fut.thenAcceptAsync(Callback.convertToConsumer(c), plugin.getSyncExecutor());
}
}
@Override
public String getName() {
return master.getName();
}
@Override
public boolean isAcceptingLogins() {
return master.isAcceptingLogins();
}
@Override
public Datastore.Async async() {
return async;
}
@Override
public Datastore.Sync sync() {
return sync;
}
@Override
public Datastore.Future future() {
return future;
}
@AllArgsConstructor
public class Async implements Datastore.Async {
private final me.lucko.luckperms.common.storage.Storage master;
@Override
public void logAction(@NonNull LogEntry entry, Callback<Boolean> callback) {
registerCallback(master.force().logAction(entry), callback);
}
@Override
public void getLog(@NonNull Callback<Log> callback) {
master.force().getLog().thenAcceptAsync(log -> callback.onComplete(new LogDelegate(log)), plugin.getSyncExecutor());
}
@Override
public void loadOrCreateUser(@NonNull UUID uuid, @NonNull String username, Callback<Boolean> callback) {
registerCallback(master.force().loadUser(uuid, checkUsername(username)), callback);
}
@Override
public void loadUser(@NonNull UUID uuid, Callback<Boolean> callback) {
registerCallback(master.force().loadUser(uuid, "null"), callback);
}
@Override
public void loadUser(@NonNull UUID uuid, @NonNull String username, Callback<Boolean> callback) {
registerCallback(master.force().loadUser(uuid, checkUsername(username)), callback);
}
@Override
public void saveUser(@NonNull User user, Callback<Boolean> callback) {
checkUser(user);
registerCallback(master.force().saveUser(((UserDelegate) user).getMaster()), callback);
}
@Override
public void cleanupUsers(Callback<Boolean> callback) {
registerCallback(master.force().cleanupUsers(), callback);
}
@Override
public void getUniqueUsers(Callback<Set<UUID>> callback) {
registerCallback(master.force().getUniqueUsers(), callback);
}
@Override
public void createAndLoadGroup(@NonNull String name, Callback<Boolean> callback) {
registerCallback(master.force().createAndLoadGroup(checkName(name)), callback);
}
@Override
public void loadGroup(@NonNull String name, Callback<Boolean> callback) {
registerCallback(master.force().loadGroup(checkName(name)), callback);
}
@Override
public void loadAllGroups(Callback<Boolean> callback) {
registerCallback(master.force().loadAllGroups(), callback);
}
@Override
public void saveGroup(@NonNull Group group, Callback<Boolean> callback) {
checkGroup(group);
registerCallback(master.force().saveGroup(((GroupDelegate) group).getMaster()), callback);
}
@Override
public void deleteGroup(@NonNull Group group, Callback<Boolean> callback) {
checkGroup(group);
if (group.getName().equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
registerCallback(master.force().deleteGroup(((GroupDelegate) group).getMaster()), callback);
}
@Override
public void createAndLoadTrack(@NonNull String name, Callback<Boolean> callback) {
registerCallback(master.force().createAndLoadTrack(checkName(name)), callback);
}
@Override
public void loadTrack(@NonNull String name, Callback<Boolean> callback) {
registerCallback(master.force().loadTrack(checkName(name)), callback);
}
@Override
public void loadAllTracks(Callback<Boolean> callback) {
registerCallback(master.force().loadAllTracks(), callback);
}
@Override
public void saveTrack(@NonNull Track track, Callback<Boolean> callback) {
checkTrack(track);
registerCallback(master.force().saveTrack(((TrackDelegate) track).getMaster()), callback);
}
@Override
public void deleteTrack(@NonNull Track track, Callback<Boolean> callback) {
checkTrack(track);
registerCallback(master.force().deleteTrack(((TrackDelegate) track).getMaster()), callback);
}
@Override
public void saveUUIDData(@NonNull String username, @NonNull UUID uuid, Callback<Boolean> callback) {
registerCallback(master.force().saveUUIDData(checkUsername(username), uuid), callback);
}
@Override
public void getUUID(@NonNull String username, Callback<UUID> callback) {
registerCallback(master.force().getUUID(checkUsername(username)), callback);
}
}
@AllArgsConstructor
public class Sync implements Datastore.Sync {
private final Storage master;
@Override
public boolean logAction(@NonNull LogEntry entry) {
return master.force().logAction(entry).join();
}
@Override
public Log getLog() {
me.lucko.luckperms.common.data.Log log = master.force().getLog().join();
if (log == null) {
return null;
}
return new LogDelegate(log);
}
@Override
public boolean loadOrCreateUser(@NonNull UUID uuid, @NonNull String username) {
return master.force().loadUser(uuid, checkUsername(username)).join();
}
@Override
public boolean loadUser(@NonNull UUID uuid) {
return master.force().loadUser(uuid, "null").join();
}
@Override
public boolean loadUser(@NonNull UUID uuid, @NonNull String username) {
return master.force().loadUser(uuid, checkUsername(username)).join();
}
@Override
public boolean saveUser(@NonNull User user) {
checkUser(user);
return master.force().saveUser(((UserDelegate) user).getMaster()).join();
}
@Override
public boolean cleanupUsers() {
return master.force().cleanupUsers().join();
}
@Override
public Set<UUID> getUniqueUsers() {
return master.force().getUniqueUsers().join();
}
@Override
public boolean createAndLoadGroup(@NonNull String name) {
return master.force().createAndLoadGroup(checkName(name)).join();
}
@Override
public boolean loadGroup(@NonNull String name) {
return master.force().loadGroup(checkName(name)).join();
}
@Override
public boolean loadAllGroups() {
return master.force().loadAllGroups().join();
}
@Override
public boolean saveGroup(@NonNull Group group) {
checkGroup(group);
return master.force().saveGroup(((GroupDelegate) group).getMaster()).join();
}
@Override
public boolean deleteGroup(@NonNull Group group) {
checkGroup(group);
if (group.getName().equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
return master.force().deleteGroup(((GroupDelegate) group).getMaster()).join();
}
@Override
public boolean createAndLoadTrack(@NonNull String name) {
return master.force().createAndLoadTrack(checkName(name)).join();
}
@Override
public boolean loadTrack(@NonNull String name) {
return master.force().loadTrack(checkName(name)).join();
}
@Override
public boolean loadAllTracks() {
return master.force().loadAllTracks().join();
}
@Override
public boolean saveTrack(@NonNull Track track) {
checkTrack(track);
return master.force().saveTrack(((TrackDelegate) track).getMaster()).join();
}
@Override
public boolean deleteTrack(@NonNull Track track) {
checkTrack(track);
return master.force().deleteTrack(((TrackDelegate) track).getMaster()).join();
}
@Override
public boolean saveUUIDData(@NonNull String username, @NonNull UUID uuid) {
return master.force().saveUUIDData(checkUsername(username), uuid).join();
}
@Override
public UUID getUUID(@NonNull String username) {
return master.force().getUUID(checkUsername(username)).join();
}
}
@AllArgsConstructor
public class Future implements Datastore.Future {
private final Storage master;
@Override
public java.util.concurrent.Future<Boolean> logAction(@NonNull LogEntry entry) {
return master.force().logAction(entry);
}
@Override
public java.util.concurrent.Future<Log> getLog() {
return master.force().getLog().thenApply(log -> log == null ? null : new LogDelegate(log));
}
@Override
public java.util.concurrent.Future<Boolean> loadOrCreateUser(@NonNull UUID uuid, @NonNull String username) {
return master.force().loadUser(uuid, checkUsername(username));
}
@Override
public java.util.concurrent.Future<Boolean> loadUser(@NonNull UUID uuid) {
return master.force().loadUser(uuid, "null");
}
@Override
public java.util.concurrent.Future<Boolean> loadUser(@NonNull UUID uuid, @NonNull String username) {
return master.force().loadUser(uuid, checkUsername(username));
}
@Override
public java.util.concurrent.Future<Boolean> saveUser(@NonNull User user) {
checkUser(user);
return master.force().saveUser(((UserDelegate) user).getMaster());
}
@Override
public java.util.concurrent.Future<Boolean> cleanupUsers() {
return master.force().cleanupUsers();
}
@Override
public java.util.concurrent.Future<Set<UUID>> getUniqueUsers() {
return master.force().getUniqueUsers();
}
@Override
public java.util.concurrent.Future<Boolean> createAndLoadGroup(@NonNull String name) {
return master.force().createAndLoadGroup(checkName(name));
}
@Override
public java.util.concurrent.Future<Boolean> loadGroup(@NonNull String name) {
return master.force().loadGroup(checkName(name));
}
@Override
public java.util.concurrent.Future<Boolean> loadAllGroups() {
return master.force().loadAllGroups();
}
@Override
public java.util.concurrent.Future<Boolean> saveGroup(@NonNull Group group) {
checkGroup(group);
return master.force().saveGroup(((GroupDelegate) group).getMaster());
}
@Override
public java.util.concurrent.Future<Boolean> deleteGroup(@NonNull Group group) {
checkGroup(group);
if (group.getName().equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
return master.force().deleteGroup(((GroupDelegate) group).getMaster());
}
@Override
public java.util.concurrent.Future<Boolean> createAndLoadTrack(@NonNull String name) {
return master.force().createAndLoadTrack(checkName(name));
}
@Override
public java.util.concurrent.Future<Boolean> loadTrack(@NonNull String name) {
return master.force().loadTrack(checkName(name));
}
@Override
public java.util.concurrent.Future<Boolean> loadAllTracks() {
return master.force().loadAllTracks();
}
@Override
public java.util.concurrent.Future<Boolean> saveTrack(@NonNull Track track) {
checkTrack(track);
return master.force().saveTrack(((TrackDelegate) track).getMaster());
}
@Override
public java.util.concurrent.Future<Boolean> deleteTrack(@NonNull Track track) {
checkTrack(track);
return master.force().deleteTrack(((TrackDelegate) track).getMaster());
}
@Override
public java.util.concurrent.Future<Boolean> saveUUIDData(@NonNull String username, @NonNull UUID uuid) {
return master.force().saveUUIDData(checkUsername(username), uuid);
}
@Override
public java.util.concurrent.Future<UUID> getUUID(@NonNull String username) {
return master.force().getUUID(checkUsername(username));
}
}
}
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.api.delegate;
package me.lucko.luckperms.common.api.delegates;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
@@ -35,7 +35,6 @@ import java.util.List;
import java.util.OptionalInt;
import static me.lucko.luckperms.common.api.ApiUtils.checkGroup;
import static me.lucko.luckperms.common.api.ApiUtils.checkServer;
import static me.lucko.luckperms.common.api.ApiUtils.checkTime;
/**
@@ -83,13 +82,13 @@ public class GroupDelegate extends PermissionHolderDelegate implements Group {
@Override
public void setInheritGroup(@NonNull Group group, @NonNull String server) throws ObjectAlreadyHasException {
checkGroup(group);
master.setInheritGroup(((GroupDelegate) group).getMaster(), checkServer(server));
master.setInheritGroup(((GroupDelegate) group).getMaster(), server);
}
@Override
public void setInheritGroup(@NonNull Group group, @NonNull String server, @NonNull String world) throws ObjectAlreadyHasException {
checkGroup(group);
master.setInheritGroup(((GroupDelegate) group).getMaster(), checkServer(server), world);
master.setInheritGroup(((GroupDelegate) group).getMaster(), server, world);
}
@Override
@@ -101,13 +100,13 @@ public class GroupDelegate extends PermissionHolderDelegate implements Group {
@Override
public void setInheritGroup(@NonNull Group group, @NonNull String server, @NonNull long expireAt) throws ObjectAlreadyHasException {
checkGroup(group);
master.setInheritGroup(((GroupDelegate) group).getMaster(), checkServer(server), checkTime(expireAt));
master.setInheritGroup(((GroupDelegate) group).getMaster(), server, checkTime(expireAt));
}
@Override
public void setInheritGroup(@NonNull Group group, @NonNull String server, @NonNull String world, @NonNull long expireAt) throws ObjectAlreadyHasException {
checkGroup(group);
master.setInheritGroup(((GroupDelegate) group).getMaster(), checkServer(server), world, checkTime(expireAt));
master.setInheritGroup(((GroupDelegate) group).getMaster(), server, world, checkTime(expireAt));
}
@Override
@@ -125,25 +124,25 @@ public class GroupDelegate extends PermissionHolderDelegate implements Group {
@Override
public void unsetInheritGroup(@NonNull Group group, @NonNull String server) throws ObjectLacksException {
checkGroup(group);
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), checkServer(server));
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server);
}
@Override
public void unsetInheritGroup(@NonNull Group group, @NonNull String server, @NonNull String world) throws ObjectLacksException {
checkGroup(group);
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), checkServer(server), world);
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server, world);
}
@Override
public void unsetInheritGroup(@NonNull Group group, @NonNull String server, @NonNull boolean temporary) throws ObjectLacksException {
checkGroup(group);
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), checkServer(server), temporary);
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server, temporary);
}
@Override
public void unsetInheritGroup(@NonNull Group group, @NonNull String server, @NonNull String world, @NonNull boolean temporary) throws ObjectLacksException {
checkGroup(group);
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), checkServer(server), world, temporary);
master.unsetInheritGroup(((GroupDelegate) group).getMaster(), server, world, temporary);
}
@Override
@@ -158,7 +157,7 @@ public class GroupDelegate extends PermissionHolderDelegate implements Group {
@Override
public List<String> getLocalGroups(@NonNull String server, @NonNull String world) {
return master.getLocalGroups(checkServer(server), world);
return master.getLocalGroups(server, world);
}
@Override
@@ -168,6 +167,6 @@ public class GroupDelegate extends PermissionHolderDelegate implements Group {
@Override
public List<String> getLocalGroups(@NonNull String server) {
return master.getLocalGroups(checkServer(server));
return master.getLocalGroups(server);
}
}
Loaded 100 of 363 files, more files were not shown because too many files have changed in this diff. Show more