Compare commits

...
92 Commits
Author SHA1 Message Date
Luck f1606ac51b API changes for 2.15 2016-11-22 18:27:40 +00:00
Luck d13eb1a55d Fix default assignments never being applied on Bungee 2016-11-21 18:26:37 +00:00
Luck 384fbf5464 Revert: Use faster wildcard parsing method 2016-11-21 17:07:13 +00:00
Luck 4874f9d051 Use faster wildcard parsing method 2016-11-20 20:41:39 +00:00
Luck 51732fa660 Rearrange some packages, general cleanup 2016-11-20 13:44:36 +00:00
Luck bb25632178 Improve info command 2016-11-19 21:56:11 +00:00
Luck 9a2cf82623 Improve user info command 2016-11-19 17:52:39 +00:00
Luck c0734fc29e refactor contexts slightly 2016-11-18 22:39:00 +00:00
Luck c60067e733 Maybe fix zPerms migration & tidy up shorthand parser 2016-11-17 22:02:47 +00:00
Luck 6293634e36 refactor shorthand nodes 2016-11-17 20:50:37 +00:00
Luck a047695a84 Fix issue with nodes never being removed on sync with flatfile storage types 2016-11-17 19:01:58 +00:00
Luck db9d84ed76 Maybe fix issue with corrupted permission migration 2016-11-15 20:18:32 +00:00
Luck e296b1df60 Fix migration commands never being executed 2016-11-15 18:17:35 +00:00
Luck b72e5f5437 Update plugin.yml to make LuckPerms always enable before Vault 2016-11-14 22:50:11 +00:00
Luck de09ae94b8 Fix Vault hook - thanks @Yann151924 2016-11-14 22:32:06 +00:00
Luck b36a33f015 Make meta info command show where meta was inherited from 2016-11-14 20:40:33 +00:00
Luck d95891256b Setup a users calculated data when loaded by the SubjectCollection 2016-11-14 18:55:10 +00:00
Luck 9c8097ecb9 Sponge: Implement support for editing more than just users/groups with commands 2016-11-14 18:45:48 +00:00
Luck 18a3dfd604 cleanup 2016-11-13 19:30:46 +00:00
Luck 59fd337e44 remove debug messages, woops 2016-11-13 11:12:06 +00:00
Luck 696cd235fd Fix meta serialization. Resolves #41 2016-11-13 11:09:57 +00:00
Luck 59c7efccb2 Fix Sponge plugin guice load failure. Thanks @gravityfox 2016-11-13 09:44:34 +00:00
Luck b031ebbffd Update readme 2016-11-12 17:27:15 +00:00
Luck 67415babc2 Fix javadocs & fix compile 2016-11-12 16:25:44 +00:00
Luck 563dd4683d Changes for & release of API 2.14 2016-11-12 14:10:42 +00:00
Luck e9131f729a add methods for older sponge api versions 2016-11-11 22:54:09 +00:00
Luck c4ea626e33 Fix PM migration 2016-11-11 20:43:05 +00:00
Luck fefba7976b Actually register new migration command 2016-11-11 20:35:11 +00:00
Luck 2ce8555692 Add Sponge PermissionManager migration support 2016-11-11 20:31:42 +00:00
Luck 9fe9c386bb Sponge: rely less on dummy subjects 2016-11-11 19:32:25 +00:00
Luck e8cd2c7548 More command refactors 2016-11-10 22:13:53 +00:00
Luck 158d8b086a Command refactor 2016-11-10 19:19:43 +00:00
Luck 1c534d7475 More cleanup 2016-11-08 20:46:29 +00:00
Luck 90f8dbe243 Refactor commands 2016-11-07 22:02:48 +00:00
Luck 0c33b26fa9 Refactor meta accumulation 2016-11-07 19:01:15 +00:00
Luck d320679f69 Implement proper meta inheritance handling 2016-11-07 17:32:17 +00:00
Luck 8d5398b5a3 Make nodes with more contexts take priority over nodes with less 2016-11-06 16:15:45 +00:00
Luck 6cd8593fa5 Fix vault primary group override feature 2016-11-06 15:11:28 +00:00
Luck 5ebbc178a5 Remove messenger system & more cleanup 2016-11-06 14:56:13 +00:00
Luck 4f6e229943 Small cleanup 2016-11-05 23:23:08 +00:00
Luck 3e846d9527 Maybe fix split storage - closes #38 2016-11-05 21:43:48 +00:00
Luck 981d745b74 Fix verbose system 2016-11-05 19:19:29 +00:00
Luck 2dd0858960 Allow multiple verbose filters 2016-11-05 19:01:06 +00:00
Luck f72819a664 Try to reduce contention in PermissionHolder 2016-11-05 17:49:52 +00:00
Luck 5361b1e87b Implement group weights 2016-11-05 09:04:26 +00:00
Luck e15d03ed4e Fix parents being cleared on promote/demote 2016-11-05 07:53:18 +00:00
Luck 6c9041ce40 Improve meta info command 2016-11-04 19:13:39 +00:00
Luck 8da96e6e48 Re-add showtracks/showpos commands 2016-11-04 18:36:32 +00:00
Luck 385aa6d438 Add set "none" command as an alternative to unset 2016-11-04 16:40:55 +00:00
Luck 79f24a5944 Improve track functionality. Resolves #39 2016-11-01 21:34:54 +00:00
Luck 80570717f9 Fix slow datastore performance when using the API 2016-11-01 19:41:40 +00:00
Luck ebab79c4ca Maybe fix blocking issue with #getPermissions 2016-11-01 19:38:08 +00:00
Luck 42882ebe11 Update some ugly messages 2016-10-31 22:25:42 +00:00
Luck d2de26f765 Move hasperm/inheritsperm commands & add parent set command. Resolves #40 2016-10-31 19:27:04 +00:00
Luck e2cebfbd16 Refactor Node class 2016-10-31 18:18:31 +00:00
Luck a58cc6bdf3 Refactor PermissionHolder 2016-10-30 21:29:14 +00:00
Luck 36bc1553c0 Implement Sponge timings 2016-10-30 19:35:11 +00:00
Luck 17b06c39e9 Ignore negated primary group override nodes & fix broken message 2016-10-30 15:29:55 +00:00
Luck ba2f6eb7be Update .gitignore 2016-10-30 13:37:25 +00:00
Luck b93145f26d Change some listener priorities 2016-10-30 13:23:45 +00:00
Luck e88ea9c13d Don't fully unload Sponge user subjects 2016-10-30 13:21:43 +00:00
Luck 1275d0023d Listen to PlayerQuit on monitor priority 2016-10-29 22:58:06 +01:00
Luck 27f6f225c9 whoops 2016-10-29 21:56:55 +01:00
Luck 41362aa34a Use a temporary executor until the bukkit one has started 2016-10-29 21:54:13 +01:00
Luck a99609e016 Don't wrap buffer tasks in scheduler calls 2016-10-29 21:23:30 +01:00
Luck c0ea2d8ec3 Fix data not being loaded sync when the plugin starts 2016-10-29 21:14:59 +01:00
Luck bb6b31d715 change Sponge listener priorities 2016-10-29 21:12:55 +01:00
Luck 21695dd2cb Implement support for Bukkit child permissions 2016-10-28 19:16:32 +01:00
Luck 531835c948 Fix GroupManager primary group migration 2016-10-28 18:00:18 +01:00
Luck 77e3b351fd Fix GroupManager user migration 2016-10-28 17:58:36 +01:00
Luck 66f756575a Remove redundant config option 2016-10-27 18:48:38 +01:00
Luck 7acc8bc7ed Add verbose command 2016-10-27 17:46:44 +01:00
Luck 0a4d337a53 Cache context lookups & refactor Sponge subjects 2016-10-27 16:32:14 +01:00
Luck 0198068a13 Improve permission lookup speed (slightly) 2016-10-26 21:35:44 +01:00
Luck 1c15f8462f Don't run commands through the buffer system 2016-10-26 19:52:03 +01:00
Luck 3929ce0dfc Fix compile 2016-10-26 19:32:41 +01:00
Luck 7deeaf305d Experimental: Run I/O after commands in a new thread 2016-10-26 17:55:38 +01:00
Luck 0f04c06e13 Remove redundant method 2016-10-26 17:19:56 +01:00
Luck d1863fa714 Implement more customizable primary groups 2016-10-26 17:19:33 +01:00
Luck 46b122a167 Fix memory leak preventing users from being unloaded 2016-10-25 18:44:11 +01:00
Luck ee3db1e5c5 Maybe fix GroupManager primary group migration 2016-10-25 15:02:49 +01:00
Luck bd830617c9 Small cleanup 2016-10-25 11:14:56 +01:00
Luck a9b6493091 A few small optimizations 2016-10-24 18:48:39 +01:00
Luck 9894e45516 Fix issue with Vault lookups not being preprocessed 2016-10-24 15:57:05 +01:00
Luck 2cfc82f3aa Implement support for instant data propagation with Redis 2016-10-24 14:38:12 +01:00
Luck bb9eab0989 Lower sync wait buffer & fix export command 2016-10-24 13:02:26 +01:00
Luck dc87ec1c82 Update placeholder expansion 2016-10-24 09:57:29 +01:00
Luck 98b7b65ce7 Remove PEX dependency 2016-10-24 09:22:53 +01:00
Luck 9f8f32b33e Fix suffixes not being applied 2016-10-23 22:02:48 +01:00
Luck a80ec6d893 Implement PermissionsEx 2.0 migration for Sponge 2016-10-23 20:42:58 +01:00
Luck 4d85930f5a Refactor migration classes 2016-10-23 20:42:25 +01:00
Luck f722f4112d Update default-lang.yml 2016-10-23 17:59:34 +01:00
264 changed files with 10034 additions and 6127 deletions

No files matched your search

+151 -24
View File
@@ -1,31 +1,27 @@
# built application files
*.jar
# Created by https://www.gitignore.io/
# Java class files
*.class
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# Local configuration file (sdk path, etc)
logs/
# Eclipse project files
.classpath
.project
# Intellij project files
*.iml
*.ipr
*.iws
# User-specific stuff:
.idea/
*.iws
/out/
*.iml
.idea_modules/
# Gradle
.gradletasknamecache
.gradle/
build/
bin/
gradle/
gradlew*
# JIRA plugin
atlassian-ide-plugin.xml
# Maven
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
@@ -34,4 +30,135 @@ pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/timing.properties
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# Eclipse Core
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# JDT-specific (Eclipse Java Development Tools)
.classpath
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
*.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Windows ###
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
### Java ###
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
+9 -4
View File
@@ -8,10 +8,14 @@ An advanced permissions implementation for Bukkit/Spigot, BungeeCord and Sponge.
* **Wiki** - <https://github.com/lucko/LuckPerms/wiki>
## Description
LuckPerms is an advanced permissions implementation aiming to be a flexible, performant and reliable alternative to other permission systems, providing all the features you could ever possibly need in a permissions plugin, along with an extensive and well documented API for developers.
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.
* [Spigot Plugin Page](https://www.spigotmc.org/resources/luckperms-an-advanced-permissions-system.28140/ "Spigot Plugin Page")
* [Sponge Plugin Page](https://forums.spongepowered.org/t/luckperms-an-advanced-permissions-system/14274 "Sponge Plugin Page")
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.
* [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")
## LuckPerms vs Other Plugins
### Bukkit
@@ -20,10 +24,11 @@ _Features checked on 23rd Aug 2016. If you find any inaccuracies, please do let
### 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._
## License
LuckPerms is licensed under the permissive MIT license. See LICENSE.md for more info.
## Thanks to:
## Sponsor
[![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").
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.13-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -32,6 +32,7 @@ import java.util.Map;
* @since 2.11
*/
public class Contexts {
private static final Contexts ALLOW_ALL = new Contexts(ContextSet.empty(), true, true, true, true, true, true);
public static final String SERVER_KEY = "server";
public static final String WORLD_KEY = "world";
@@ -40,7 +41,7 @@ public class Contexts {
* @return a context that will not apply any filters
*/
public static Contexts allowAll() {
return new Contexts(ContextSet.empty(), true, true, true, true, true, true);
return ALLOW_ALL;
}
public static Contexts of(ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
@@ -29,226 +29,50 @@ import java.util.UUID;
/**
* Interface for the internal Datastore instance
* @deprecated as of version 2.14 in favour of {@link Storage}.
*/
@SuppressWarnings("unused")
@Deprecated
public interface Datastore {
String getName();
boolean isAcceptingLogins();
/**
* Gets the {@link Sync} interface.
*
* All operations through this interface are called immediately and in the same thread as they are called.
* Datastore operations are thread blocking, and Sync operations should not be called on the main server thread.
* @return the sync interface
*/
@Deprecated
Sync sync();
/**
* Gets the {@link Async} interface.
*
* All operations through this interface are called in a new, separate asynchronous thread.
* When the operation is complete, the provided callback method is called, in applicable, in the main server thread.
* @return the async interface
*/
@Deprecated
Async async();
/**
* Gets the {@link Future} interface.
*
* All operations through this interface are called in a new, separate asynchronous thread, similar to {@link Async}.
* The only difference is that instead of providing a callback, a {@link java.util.concurrent.Future} is returned.
* See the Oracle JavaDocs for usage of the Future class.
* @return the future interface
*/
@Deprecated
Future future();
/**
* All operations through this interface are called immediately and in the same thread as they are called.
* Datastore operations are thread blocking, and Sync operations should not be called on the main server thread.
*/
@Deprecated
interface Sync {
/**
* Saves an action to the datastore
* @param entry the log entry to be saved
* @return true if the operation completed successfully.
* @throws NullPointerException if entry is null
*/
boolean logAction(LogEntry entry);
/**
* Loads and returns the log from the datastore
* @return a log instance, could be null
*/
Log getLog();
/**
* Either loads or creates a user object, and loads it into the plugins internal storage
* @param uuid the uuid of the user
* @param username the users username. (if you want to specify <code>null</code> here, just input "null" as a string.)
* @return true if the operation completed successfully.
* @throws NullPointerException if uuid or username is null
* @throws IllegalArgumentException if either of the parameters are invalid
* @deprecated functionality of this method is taken on by {@link #loadUser(UUID, String)}
*/
@Deprecated
boolean loadOrCreateUser(UUID uuid, String username);
/**
* Loads a user from the datastore into the plugins internal storage.
* @param uuid the uuid of the user to load
* @return true if the user exists, and was loaded correctly.
* @throws NullPointerException if uuid is null
* @deprecated replaced by {@link #loadUser(UUID, String)}
*/
@Deprecated
boolean loadUser(UUID uuid);
/**
* Loads a user's data into the plugins internal storage.
* @param uuid the uuid of the user to load
* @param username the users username. (if you want to specify <code>null</code> here, just input "null" as a string.)
* @return if the operation was performed successfully
* @throws NullPointerException if uuid or username is null
* @since 2.6
*/
boolean loadUser(UUID uuid, String username);
/**
* Saves a user object into the datastore. You should call this after you make any changes to a user.
* @param user the user to save
* @return true if the operation completed successfully.
* @throws NullPointerException if user is null
* @throws IllegalStateException if the user instance was not obtained from LuckPerms.
*/
boolean saveUser(User user);
/**
* Removes users from the datastore who are "default". This is called every time the plugin loads.
* @return true if the operation completed successfully
* @since 2.6
*/
boolean cleanupUsers();
/**
* Gets a set all user's UUIDs who are "unique", and aren't just a member of the "default" group.
* @return a set of uuids, or null if the operation failed.
* @since 2.6
*/
Set<UUID> getUniqueUsers();
/**
* Creates and loads a group into the plugins internal storage
* @param name the name of the group
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
boolean createAndLoadGroup(String name);
/**
* Loads a group into the plugins internal storage.
* @param name the name of the group
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
boolean loadGroup(String name);
/**
* Loads all groups from the datastore into the plugins internal storage
* @return true if the operation completed successfully.
*/
boolean loadAllGroups();
/**
* Saves a group back to the datastore. You should call this after you make any changes to a group.
* @param group the group to save
* @return true if the operation completed successfully.
* @throws NullPointerException if group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
*/
boolean saveGroup(Group group);
/**
* Permanently deletes a group from the datastore
* @param group the group to delete
* @return true if the operation completed successfully.
* @throws NullPointerException if group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
*/
boolean deleteGroup(Group group);
/**
* Creates and loads a track into the plugins internal storage
* @param name the name of the track
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
boolean createAndLoadTrack(String name);
/**
* Loads a track into the plugins internal storage.
* @param name the name of the track
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
boolean loadTrack(String name);
/**
* Loads all tracks from the datastore into the plugins internal storage
* @return true if the operation completed successfully.
*/
boolean loadAllTracks();
/**
* Saves a track back to the datastore. You should call this after you make any changes to a track.
* @param track the track to save
* @return true if the operation completed successfully.
* @throws NullPointerException if track is null
* @throws IllegalStateException if the track instance was not obtained from LuckPerms.
*/
boolean saveTrack(Track track);
/**
* Permanently deletes a track from the datastore
* @param track the track to delete
* @return true if the operation completed successfully.
* @throws NullPointerException if track is null
* @throws IllegalStateException if the track instance was not obtained from LuckPerms.
*/
boolean deleteTrack(Track track);
/**
* Saves UUID caching data to the datastore
* @param username the users username
* @param uuid the users mojang unique id
* @return true if the operation completed successfully.
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
*/
boolean saveUUIDData(String username, UUID uuid);
/**
* Gets a UUID from a username
* @param username the corresponding username
* @return a uuid object, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
*/
UUID getUUID(String username);
}
/**
* All operations through this interface are called in a new, separate asynchronous thread.
* When the operation is complete, the provided callback method is called, in applicable, in the main server thread.
*
* See {@link Sync} for method documentation.
*/
@Deprecated
interface Async {
void logAction(LogEntry entry, Callback<Boolean> callback);
void getLog(Callback<Log> callback);
@@ -274,13 +98,7 @@ public interface Datastore {
void getUUID(String username, Callback<UUID> callback);
}
/**
* All operations through this interface are called in a new, separate asynchronous thread, similar to {@link Async}.
* The only difference is that instead of providing a callback, a {@link java.util.concurrent.Future} is returned.
* See the Oracle JavaDocs for usage of the Future class.
*
* See {@link Sync} for method documentation.
*/
@Deprecated
interface Future {
java.util.concurrent.Future<Boolean> logAction(LogEntry entry);
java.util.concurrent.Future<Log> getLog();
@@ -109,7 +109,9 @@ public interface LPConfiguration {
/**
* @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();
/**
@@ -79,11 +79,27 @@ public interface LuckPermsApi {
LPConfiguration getConfiguration();
/**
* Gets a wrapped {@link Datastore} instance, with somewhat limited access
* @return a datastore instance
* Gets a wrapped {@link Storage} instance.
* @return a storage instance
* @since 2.14
*/
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.
* @return an optional that may contain a messaging service instance.
*/
Optional<MessagingService> getMessagingService();
/**
* Gets the {@link Logger} wrapping used by the platform
* @return the logger instance
@@ -92,7 +108,7 @@ public interface LuckPermsApi {
/**
* Gets a wrapped {@link UuidCache} instance, providing read access to the LuckPerms internal uuid caching system
* @return a uuidcache instance
* @return a uuid cache instance
*/
UuidCache getUuidCache();
@@ -234,4 +250,12 @@ public interface LuckPermsApi {
*/
void registerContextListener(ContextListener<?> contextListener);
/**
* Gets a calculated context instance for the user using the rules of the platform.
* These values are calculated using the options in the configuration, and the provided calculators.
* @param user the user to get contexts for
* @return an optional containing contexts. Will return empty if the user is not online.
*/
Optional<Contexts> getContextForUser(User user);
}
@@ -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;
/**
* Exposes any networking provider being used on the platform. e.g. Redis
* @since 2.14
*/
public interface MessagingService {
/**
* Uses the messaging service to inform other servers about changes.
* This will push the update asynchronously, and this method will return almost immediately.
*/
void pushUpdate();
}
@@ -0,0 +1,217 @@
/*
* 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 java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
/**
* Interface for the internal Storage instance
*
* All methods return {@link CompletableFuture}s, which will be populated with the result once the data has been loaded
* asynchronously. Care should be taken when using the methods to ensure that the main server thread is not blocked.
*
* Methods such as {@link CompletableFuture#get()} and equivalent should <strong>not</strong> be called on the main server thread.
* If you need to use the result of these operations on the main server thread, please register a callback using
* {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)} and {@link #getSyncExecutor()}.
*
* @since 2.14
*/
public interface Storage {
/**
* Get the name of the storage implementation.
* @return the name of the implementation
*/
String getName();
/**
* Return whether the storage instance is allowing logins on the platform.
* @return true if logins are enabled
*/
boolean isAcceptingLogins();
/**
* Returns an executor which will run all passed runnables on the main server thread.
* @return an executor instance
*/
Executor getSyncExecutor();
/**
* Returns an executor which will run all passed runnables asynchronously using the platforms scheduler and thread pools.
* @return an executor instance
*/
Executor getAsyncExecutor();
/**
* Saves an action to storage
* @param entry the log entry to be saved
* @return true if the operation completed successfully.
* @throws NullPointerException if entry is null
*/
CompletableFuture<Boolean> logAction(LogEntry entry);
/**
* Loads and returns the entire log from storage
* @return a log instance, could be null if loading failed
*/
CompletableFuture<Log> getLog();
/**
* Loads a user's data from the main storage into the plugins local storage.
* @param uuid the uuid of the user to load
* @param username the users username. (if you want to specify <code>null</code> here, just input "null" as a string.)
* @return if the operation completed successfully
* @throws NullPointerException if uuid or username is null
*/
CompletableFuture<Boolean> loadUser(UUID uuid, String username);
/**
* Saves a user object back to storage. You should call this after you make any changes to a user.
* @param user the user to save
* @return true if the operation completed successfully.
* @throws NullPointerException if user is null
* @throws IllegalStateException if the user instance was not obtained from LuckPerms.
*/
CompletableFuture<Boolean> saveUser(User user);
/**
* Removes users from the main storage who are "default". This is called every time the plugin loads.
* @return true if the operation completed successfully
*/
CompletableFuture<Boolean> cleanupUsers();
/**
* Gets a set all "unique" user UUIDs.
* "Unique" meaning the user isn't just a member of the "default" group.
* @return a set of uuids, or null if the operation failed.
*/
CompletableFuture<Set<UUID>> getUniqueUsers();
/**
* Creates and loads a group into the plugins local storage
* @param name the name of the group
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
CompletableFuture<Boolean> createAndLoadGroup(String name);
/**
* Loads a group into the plugins local storage.
* @param name the name of the group
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
CompletableFuture<Boolean> loadGroup(String name);
/**
* Loads all groups from the storage into memory
* @return true if the operation completed successfully.
*/
CompletableFuture<Boolean> loadAllGroups();
/**
* Saves a group back to storage. You should call this after you make any changes to a group.
* @param group the group to save
* @return true if the operation completed successfully.
* @throws NullPointerException if group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
*/
CompletableFuture<Boolean> saveGroup(Group group);
/**
* Permanently deletes a group from storage.
* @param group the group to delete
* @return true if the operation completed successfully.
* @throws NullPointerException if group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
*/
CompletableFuture<Boolean> deleteGroup(Group group);
/**
* Creates and loads a track into the plugins local storage
* @param name the name of the track
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
CompletableFuture<Boolean> createAndLoadTrack(String name);
/**
* Loads a track into the plugins local storage.
* @param name the name of the track
* @return true if the operation completed successfully
* @throws NullPointerException if name is null
* @throws IllegalArgumentException if the name is invalid
*/
CompletableFuture<Boolean> loadTrack(String name);
/**
* Loads all tracks from the storage into memory
* @return true if the operation completed successfully.
*/
CompletableFuture<Boolean> loadAllTracks();
/**
* Saves a track back to storage. You should call this after you make any changes to a track.
* @param track the track to save
* @return true if the operation completed successfully.
* @throws NullPointerException if track is null
* @throws IllegalStateException if the track instance was not obtained from LuckPerms.
*/
CompletableFuture<Boolean> saveTrack(Track track);
/**
* Permanently deletes a track from storage
* @param track the track to delete
* @return true if the operation completed successfully.
* @throws NullPointerException if track is null
* @throws IllegalStateException if the track instance was not obtained from LuckPerms.
*/
CompletableFuture<Boolean> deleteTrack(Track track);
/**
* Saves UUID caching data to the global cache
* @param username the users username
* @param uuid the users mojang unique id
* @return true if the operation completed successfully.
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
*/
CompletableFuture<Boolean> saveUUIDData(String username, UUID uuid);
/**
* Gets a UUID from a username
* @param username the corresponding username
* @return a uuid object, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
*/
CompletableFuture<UUID> getUUID(String username);
}
@@ -32,8 +32,8 @@ import java.util.UUID;
* they first join the server, but this UUID will then not be consistent across the network. LuckPerms will instead check
* the datastore cache, to get a UUID for a user that is consistent across an entire network.
*
* <p> If you want to get a user object from the datastore using the api on a server in offline mode, you will need to use this cache,
* OR use Datastore#getUUID, for users that are not online.
* <p> If you want to get a user object from the Storage using the api on a server in offline mode, you will need to use this cache,
* OR use Storage#getUUID, for users that are not online.
*
* <p> WARNING: THIS IS ONLY EFFECTIVE FOR ONLINE PLAYERS. USE THE DATASTORE METHODS FOR OFFLINE PLAYERS.
*/
@@ -37,6 +37,7 @@ import java.util.stream.Collectors;
* @since 2.13
*/
public class ContextSet {
private static final ContextSet EMPTY = new ContextSet();
/**
* Make a singleton ContextSet from a context pair
@@ -112,7 +113,7 @@ public class ContextSet {
* @return a new ContextSet
*/
public static ContextSet empty() {
return new ContextSet();
return EMPTY;
}
final Set<Map.Entry<String, String>> contexts;
@@ -303,4 +304,9 @@ public class ContextSet {
public int hashCode() {
return 59 + (this.contexts == null ? 43 : this.contexts.hashCode());
}
@Override
public String toString() {
return "ContextSet(contexts=" + this.contexts + ")";
}
}
@@ -28,7 +28,9 @@ 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> {
/**
@@ -55,4 +57,17 @@ public interface Callback<T> {
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;
}
}
+13 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.13-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -75,6 +75,18 @@
<pattern>com.google.gson</pattern>
<shadedPattern>me.lucko.luckperms.lib.gson</shadedPattern>
</relocation>
<relocation>
<pattern>redis.clients.jedis</pattern>
<shadedPattern>me.lucko.luckperms.lib.jedis.jedis</shadedPattern>
</relocation>
<relocation>
<pattern>redis.clients.util</pattern>
<shadedPattern>me.lucko.luckperms.lib.jedis.util</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache.commons.pool2</pattern>
<shadedPattern>me.lucko.luckperms.lib.jedis.pool2</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
+2 -2
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.13-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -30,7 +30,7 @@
<dependency>
<groupId>me.lucko.luckperms</groupId>
<artifactId>luckperms-api</artifactId>
<version>2.8</version>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<!-- BukkitAPI -->
@@ -26,16 +26,20 @@ import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.TimeUtil;
import me.lucko.luckperms.api.*;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.api.context.MutableContextSet;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.Optional;
import java.util.stream.Collectors;
/*
* PlaceholderAPI Expansion for LuckPerms, implemented using the LuckPerms API.
*
* Placeholders:
* - group_name
* - groups
* - has_permission_<node>
* - inherits_permission_<node>
* - in_group_<name>
@@ -71,7 +75,14 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
@Override
public String getVersion() {
return "2.8";
return "2.13";
}
private Contexts makeContexts(Player player) {
MutableContextSet contextSet = new MutableContextSet();
contextSet.add("server", api.getConfiguration().getVaultServer());
contextSet.add("world", player.getWorld().getName());// ignore world?
return Contexts.of(contextSet.makeImmutable(), api.getConfiguration().getVaultIncludeGlobal(), true, true, true, true, player.isOp());
}
@Override
@@ -84,14 +95,24 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
if (!u.isPresent()) {
return "";
}
final User user = u.get();
Optional<UserData> d = user.getUserDataCache();
if (!d.isPresent()) {
return "";
}
final UserData data = d.get();
identifier = identifier.toLowerCase();
final User user = u.get();
if (identifier.equalsIgnoreCase("group_name")) {
return user.getPrimaryGroup();
}
if (identifier.equalsIgnoreCase("groups")) {
return user.getGroupNames().stream().collect(Collectors.joining(", "));
}
if (identifier.startsWith("has_permission_") && identifier.length() > "has_permission_".length()) {
String node = identifier.substring("has_permission_".length());
return formatBoolean(user.hasPermission(node, true));
@@ -99,7 +120,7 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
if (identifier.startsWith("inherits_permission_") && identifier.length() > "inherits_permission_".length()) {
String node = identifier.substring("inherits_permission_".length());
return formatBoolean(user.inheritsPermission(node, true));
return formatBoolean(data.getPermissionData(makeContexts(player)).getPermissionValue(node).asBoolean());
}
if (identifier.startsWith("in_group_") && identifier.length() > "in_group_".length()) {
@@ -109,7 +130,7 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
if (identifier.startsWith("inherits_group_") && identifier.length() > "inherits_group_".length()) {
String groupName = identifier.substring("inherits_group_".length());
return formatBoolean(user.getLocalGroups("global").contains(groupName));
return formatBoolean(data.getPermissionData(makeContexts(player)).getPermissionValue("group." + groupName).asBoolean());
}
if (identifier.startsWith("on_track_") && identifier.length() > "on_track_".length()) {
@@ -125,7 +146,7 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
String node = identifier.substring("expiry_time_".length());
long currentTime = System.currentTimeMillis() / 1000L;
for (Node n : user.getTemporaryPermissionNodes()) {
if (n.getPermission().equalsIgnoreCase(node)) {
if (n.toSerializedNode().equalsIgnoreCase(node)) {
return TimeUtil.getTime((int) (n.getExpiryUnixTime() - currentTime));
}
}
@@ -146,16 +167,28 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
}
if (identifier.equalsIgnoreCase("prefix")) {
return MetaUtils.getPrefix(user, null, null, true);
String prefix = data.calculateMeta(makeContexts(player)).getPrefix();
if (prefix == null) {
prefix = "";
}
return prefix;
}
if (identifier.equalsIgnoreCase("suffix")) {
return MetaUtils.getSuffix(user, null, null, true);
String suffix = data.calculateMeta(makeContexts(player)).getSuffix();
if (suffix == null) {
suffix = "";
}
return suffix;
}
if (identifier.startsWith("meta_") && identifier.length() > "meta_".length()) {
String node = identifier.substring("meta_".length());
return MetaUtils.getMeta(user, null, null, node, "", true);
String meta = data.getMetaData(makeContexts(player)).getMeta().get(node);
if (meta == null) {
meta = "";
}
return meta;
}
return null;
+54 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.13-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -70,6 +70,18 @@
<pattern>org.h2</pattern>
<shadedPattern>me.lucko.luckperms.lib.h2</shadedPattern>
</relocation>
<relocation>
<pattern>redis.clients.jedis</pattern>
<shadedPattern>me.lucko.luckperms.lib.jedis.jedis</shadedPattern>
</relocation>
<relocation>
<pattern>redis.clients.util</pattern>
<shadedPattern>me.lucko.luckperms.lib.jedis.util</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache.commons.pool2</pattern>
<shadedPattern>me.lucko.luckperms.lib.jedis.pool2</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
@@ -129,5 +141,46 @@
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
<!-- **************Migration Plugins************** -->
<dependency>
<groupId>org.tyrannyofheaven.bukkit</groupId>
<artifactId>zPermissions</artifactId>
<version>1.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ru.tehkode</groupId>
<artifactId>PermissionsEx</artifactId>
<version>1.23</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
<exclusion>
<groupId>net.gravitydevelopment.updater</groupId>
<artifactId>updater</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.cheesesoftware</groupId>
<artifactId>PowerfulPermsAPI</artifactId>
<version>1.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.anjocaido</groupId>
<artifactId>GroupManager</artifactId>
<version>1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.bananaco</groupId>
<artifactId>bpermissions-api</artifactId>
<version>2.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -22,18 +22,22 @@
package me.lucko.luckperms.bukkit;
import com.google.common.collect.ImmutableList;
import lombok.AllArgsConstructor;
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.inject.LPPermissible;
import me.lucko.luckperms.common.calculators.*;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.calculators.PermissionCalculator;
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.users.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@AllArgsConstructor
@@ -41,23 +45,24 @@ public class BukkitCalculatorFactory implements CalculatorFactory {
private final LPBukkitPlugin plugin;
@Override
public PermissionCalculator build(Contexts contexts, User user, Map<String, Boolean> map) {
public PermissionCalculator build(Contexts contexts, User user) {
UUID uuid = plugin.getUuidCache().getExternalUUID(user.getUuid());
List<PermissionProcessor> processors = new ArrayList<>(5);
processors.add(new MapProcessor(map));
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
processors.add(new MapProcessor());
processors.add(new ChildProcessor(plugin.getChildPermissionProvider()));
processors.add(new AttachmentProcessor(() -> {
LPPermissible permissible = Injector.getPermissible(uuid);
return permissible == null ? null : permissible.getAttachmentPermissions();
}));
if (plugin.getConfiguration().isApplyingWildcards()) {
processors.add(new WildcardProcessor(map));
processors.add(new WildcardProcessor());
}
if (plugin.getConfiguration().isApplyingRegex()) {
processors.add(new RegexProcessor(map));
processors.add(new RegexProcessor());
}
processors.add(new DefaultsProcessor(contexts.isOp(), plugin.getDefaultsProvider()));
return new PermissionCalculator(plugin, user.getName(), plugin.getConfiguration().isDebugPermissionChecks(), processors);
return new PermissionCalculator(plugin, user.getName(), processors.build());
}
}
@@ -24,10 +24,8 @@ package me.lucko.luckperms.bukkit;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.commands.Util;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Patterns;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@@ -38,24 +36,26 @@ import java.util.Arrays;
import java.util.List;
class BukkitCommand extends CommandManager implements CommandExecutor, TabExecutor {
BukkitCommand(LuckPermsPlugin plugin) {
private final LPBukkitPlugin plugin;
BukkitCommand(LPBukkitPlugin plugin) {
super(plugin);
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
onCommand(
BukkitSenderFactory.get(getPlugin()).wrap(sender),
plugin.getSenderFactory().wrap(sender),
label,
Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(Joiner.on(' ').join(args))),
Callback.empty()
null
);
return true;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
return onTabComplete(BukkitSenderFactory.get(getPlugin()).wrap(sender), Arrays.asList(args));
return onTabComplete(plugin.getSenderFactory().wrap(sender), Arrays.asList(args));
}
}
@@ -23,7 +23,7 @@
package me.lucko.luckperms.bukkit;
import me.lucko.luckperms.bukkit.inject.Injector;
import me.lucko.luckperms.bukkit.inject.LPPermissible;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.AbstractListener;
@@ -35,6 +35,7 @@ import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
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.UUID;
@@ -48,7 +49,7 @@ class BukkitListener extends AbstractListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerPreLogin(AsyncPlayerPreLoginEvent e) {
if (!plugin.isStarted() || !plugin.getDatastore().isAcceptingLogins()) {
if (!plugin.isStarted() || !plugin.getStorage().isAcceptingLogins()) {
// The datastore is disabled, prevent players from joining the server
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
@@ -61,7 +62,7 @@ class BukkitListener extends AbstractListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerPreLoginMonitor(AsyncPlayerPreLoginEvent e) {
if (plugin.isStarted() && plugin.getDatastore().isAcceptingLogins() && e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
if (plugin.isStarted() && plugin.getStorage().isAcceptingLogins() && e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
// Login event was cancelled by another plugin
onLeave(e.getUniqueId());
@@ -106,7 +107,7 @@ class BukkitListener extends AbstractListener implements Listener {
}
}
@EventHandler(priority = EventPriority.HIGHEST) // Allow other plugins to see data when this event gets called.
@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());
@@ -143,4 +144,11 @@ class BukkitListener extends AbstractListener implements Listener {
e.getPlayer().sendMessage(Message.OP_DISABLED.toString());
}
}
@EventHandler
public void onPluginEnable(PluginEnableEvent e) {
if (e.getPlugin().getName().equalsIgnoreCase("Vault")) {
plugin.tryVaultHook(true);
}
}
}
@@ -23,7 +23,7 @@
package me.lucko.luckperms.bukkit;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.SenderFactory;
import me.lucko.luckperms.common.commands.sender.SenderFactory;
import me.lucko.luckperms.common.constants.Constants;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -31,19 +31,10 @@ import org.bukkit.entity.Player;
import java.util.UUID;
public class BukkitSenderFactory extends SenderFactory<CommandSender> {
private static BukkitSenderFactory instance = null;
private BukkitSenderFactory(LuckPermsPlugin plugin) {
public BukkitSenderFactory(LuckPermsPlugin plugin) {
super(plugin);
}
public static synchronized BukkitSenderFactory get(LuckPermsPlugin plugin) {
if (instance == null) {
instance = new BukkitSenderFactory(plugin);
}
return instance;
}
@Override
protected String getName(CommandSender sender) {
if (sender instanceof Player) {
@@ -31,13 +31,14 @@ 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.calculators.DefaultsProvider;
import me.lucko.luckperms.bukkit.model.ChildPermissionProvider;
import me.lucko.luckperms.bukkit.model.DefaultsProvider;
import me.lucko.luckperms.bukkit.vault.VaultHook;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.api.ApiProvider;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.commands.ConsecutiveExecutor;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.config.LPConfiguration;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.contexts.ContextManager;
@@ -45,13 +46,16 @@ import me.lucko.luckperms.common.contexts.ServerCalculator;
import me.lucko.luckperms.common.core.UuidCache;
import me.lucko.luckperms.common.data.Importer;
import me.lucko.luckperms.common.groups.GroupManager;
import me.lucko.luckperms.common.runnables.ExpireTemporaryTask;
import me.lucko.luckperms.common.runnables.UpdateTask;
import me.lucko.luckperms.common.storage.Datastore;
import me.lucko.luckperms.common.messaging.RedisMessaging;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.storage.StorageFactory;
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
import me.lucko.luckperms.common.tasks.UpdateTask;
import me.lucko.luckperms.common.tracks.TrackManager;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.users.UserManager;
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 org.bukkit.World;
@@ -65,10 +69,16 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
@Getter
public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private ExecutorService executorService;
private Executor syncExecutor;
private Executor asyncExecutor;
private VaultHook vaultHook = null;
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
@@ -76,27 +86,78 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private UserManager userManager;
private GroupManager groupManager;
private TrackManager trackManager;
private Datastore datastore;
private Storage storage;
private RedisMessaging redisMessaging = null;
private UuidCache uuidCache;
private ApiProvider apiProvider;
private Logger log;
private Importer importer;
private ConsecutiveExecutor consecutiveExecutor;
private DefaultsProvider defaultsProvider;
private ChildPermissionProvider childPermissionProvider;
private LocaleManager localeManager;
private ContextManager<Player> contextManager;
private WorldCalculator worldCalculator;
private CalculatorFactory calculatorFactory;
private BufferedRequest<Void> updateTaskBuffer;
private boolean started = false;
private DebugHandler debugHandler;
private BukkitSenderFactory senderFactory;
@Override
public void onEnable() {
// Used whilst the server is still starting
executorService = Executors.newCachedThreadPool();
asyncExecutor = executorService;
syncExecutor = r -> getServer().getScheduler().runTask(this, r);
log = LogFactory.wrap(getLogger());
debugHandler = new DebugHandler();
senderFactory = new BukkitSenderFactory(this);
getLog().info("Loading configuration...");
configuration = new BukkitConfig(this);
// setup the Bukkit defaults hook
defaultsProvider = new DefaultsProvider();
childPermissionProvider = new ChildPermissionProvider();
// give all plugins a chance to load their defaults, then refresh.
getServer().getScheduler().runTaskLater(this, () -> {
defaultsProvider.refresh();
childPermissionProvider.setup();
}, 1L);
// register events
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new BukkitListener(this), this);
// initialise datastore
storage = StorageFactory.getInstance(this, "h2");
// initialise redis
if (getConfiguration().isRedisEnabled()) {
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();
}
}
// setup the update task buffer
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
@Override
protected Void perform() {
new UpdateTask(LPBukkitPlugin.this).run();
return null;
}
};
// load locale
localeManager = new LocaleManager();
File locale = new File(getDataFolder(), "lang.yml");
if (locale.exists()) {
@@ -108,13 +169,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
}
defaultsProvider = new DefaultsProvider();
getServer().getScheduler().runTaskLater(this, () -> defaultsProvider.refresh(), 1L);
// register events
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new BukkitListener(this), this);
// register commands
getLog().info("Registering commands...");
BukkitCommand commandManager = new BukkitCommand(this);
@@ -123,8 +177,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
main.setTabCompleter(commandManager);
main.setAliases(Arrays.asList("perms", "lp", "permissions", "p", "perm"));
datastore = StorageFactory.getDatastore(this, "h2");
// load internal managers
getLog().info("Loading internal permission managers...");
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
userManager = new UserManager(this);
@@ -140,58 +193,46 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
contextManager.registerCalculator(worldCalculator);
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
// handle server operators
if (getConfiguration().isAutoOp()) {
contextManager.registerListener(new AutoOPListener());
}
final LPBukkitPlugin i = this;
updateTaskBuffer = new BufferedRequest<Void>(6000L, this::doAsync) {
@Override
protected Void perform() {
getServer().getScheduler().runTaskAsynchronously(i, new UpdateTask(i));
return null;
}
};
int mins = getConfiguration().getSyncTime();
if (mins > 0) {
long ticks = mins * 60 * 20;
getServer().getScheduler().runTaskTimerAsynchronously(this, () -> updateTaskBuffer.request(), ticks, ticks);
}
getServer().getScheduler().runTaskTimer(this, BukkitSenderFactory.get(this), 1L, 1L);
getServer().getScheduler().runTaskTimerAsynchronously(this, new ExpireTemporaryTask(this), 60L, 60L);
getServer().getScheduler().runTaskTimerAsynchronously(this, consecutiveExecutor, 20L, 20L);
// Provide vault support
getLog().info("Attempting to hook into Vault...");
try {
if (getServer().getPluginManager().isPluginEnabled("Vault")) {
vaultHook = new VaultHook();
vaultHook.hook(this);
getLog().info("Registered Vault permission & chat hook.");
} else {
getLog().info("Vault not found.");
}
} catch (Exception e) {
getLog().severe("Error occurred whilst hooking into Vault.");
e.printStackTrace();
}
tryVaultHook(false);
// register with the LP API
getLog().info("Registering API...");
apiProvider = new ApiProvider(this);
ApiHandler.registerProvider(apiProvider);
getServer().getServicesManager().register(LuckPermsApi.class, apiProvider, this, ServicePriority.Normal);
// Run update task to refresh any online users
getLog().info("Scheduling Update Task to refresh any online users.");
updateTaskBuffer.request();
// schedule update tasks
int mins = getConfiguration().getSyncTime();
if (mins > 0) {
long ticks = mins * 60 * 20;
getServer().getScheduler().runTaskTimerAsynchronously(this, () -> updateTaskBuffer.request(), 20L, ticks);
}
// run an update instantly.
updateTaskBuffer.requestDirectly();
// register tasks
getServer().getScheduler().runTaskTimerAsynchronously(this, new ExpireTemporaryTask(this), 60L, 60L);
getServer().getScheduler().runTaskTimerAsynchronously(this, consecutiveExecutor, 20L, 20L);
// register permissions
registerPermissions(getConfiguration().isCommandsAllowOp() ? PermissionDefault.OP : PermissionDefault.FALSE);
if (!getConfiguration().isOpsEnabled()) {
getServer().getOperators().forEach(o -> o.setOp(false));
}
// replace the temporary executor when the Bukkit one starts
getServer().getScheduler().runTaskAsynchronously(this, () -> {
asyncExecutor = r -> getServer().getScheduler().runTaskAsynchronously(this, r);
});
started = true;
getLog().info("Successfully loaded.");
}
@@ -200,7 +241,12 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
public void onDisable() {
started = false;
getLog().info("Closing datastore...");
datastore.shutdown();
storage.shutdown();
if (redisMessaging != null) {
getLog().info("Closing redis...");
redisMessaging.shutdown();
}
getLog().info("Unregistering API...");
ApiHandler.unregisterProvider();
@@ -211,14 +257,35 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
}
public void tryVaultHook(boolean force) {
if (vaultHook != null) {
return;
}
getLog().info("Attempting to hook with Vault...");
try {
if (force || getServer().getPluginManager().isPluginEnabled("Vault")) {
vaultHook = new VaultHook();
vaultHook.hook(this);
getLog().info("Registered Vault permission & chat hook.");
} else {
getLog().info("Vault not found.");
}
} catch (Exception e) {
vaultHook = null;
getLog().severe("Error occurred whilst hooking into Vault.");
e.printStackTrace();
}
}
@Override
public void doAsync(Runnable r) {
getServer().getScheduler().runTaskAsynchronously(this, r);
asyncExecutor.execute(r);
}
@Override
public void doSync(Runnable r) {
getServer().getScheduler().runTask(this, r);
syncExecutor.execute(r);
}
@Override
@@ -241,6 +308,28 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
return getDataFolder();
}
@Override
public Player getPlayer(User user) {
return getServer().getPlayer(uuidCache.getExternalUUID(user.getUuid()));
}
@Override
public Contexts getContextForUser(User user) {
Player player = getPlayer(user);
if (player == null) {
return null;
}
return new Contexts(
getContextManager().getApplicableContext(player),
getConfiguration().isIncludingGlobalPerms(),
getConfiguration().isIncludingGlobalWorldPerms(),
true,
getConfiguration().isApplyingGlobalGroups(),
getConfiguration().isApplyingGlobalWorldGroups(),
player.isOp()
);
}
@Override
public int getPlayerCount() {
return getServer().getOnlinePlayers().size();
@@ -262,16 +351,15 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
@Override
public List<Sender> getNotifyListeners() {
public List<Sender> getSenders() {
return getServer().getOnlinePlayers().stream()
.map(p -> BukkitSenderFactory.get(this).wrap(p, Collections.singleton(Permission.LOG_NOTIFY)))
.filter(Permission.LOG_NOTIFY::isAuthorized)
.map(p -> getSenderFactory().wrap(p))
.collect(Collectors.toList());
}
@Override
public Sender getConsoleSender() {
return BukkitSenderFactory.get(this).wrap(getServer().getConsoleSender());
return getSenderFactory().wrap(getServer().getConsoleSender());
}
@Override
@@ -324,12 +412,12 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
);
// Check for and include varying Vault config options
try {
assert getConfiguration().isVaultIncludingGlobal() == getConfiguration().isIncludingGlobalPerms();
assert getConfiguration().isIncludingGlobalWorldPerms();
assert getConfiguration().isApplyingGlobalGroups();
assert getConfiguration().isApplyingGlobalWorldGroups();
} catch (AssertionError e) {
boolean vaultDiff = getConfiguration().isVaultIncludingGlobal() != getConfiguration().isIncludingGlobalPerms() ||
!getConfiguration().isIncludingGlobalWorldPerms() ||
!getConfiguration().isApplyingGlobalGroups() ||
!getConfiguration().isApplyingGlobalWorldGroups();
if (vaultDiff) {
contexts.addAll(c.stream()
.map(map -> new Contexts(map, getConfiguration().isVaultIncludingGlobal(), true, true, true, true, op))
.collect(Collectors.toSet())
@@ -339,6 +427,24 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
return contexts;
}
@Override
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("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());
return map;
}
@Override
public Object getPlugin(String name) {
return getServer().getPluginManager().getPlugin(name);
@@ -71,11 +71,11 @@ public class WorldCalculator extends ContextCalculator<Player> implements Listen
private String getWorld(Player player) {
UUID internal = plugin.getUuidCache().getUUID(player.getUniqueId());
if (!worldCache.containsKey(internal)) {
String world = worldCache.get(internal);
if (world == null) {
return null;
}
String world = worldCache.get(internal);
return plugin.getConfiguration().getWorldRewrites().getOrDefault(world, world);
}
@@ -48,4 +48,9 @@ public class AttachmentProcessor implements PermissionProcessor {
return pai == null ? Tristate.UNDEFINED : Tristate.fromBoolean(pai.getValue());
}
@Override
public void updateBacking(Map<String, Boolean> map) {
// Do nothing, this doesn't use the backing
}
}
@@ -24,7 +24,7 @@ package me.lucko.luckperms.bukkit.calculators;
import me.lucko.luckperms.api.context.ContextListener;
import me.lucko.luckperms.bukkit.inject.Injector;
import me.lucko.luckperms.bukkit.inject.LPPermissible;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import org.bukkit.entity.Player;
import java.util.Map;
@@ -20,49 +20,35 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.utils;
package me.lucko.luckperms.bukkit.calculators;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.bukkit.model.ChildPermissionProvider;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
public class AbstractFuture<R> implements LPFuture<R> {
private final CountDownLatch latch = new CountDownLatch(1);
private R value;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public void complete(R r) {
value = r;
latch.countDown();
@RequiredArgsConstructor
public class ChildProcessor implements PermissionProcessor {
private final ChildPermissionProvider provider;
private Map<String, Boolean> childPermissions = new ConcurrentHashMap<>();
@Override
public Tristate hasPermission(String permission) {
Boolean b = childPermissions.get(permission);
return b == null ? Tristate.UNDEFINED : Tristate.fromBoolean(b);
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
// Not supported
return false;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return latch.getCount() == 0;
}
@Override
public R get() throws InterruptedException {
latch.await();
return value;
}
@Override
public R get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
if (latch.await(timeout, unit)) {
return value;
} else {
throw new TimeoutException();
public void updateBacking(Map<String, Boolean> map) {
childPermissions.clear();
for (Map.Entry<String, Boolean> e : map.entrySet()) {
Map<String, Boolean> children = provider.getPermissions().get(e);
if (children != null) {
childPermissions.putAll(children);
}
}
}
}
@@ -24,10 +24,13 @@ package me.lucko.luckperms.bukkit.calculators;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.bukkit.model.DefaultsProvider;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import org.bukkit.Bukkit;
import org.bukkit.permissions.Permission;
import java.util.Map;
@AllArgsConstructor
public class DefaultsProcessor implements PermissionProcessor {
private final boolean isOp;
@@ -43,4 +46,9 @@ public class DefaultsProcessor implements PermissionProcessor {
Permission defPerm = Bukkit.getServer().getPluginManager().getPermission(permission);
return defPerm == null ? Tristate.UNDEFINED : Tristate.fromBoolean(defPerm.getDefault().getValue(isOp));
}
@Override
public void updateBacking(Map<String, Boolean> map) {
// Do nothing, this doesn't use the backing
}
}
@@ -23,6 +23,7 @@
package me.lucko.luckperms.bukkit.inject;
import lombok.experimental.UtilityClass;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permissible;
@@ -20,19 +20,20 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.commands.migration.subcommands;
package me.lucko.luckperms.bukkit.migration;
import de.bananaco.bpermissions.api.*;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.Predicate;
import me.lucko.luckperms.common.commands.Sender;
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.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import java.lang.reflect.Field;
@@ -82,11 +83,11 @@ public class MigrationBPermissions extends SubCommand<Object> {
}
public MigrationBPermissions() {
super("bpermissions", "Migration from bPermissions", MIGRATION, Predicate.alwaysFalse(), null);
super("bpermissions", "Migration from bPermissions", MIGRATION, Predicates.alwaysFalse(), null);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) {
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();
@@ -121,7 +122,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
}
// Make a LuckPerms group for the one being migrated.
plugin.getDatastore().createAndLoadGroup(groupName).getUnchecked();
plugin.getStorage().createAndLoadGroup(groupName).join();
me.lucko.luckperms.common.groups.Group lpGroup = plugin.getGroupManager().get(groupName);
try {
LogEntry.build()
@@ -133,7 +134,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
}
migrateHolder(plugin, world, group, lpGroup);
plugin.getDatastore().saveGroup(lpGroup);
plugin.getStorage().saveGroup(lpGroup);
}
log.info("bPermissions Migration: Migrated " + groupCount + " groups in world " + world.getName() + ".");
@@ -157,12 +158,12 @@ public class MigrationBPermissions extends SubCommand<Object> {
}
// Make a LuckPerms user for the one being migrated.
plugin.getDatastore().loadUser(uuid, "null").getUnchecked();
plugin.getStorage().loadUser(uuid, "null").join();
me.lucko.luckperms.common.users.User lpUser = plugin.getUserManager().get(uuid);
migrateHolder(plugin, world, user, lpUser);
plugin.getDatastore().saveUser(lpUser);
plugin.getStorage().saveUser(lpUser);
plugin.getUserManager().cleanup(lpUser);
}
@@ -20,15 +20,22 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.commands.migration.subcommands;
package me.lucko.luckperms.bukkit.migration;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.*;
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.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import org.anjocaido.groupmanager.GlobalGroups;
import org.anjocaido.groupmanager.GroupManager;
import org.anjocaido.groupmanager.data.Group;
@@ -36,19 +43,18 @@ import org.anjocaido.groupmanager.data.User;
import org.anjocaido.groupmanager.dataholder.WorldDataHolder;
import org.anjocaido.groupmanager.dataholder.worlds.WorldsHolder;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;
public class MigrationGroupManager extends SubCommand<Object> {
public MigrationGroupManager() {
super("groupmanager", "Migration from GroupManager", Permission.MIGRATION, Predicate.is(0),
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"))
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) {
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.");
@@ -63,17 +69,10 @@ public class MigrationGroupManager extends SubCommand<Object> {
// Migrate Global Groups
log.info("GroupManager Migration: Starting Global Group migration.");
GlobalGroups gg;
try {
gg = (GlobalGroups) GroupManager.class.getMethod("getGlobalGroups").invoke(gm);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
return CommandResult.FAILURE;
}
GlobalGroups gg = GroupManager.getGlobalGroups();
for (Group g : gg.getGroupList()) {
plugin.getDatastore().createAndLoadGroup(g.getName().toLowerCase()).getUnchecked();
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase()).join();
me.lucko.luckperms.common.groups.Group group = plugin.getGroupManager().get(g.getName().toLowerCase());
try {
LogEntry.build()
@@ -121,33 +120,21 @@ public class MigrationGroupManager extends SubCommand<Object> {
}
}
plugin.getDatastore().saveGroup(group);
plugin.getStorage().saveGroup(group);
}
Map<UUID, Map<Map.Entry<String, String>, Boolean>> users = new HashMap<>();
Map<UUID, String> primaryGroups = new HashMap<>();
Map<String, Map<Map.Entry<String, String>, Boolean>> groups = new HashMap<>();
WorldsHolder wh;
try {
wh = (WorldsHolder) GroupManager.class.getMethod("getWorldsHolder").invoke(gm);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
return CommandResult.FAILURE;
}
WorldsHolder wh = gm.getWorldsHolder();
// Collect data for all users and groups.
log.info("GroupManager Migration: Starting user and group migration.");
for (String world : worlds) {
world = world.toLowerCase();
WorldDataHolder wdh;
try {
wdh = (WorldDataHolder) WorldsHolder.class.getMethod("getWorldData", String.class).invoke(wh, world);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
return CommandResult.FAILURE;
}
WorldDataHolder wdh = wh.getWorldData(world);
for (Group g : wdh.getGroupList()) {
groups.putIfAbsent(g.getName().toLowerCase(), new HashMap<>());
@@ -193,7 +180,13 @@ public class MigrationGroupManager extends SubCommand<Object> {
users.get(uuid).put(new AbstractMap.SimpleEntry<>(world, node), value);
}
users.get(uuid).put(new AbstractMap.SimpleEntry<>(world, "group." + user.getGroupName().toLowerCase()), true);
String finalWorld = world;
users.get(uuid).putAll(user.subGroupListStringCopy().stream()
.map(n -> "group." + n)
.map(n -> new AbstractMap.SimpleEntry<>(finalWorld, n))
.collect(Collectors.toMap(n -> n, n -> true))
);
primaryGroups.put(uuid, user.getGroupName());
}
}
@@ -202,7 +195,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
log.info("GroupManager Migration: Found a total of " + users.size() + " users and " + groups.size() + " groups.");
for (Map.Entry<String, Map<Map.Entry<String, String>, Boolean>> e : groups.entrySet()) {
plugin.getDatastore().createAndLoadGroup(e.getKey()).getUnchecked();
plugin.getStorage().createAndLoadGroup(e.getKey()).join();
me.lucko.luckperms.common.groups.Group group = plugin.getGroupManager().get(e.getKey());
try {
LogEntry.build()
@@ -219,7 +212,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
// n.key.value = node
// n.value = true/false
try {
group.setPermission("global-" + n.getKey().getKey() + "/" + n.getKey().getValue(), n.getValue());
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);
@@ -241,11 +234,11 @@ public class MigrationGroupManager extends SubCommand<Object> {
}
}
plugin.getDatastore().saveGroup(group);
plugin.getStorage().saveGroup(group);
}
for (Map.Entry<UUID, Map<Map.Entry<String, String>, Boolean>> e : users.entrySet()) {
plugin.getDatastore().loadUser(e.getKey(), "null").getUnchecked();
plugin.getStorage().loadUser(e.getKey(), "null").join();
me.lucko.luckperms.common.users.User user = plugin.getUserManager().get(e.getKey());
for (Map.Entry<Map.Entry<String, String>, Boolean> n : e.getValue().entrySet()) {
@@ -253,7 +246,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
// n.key.value = node
// n.value = true/false
try {
user.setPermission("global-" + n.getKey().getKey() + "/" + n.getKey().getValue(), n.getValue());
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);
@@ -275,7 +268,18 @@ public class MigrationGroupManager extends SubCommand<Object> {
}
}
plugin.getDatastore().saveUser(user);
String primaryGroup = primaryGroups.get(e.getKey());
if (primaryGroup != null) {
try {
user.setPermission("group." + primaryGroup, true);
} catch (ObjectAlreadyHasException ignored) {}
user.setPrimaryGroup(primaryGroup);
try {
user.unsetPermission("group.default");
} catch (ObjectLacksException ignored) {}
}
plugin.getStorage().saveUser(user);
plugin.getUserManager().cleanup(user);
}
@@ -20,18 +20,23 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.commands.migration.subcommands;
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.*;
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.data.LogEntry;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import ru.tehkode.permissions.NativeInterface;
import ru.tehkode.permissions.PermissionGroup;
@@ -40,21 +45,20 @@ import ru.tehkode.permissions.PermissionUser;
import ru.tehkode.permissions.bukkit.PermissionsEx;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public class MigrationPermissionsEx extends SubCommand<Object> {
public MigrationPermissionsEx() {
super("permissionsex", "Migration from PermissionsEx", Permission.MIGRATION, Predicate.alwaysFalse(),
super("permissionsex", "Migration from PermissionsEx", Permission.MIGRATION, Predicates.alwaysFalse(),
Arg.list(Arg.create("world names...", false, "a list of worlds to migrate permissions from"))
);
}
@SuppressWarnings("deprecation")
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) {
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.");
@@ -72,13 +76,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
.collect(Collectors.toList());
PermissionsEx pex = (PermissionsEx) plugin.getPlugin("PermissionsEx");
PermissionManager manager; // The compiler complains if you call the method directly, as Bukkit is not in this module.
try {
manager = (PermissionManager) PermissionsEx.class.getMethod("getPermissionsManager").invoke(pex);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
return CommandResult.FAILURE;
}
PermissionManager manager = pex.getPermissionsManager();
NativeInterface ni;
try {
@@ -102,7 +100,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
maxGroupWeight = Math.max(maxGroupWeight, groupWeight);
final String name = group.getName().toLowerCase();
plugin.getDatastore().createAndLoadGroup(name).getUnchecked();
plugin.getStorage().createAndLoadGroup(name).join();
Group lpGroup = plugin.getGroupManager().get(name);
try {
LogEntry.build()
@@ -226,7 +224,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
}
}
plugin.getDatastore().saveGroup(lpGroup);
plugin.getStorage().saveGroup(lpGroup);
}
@@ -254,7 +252,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
}
userCount++;
plugin.getDatastore().loadUser(u, "null").getUnchecked();
plugin.getStorage().loadUser(u, "null").join();
User lpUser = plugin.getUserManager().get(u);
try {
@@ -387,7 +385,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
}
plugin.getUserManager().cleanup(lpUser);
plugin.getDatastore().saveUser(lpUser);
plugin.getStorage().saveUser(lpUser);
}
log.info("PermissionsEx Migration: Migrated " + userCount + " users.");
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.commands.migration.subcommands;
package me.lucko.luckperms.bukkit.migration;
import com.github.cheesesoftware.PowerfulPermsAPI.*;
import com.google.common.util.concurrent.ListenableFuture;
@@ -28,13 +28,18 @@ import com.zaxxer.hikari.HikariDataSource;
import lombok.Cleanup;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.bukkit.migration.utils.LPResultRunnable;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.*;
import me.lucko.luckperms.common.commands.migration.subcommands.utils.LPResultRunnable;
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.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import java.lang.reflect.InvocationTargetException;
@@ -116,7 +121,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
public MigrationPowerfulPerms() {
super("powerfulperms", "Migration from PowerfulPerms", MIGRATION, Predicate.not(5),
super("powerfulperms", "Migration from PowerfulPerms", MIGRATION, Predicates.not(5),
Arg.list(
Arg.create("address", true, "the address of the PP database"),
Arg.create("database", true, "the name of the PP database"),
@@ -128,7 +133,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) {
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) throws CommandException {
try {
return run(plugin, args);
} catch (Throwable t) {
@@ -246,7 +251,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
log.info("PowerfulPerms Migration: Starting group migration.");
Map<Integer, Group> groups = pm.getGroups(); // All versions
for (Group g : groups.values()) {
plugin.getDatastore().createAndLoadGroup(g.getName().toLowerCase()).getUnchecked();
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase()).join();
final me.lucko.luckperms.common.groups.Group group = plugin.getGroupManager().get(g.getName().toLowerCase());
try {
LogEntry.build()
@@ -275,7 +280,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
}
}
plugin.getDatastore().saveGroup(group);
plugin.getStorage().saveGroup(group);
}
log.info("PowerfulPerms Migration: Group migration complete.");
@@ -288,7 +293,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
progress.put(uuid, new CountDownLatch(2));
// Create a LuckPerms user for the UUID
plugin.getDatastore().loadUser(uuid, "null").getUnchecked();
plugin.getStorage().loadUser(uuid, "null").join();
User user = plugin.getUserManager().get(uuid);
// Get a list of Permissions held by the user from the PP API.
@@ -299,7 +304,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
synchronized (progress) {
progress.get(uuid).countDown();
if (progress.get(uuid).getCount() == 0) {
plugin.getDatastore().saveUser(user);
plugin.getStorage().saveUser(user);
plugin.getUserManager().cleanup(user);
}
}
@@ -422,7 +427,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
synchronized (progress) {
progress.get(uuid).countDown();
if (progress.get(uuid).getCount() == 0) {
plugin.getDatastore().saveUser(user);
plugin.getStorage().saveUser(user);
plugin.getUserManager().cleanup(user);
}
}
@@ -0,0 +1,152 @@
/*
* 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.migration;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.common.LuckPermsPlugin;
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.Permission;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.tracks.Track;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
import org.tyrannyofheaven.bukkit.zPermissions.dao.PermissionService;
import org.tyrannyofheaven.bukkit.zPermissions.model.EntityMetadata;
import org.tyrannyofheaven.bukkit.zPermissions.model.Entry;
import org.tyrannyofheaven.bukkit.zPermissions.model.Inheritance;
import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity;
import java.lang.reflect.Field;
import java.util.List;
import java.util.UUID;
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.");
return CommandResult.STATE_ERROR;
}
ZPermissionsService service = (ZPermissionsService) plugin.getService(ZPermissionsService.class);
if (service == null) {
log.severe("zPermissions Migration: Error -> zPermissions is not loaded.");
return CommandResult.STATE_ERROR;
}
PermissionService internalService;
try {
Field psField = service.getClass().getDeclaredField("permissionService");
psField.setAccessible(true);
internalService = (PermissionService) psField.get(service);
} catch (Exception e) {
e.printStackTrace();
return CommandResult.FAILURE;
}
// Migrate all groups
log.info("zPermissions Migration: Starting group migration.");
for (String g : service.getAllGroups()) {
plugin.getStorage().createAndLoadGroup(g.toLowerCase()).join();
Group group = plugin.getGroupManager().get(g.toLowerCase());
PermissionEntity entity = internalService.getEntity(g, null, true);
migrateEntity(group, entity);
plugin.getStorage().saveGroup(group);
}
// Migrate all tracks
log.info("zPermissions Migration: Starting track migration.");
for (String t : service.getAllTracks()) {
plugin.getStorage().createAndLoadTrack(t.toLowerCase()).join();
Track track = plugin.getTrackManager().get(t.toLowerCase());
track.setGroups(service.getTrackGroups(t));
plugin.getStorage().saveTrack(track);
}
// Migrate all users.
log.info("zPermissions Migration: Starting user migration.");
for (UUID u : service.getAllPlayersUUID()) {
plugin.getStorage().loadUser(u, "null").join();
User user = plugin.getUserManager().get(u);
PermissionEntity entity = internalService.getEntity(null, u, false);
migrateEntity(user, entity);
user.setPrimaryGroup(service.getPlayerPrimaryGroup(u));
plugin.getUserManager().cleanup(user);
plugin.getStorage().saveUser(user);
}
log.info("zPermissions Migration: Success! Completed without any errors.");
return CommandResult.SUCCESS;
}
private void migrateEntity(PermissionHolder group, PermissionEntity entity) {
for (Entry e : entity.getPermissions()) {
if (e.getWorld() != null) {
try {
group.setPermission(e.getPermission(), true, "global", e.getWorld().getName());
} catch (ObjectAlreadyHasException ignored) {}
} else {
try {
group.setPermission(e.getPermission(), true); // TODO handle negated.
} catch (ObjectAlreadyHasException ignored) {}
}
}
for (Inheritance inheritance : entity.getInheritancesAsChild()) {
if (!inheritance.getChild().getId().equals(entity.getId())) {
new Throwable("Illegal inheritance").printStackTrace();
continue;
}
try {
group.setPermission("group." + inheritance.getParent(), true);
} catch (ObjectAlreadyHasException ignored) {}
}
for (EntityMetadata metadata : entity.getMetadata()) {
try {
group.setPermission(NodeFactory.makeMetaNode(metadata.getName(), metadata.getStringValue()).build());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.commands.migration.subcommands.utils;
package me.lucko.luckperms.bukkit.migration.utils;
import com.github.cheesesoftware.PowerfulPermsAPI.ResultRunnable;
@@ -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.bukkit.model;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.permissions.Permission;
import java.util.Collections;
import java.util.HashMap;
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> 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 = 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())) {
continue; // Prevent infinite loops
}
Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey());
boolean value = e.getValue() ^ invert;
String lName = e.getKey().toLowerCase();
accumulator.put(lName, value);
if (perm != null) {
resolveChildren(accumulator, perm.getChildren(), !value);
}
}
}
}
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit.calculators;
package me.lucko.luckperms.bukkit.model;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.Tristate;
@@ -102,6 +102,10 @@ public class DefaultsProvider {
return b == null ? Tristate.UNDEFINED : Tristate.fromBoolean(b);
}
public int size() {
return op.size() + nonOp.size();
}
@AllArgsConstructor
private static class DummyPermissible implements Permissible {
private final Runnable onRefresh;
@@ -20,13 +20,12 @@
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit.inject;
package me.lucko.luckperms.bukkit.model;
import lombok.Getter;
import lombok.NonNull;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.users.User;
import org.bukkit.Bukkit;
@@ -67,7 +66,7 @@ public class LPPermissible extends PermissibleBase {
public Contexts calculateContexts() {
return new Contexts(
plugin.getContextManager().giveApplicableContext(parent, new MutableContextSet()),
plugin.getContextManager().getApplicableContext(parent),
plugin.getConfiguration().isIncludingGlobalPerms(),
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
true,
@@ -185,7 +184,7 @@ public class LPPermissible extends PermissibleBase {
}
PermissionAttachment result = addAttachment(plugin);
if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new RemoveAttachmentRunnable(result), ticks) == -1) {
if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> result.remove(), ticks) == -1) {
Bukkit.getServer().getLogger().log(Level.WARNING, "Could not add PermissionAttachment to " + parent + " for plugin " + plugin.getDescription().getFullName() + ": Scheduler returned -1");
result.remove();
return null;
@@ -255,16 +254,4 @@ public class LPPermissible extends PermissibleBase {
}
}
}
private class RemoveAttachmentRunnable implements Runnable {
private PermissionAttachment attachment;
private RemoveAttachmentRunnable(PermissionAttachment attachment) {
this.attachment = attachment;
}
public void run() {
attachment.remove();
}
}
}
@@ -27,9 +27,12 @@ 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.core.NodeFactory;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import net.milkbowl.vault.chat.Chat;
@@ -82,11 +85,8 @@ public class VaultChatHook extends Chat {
perms.log("Setting meta: '" + node + "' for " + holder.getObjectName() + " on world " + world + ", server " + perms.getServer());
perms.getScheduler().scheduleTask(() -> {
String k = escapeCharacters(node);
String v = escapeCharacters(value);
List<Node> toRemove = holder.getNodes().stream()
.filter(n -> n.isMeta() && n.getMeta().getKey().equals(k))
.filter(n -> n.isMeta() && n.getMeta().getKey().equals(node))
.collect(Collectors.toList());
toRemove.forEach(n -> {
@@ -95,7 +95,7 @@ public class VaultChatHook extends Chat {
} catch (ObjectLacksException ignored) {}
});
Node.Builder metaNode = new me.lucko.luckperms.common.core.Node.Builder("meta." + k + "." + v).setValue(true);
Node.Builder metaNode = NodeFactory.makeMetaNode(node, value).setValue(true);
if (!perms.getServer().equalsIgnoreCase("global")) {
metaNode.setServer(perms.getServer());
}
@@ -119,7 +119,7 @@ public class VaultChatHook extends Chat {
perms.log("Setting " + (prefix ? "prefix" : "suffix") + " for " + holder.getObjectName() + " on world " + world + ", server " + perms.getServer());
perms.getScheduler().scheduleTask(() -> {
Node.Builder node = new me.lucko.luckperms.common.core.Node.Builder(prefix ? "prefix" : "suffix" + ".1000." + escapeCharacters(value));
Node.Builder node = new NodeBuilder(prefix ? "prefix" : "suffix" + ".1000." + escapeCharacters(value));
node.setValue(true);
if (!perms.getServer().equalsIgnoreCase("global")) {
node.setServer(perms.getServer());
@@ -215,7 +215,8 @@ public class VaultChatHook extends Chat {
context.put("world", world);
}
for (Node n : group.getAllNodes(null, new Contexts(ContextSet.fromMap(context), perms.isIncludeGlobal(), true, true, true, true, false))) {
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;
}
@@ -42,7 +42,11 @@ public class VaultHook {
permissionHook.setPlugin(plugin);
permissionHook.setServer(plugin.getConfiguration().getVaultServer());
permissionHook.setIncludeGlobal(plugin.getConfiguration().isVaultIncludingGlobal());
permissionHook.setIncludeGlobal(plugin.getConfiguration().isVaultIgnoreWorld());
permissionHook.setIgnoreWorld(plugin.getConfiguration().isVaultIgnoreWorld());
permissionHook.setPgo(plugin.getConfiguration().isVaultPrimaryGroupOverrides());
permissionHook.setPgoCheckInherited(plugin.getConfiguration().isVaultPrimaryGroupOverridesCheckInherited());
permissionHook.setPgoCheckExists(plugin.getConfiguration().isVaultPrimaryGroupOverridesCheckExists());
permissionHook.setPgoCheckMemberOf(plugin.getConfiguration().isVaultPrimaryGroupOverridesCheckMemberOf());
permissionHook.setup();
if (chatHook == null) {
@@ -22,11 +22,15 @@
package me.lucko.luckperms.bukkit.vault;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
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.core.PermissionHolder;
@@ -43,33 +47,30 @@ import java.util.Map;
* The LuckPerms Vault Permission implementation
* Most lookups are cached.
*/
@Getter
@Setter
public class VaultPermissionHook extends Permission {
@Getter
@Setter
private LPBukkitPlugin plugin;
@Getter
@Setter(value = AccessLevel.NONE)
private VaultScheduler scheduler;
@Getter
@Setter
private String server = "global";
@Getter
@Setter
private boolean includeGlobal = true;
@Getter
@Setter
private boolean ignoreWorld = false;
// Primary Group override settings
private boolean pgo = false;
private boolean pgoCheckInherited = false;
private boolean pgoCheckExists = true;
private boolean pgoCheckMemberOf = true;
public void setup() {
scheduler = new VaultScheduler(plugin);
}
public void log(String s) {
if (plugin.getConfiguration().isDebugPermissionChecks()) {
if (plugin.getConfiguration().isVaultDebug()) {
plugin.getLog().info("[VAULT] " + s);
}
}
@@ -81,7 +82,7 @@ public class VaultPermissionHook extends Permission {
@Override
public boolean isEnabled() {
return plugin.getDatastore().isAcceptingLogins();
return plugin.getStorage().isAcceptingLogins();
}
@Override
@@ -131,13 +132,12 @@ public class VaultPermissionHook extends Permission {
*/
void save(PermissionHolder holder) {
if (holder instanceof User) {
plugin.getDatastore().saveUser(((User) holder), b -> {
((User) holder).getRefreshBuffer().request();
});
plugin.getStorage().saveUser(((User) holder))
.thenRunAsync(() -> ((User) holder).getRefreshBuffer().request(), plugin.getAsyncExecutor());
}
if (holder instanceof Group) {
plugin.getDatastore().saveGroup(((Group) holder), b -> plugin.getUpdateTaskBuffer().request());
plugin.getStorage().saveGroup(((Group) holder))
.thenRunAsync(() -> plugin.getUpdateTaskBuffer().request(), plugin.getAsyncExecutor());
}
}
@@ -311,9 +311,81 @@ public class VaultPermissionHook extends Permission {
@Override
public String getPrimaryGroup(String world, @NonNull String player) {
world = ignoreWorld ? null : world; // Correct world value
log("Getting primary group of player: " + player);
final User user = plugin.getUserManager().get(player);
return (user == null) ? null : user.getPrimaryGroup();
if (user == null) {
return null;
}
if (!pgo) {
return user.getPrimaryGroup();
}
if (pgoCheckInherited) {
PermissionData data = user.getUserData().getPermissionData(createContext(server, world));
for (Map.Entry<String, Boolean> e : data.getImmutableBacking().entrySet()) {
if (!e.getValue()) {
continue;
}
if (!e.getKey().toLowerCase().startsWith("vault.primarygroup.")) {
continue;
}
String group = e.getKey().substring("vault.primarygroup.".length());
if (pgoCheckExists) {
if (!plugin.getGroupManager().isLoaded(group)) {
continue;
}
}
if (pgoCheckMemberOf) {
if (data.getPermissionValue("group." + group) != Tristate.TRUE) {
continue;
}
}
return group;
}
} else {
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;
}
String group = node.getPermission().substring("vault.primarygroup.".length());
if (pgoCheckExists) {
if (!plugin.getGroupManager().isLoaded(group)) {
continue;
}
}
if (pgoCheckMemberOf) {
if (!user.getLocalGroups(server, world, isIncludeGlobal()).contains(group.toLowerCase())) {
continue;
}
}
return group;
}
}
// Fallback
return user.getPrimaryGroup();
}
@Override
+34 -3
View File
@@ -46,9 +46,6 @@ online-mode: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# If LuckPerms should print to console every time a plugin checks if a player has a permission
debug-permission-checks: false
@@ -70,6 +67,11 @@ apply-regex: true
# If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# Define special group weights for this server.
# Default is just 0.
group-weight:
# admin: 10
@@ -112,6 +114,22 @@ vault-include-global: true
# If Vault operations should ignore any world arguments if supplied.
vault-ignore-world: false
# This block controls the Primary Group override feature
# See the wiki for more information.
vault-primary-groups-overrides:
# If the feature is enabled
enabled: false
# If the check should query the user's inherited permissions.
# (a value of false only checks the permissions they explicitly have)
check-inherited-permissions: false
# If LuckPerms should check if the group exists
check-group-exists: true
# If LuckPerms should check if the user is actually a member of the group
check-user-member-of: true
# If LuckPerms should print debugging info to console when a plugin uses a Vault function
vault-debug: false
# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in this list, the value assigned
# will be sent forward for permission calculation instead.
world-rewrite:
@@ -155,6 +173,19 @@ 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.
#
# If enabled and configured, LuckPerms will use the Redis PubSub 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.
#
# 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.
redis:
enabled: false
address: localhost:6379
password: ''
+8 -2
View File
@@ -5,7 +5,12 @@ author: Luck
website: https://github.com/lucko/LuckPerms
main: me.lucko.luckperms.bukkit.LPBukkitPlugin
softdepend: [Vault, PermissionsEx, GroupManager, PowerfulPerms, zPermissions, bPermissions] # For migration
load: STARTUP
# This means that all plugins that (soft-)depend on Vault, depend on LuckPerms too.
# 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]
commands:
luckperms:
@@ -13,4 +18,5 @@ commands:
aliases: [perms, permissions, lp, p, perm]
# Permissions are registered programmatically instead of here.
# Permissions are registered programmatically instead of here.
# See: the last method in me.lucko.luckperms.bukkit.LPBukkitPlugin
+20 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.13-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -69,6 +69,18 @@
<pattern>org.sqlite</pattern>
<shadedPattern>me.lucko.luckperms.lib.sqlite</shadedPattern>
</relocation>
<relocation>
<pattern>redis.clients.jedis</pattern>
<shadedPattern>me.lucko.luckperms.lib.jedis.jedis</shadedPattern>
</relocation>
<relocation>
<pattern>redis.clients.util</pattern>
<shadedPattern>me.lucko.luckperms.lib.jedis.util</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache.commons.pool2</pattern>
<shadedPattern>me.lucko.luckperms.lib.jedis.pool2</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
@@ -121,6 +133,13 @@
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
<!-- **************Migration Plugins************** -->
<dependency>
<groupId>net.alpenblock</groupId>
<artifactId>BungeePerms</artifactId>
<version>3.0-dev-52</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -22,30 +22,32 @@
package me.lucko.luckperms.bungee;
import com.google.common.collect.ImmutableList;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.common.calculators.*;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.calculators.PermissionCalculator;
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.users.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@AllArgsConstructor
public class BungeeCalculatorFactory implements CalculatorFactory {
private final LPBungeePlugin plugin;
@Override
public PermissionCalculator build(Contexts contexts, User user, Map<String, Boolean> map) {
List<PermissionProcessor> processors = new ArrayList<>(3);
processors.add(new MapProcessor(map));
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(map));
processors.add(new WildcardProcessor());
}
if (plugin.getConfiguration().isApplyingRegex()) {
processors.add(new RegexProcessor(map));
processors.add(new RegexProcessor());
}
return new PermissionCalculator(plugin, user.getName(), plugin.getConfiguration().isDebugPermissionChecks(), processors);
return new PermissionCalculator(plugin, user.getName(), processors.build());
}
}
@@ -24,9 +24,8 @@ package me.lucko.luckperms.bungee;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.commands.Util;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Patterns;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
@@ -35,25 +34,27 @@ import net.md_5.bungee.api.plugin.TabExecutor;
import java.util.Arrays;
class BungeeCommand extends Command implements TabExecutor {
private final LPBungeePlugin plugin;
private final CommandManager manager;
BungeeCommand(CommandManager manager) {
BungeeCommand(LPBungeePlugin plugin, CommandManager manager) {
super("luckpermsbungee", null, "bperms", "lpb", "bpermissions", "bp", "bperm");
this.plugin = plugin;
this.manager = manager;
}
@Override
public void execute(CommandSender sender, String[] args) {
manager.onCommand(
BungeeSenderFactory.get(manager.getPlugin()).wrap(sender),
plugin.getSenderFactory().wrap(sender),
"bperms",
Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(Joiner.on(' ').join(args))),
Callback.empty()
null
);
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
return manager.onTabComplete(BungeeSenderFactory.get(manager.getPlugin()).wrap(sender), Arrays.asList(args));
return manager.onTabComplete(plugin.getSenderFactory().wrap(sender), Arrays.asList(args));
}
}
@@ -23,10 +23,10 @@
package me.lucko.luckperms.bungee;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.api.event.events.UserFirstLoginEvent;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.core.UuidCache;
import me.lucko.luckperms.common.defaults.Rule;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.AbstractListener;
import net.md_5.bungee.api.chat.TextComponent;
@@ -38,6 +38,7 @@ import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -72,7 +73,7 @@ public class BungeeListener extends AbstractListener implements Listener {
}
Contexts contexts = new Contexts(
plugin.getContextManager().giveApplicableContext(player, MutableContextSet.empty()),
plugin.getContextManager().getApplicableContext(player),
plugin.getConfiguration().isIncludingGlobalPerms(),
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
true,
@@ -84,7 +85,7 @@ public class BungeeListener extends AbstractListener implements Listener {
e.setHasPermission(user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission()).asBoolean());
}
@EventHandler
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerLogin(LoginEvent e) {
/* Delay the login here, as we want to cache UUID data before the player is connected to a backend bukkit server.
This means that a player will have the same UUID across the network, even if parts of the network are running in
@@ -96,32 +97,45 @@ public class BungeeListener extends AbstractListener implements Listener {
final PendingConnection c = e.getConnection();
if (!cache.isOnlineMode()) {
UUID uuid = plugin.getDatastore().getUUID(c.getName()).getUnchecked();
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()));
cache.addToCache(c.getUniqueId(), c.getUniqueId());
plugin.getDatastore().force().saveUUIDData(c.getName(), c.getUniqueId()).getUnchecked();
plugin.getStorage().force().saveUUIDData(c.getName(), c.getUniqueId()).join();
}
} else {
UUID uuid = plugin.getDatastore().getUUID(c.getName()).getUnchecked();
UUID uuid = plugin.getStorage().getUUID(c.getName()).join();
if (uuid == null) {
plugin.getApiProvider().fireEventAsync(new UserFirstLoginEvent(c.getUniqueId(), c.getName()));
}
// Online mode, no cache needed. This is just for name -> uuid lookup.
plugin.getDatastore().force().saveUUIDData(c.getName(), c.getUniqueId()).getUnchecked();
plugin.getStorage().force().saveUUIDData(c.getName(), c.getUniqueId()).join();
}
// We have to make a new user on this thread whilst the connection is being held, or we get concurrency issues as the Bukkit server
// and the BungeeCord server try to make a new user at the same time.
plugin.getDatastore().force().loadUser(cache.getUUID(c.getUniqueId()), c.getName()).getUnchecked();
plugin.getStorage().force().loadUser(cache.getUUID(c.getUniqueId()), c.getName()).join();
User user = plugin.getUserManager().get(cache.getUUID(c.getUniqueId()));
if (user == null) {
plugin.getLog().warn("Failed to load user: " + c.getName());
} else {
// Setup defaults for the user
boolean save = false;
for (Rule rule : plugin.getConfiguration().getDefaultAssignments()) {
if (rule.apply(user)) {
save = true;
}
}
// If they were given a default, persist the new assignments back to the storage.
if (save) {
plugin.getStorage().force().saveUser(user).join();
}
user.setupData(false); // Pretty nasty calculation call. Sets up the caching system so data is ready when the user joins.
}
@@ -23,7 +23,7 @@
package me.lucko.luckperms.bungee;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.SenderFactory;
import me.lucko.luckperms.common.commands.sender.SenderFactory;
import me.lucko.luckperms.common.constants.Constants;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent;
@@ -32,19 +32,10 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.UUID;
public class BungeeSenderFactory extends SenderFactory<CommandSender> {
private static BungeeSenderFactory instance = null;
private BungeeSenderFactory(LuckPermsPlugin plugin) {
public BungeeSenderFactory(LuckPermsPlugin plugin) {
super(plugin);
}
public static synchronized BungeeSenderFactory get(LuckPermsPlugin plugin) {
if (instance == null) {
instance = new BungeeSenderFactory(plugin);
}
return instance;
}
@Override
protected String getName(CommandSender sender) {
if (sender instanceof ProxiedPlayer) {
@@ -34,21 +34,23 @@ import me.lucko.luckperms.common.api.ApiProvider;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.commands.ConsecutiveExecutor;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.config.LPConfiguration;
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.data.Importer;
import me.lucko.luckperms.common.groups.GroupManager;
import me.lucko.luckperms.common.runnables.ExpireTemporaryTask;
import me.lucko.luckperms.common.runnables.UpdateTask;
import me.lucko.luckperms.common.storage.Datastore;
import me.lucko.luckperms.common.messaging.RedisMessaging;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.storage.StorageFactory;
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
import me.lucko.luckperms.common.tasks.UpdateTask;
import me.lucko.luckperms.common.tracks.TrackManager;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.users.UserManager;
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 net.md_5.bungee.api.config.ServerInfo;
@@ -56,19 +58,26 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
import java.io.File;
import java.util.*;
import java.util.HashSet;
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 Executor executor;
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private LPConfiguration configuration;
private UserManager userManager;
private GroupManager groupManager;
private TrackManager trackManager;
private Datastore datastore;
private Storage storage;
private RedisMessaging redisMessaging = null;
private UuidCache uuidCache;
private ApiProvider apiProvider;
private Logger log;
@@ -78,14 +87,48 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
private ContextManager<ProxiedPlayer> contextManager;
private CalculatorFactory calculatorFactory;
private BufferedRequest<Void> updateTaskBuffer;
private DebugHandler debugHandler;
private BungeeSenderFactory senderFactory;
@Override
public void onEnable() {
executor = r -> getProxy().getScheduler().runAsync(this, r);
log = LogFactory.wrap(getLogger());
debugHandler = new DebugHandler();
senderFactory = new BungeeSenderFactory(this);
getLog().info("Loading configuration...");
configuration = new BungeeConfig(this);
// register events
getProxy().getPluginManager().registerListener(this, new BungeeListener(this));
// initialise datastore
storage = StorageFactory.getInstance(this, "h2");
// initialise redis
if (getConfiguration().isRedisEnabled()) {
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();
}
}
// setup the update task buffer
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
@Override
protected Void perform() {
new UpdateTask(LPBungeePlugin.this).run();
return null;
}
};
// load locale
localeManager = new LocaleManager();
File locale = new File(getDataFolder(), "lang.yml");
if (locale.exists()) {
@@ -97,19 +140,15 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
}
}
// register events
getProxy().getPluginManager().registerListener(this, new BungeeListener(this));
// register commands
getLog().info("Registering commands...");
CommandManager commandManager = new CommandManager(this);
getProxy().getPluginManager().registerCommand(this, new BungeeCommand(commandManager));
getProxy().getPluginManager().registerCommand(this, new BungeeCommand(this, commandManager));
// disable the default Bungee /perms command so it gets handled by the Bukkit plugin
getProxy().getDisabledCommands().add("perms");
datastore = StorageFactory.getDatastore(this, "h2");
// load internal managers
getLog().info("Loading internal permission managers...");
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
userManager = new UserManager(this);
@@ -125,40 +164,36 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
contextManager.registerCalculator(serverCalculator);
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
final LPBungeePlugin i = this;
updateTaskBuffer = new BufferedRequest<Void>(6000L, this::doAsync) {
@Override
protected Void perform() {
doAsync(new UpdateTask(i));
return null;
}
};
// register with the LP API
getLog().info("Registering API...");
apiProvider = new ApiProvider(this);
ApiHandler.registerProvider(apiProvider);
// schedule update tasks
int mins = getConfiguration().getSyncTime();
if (mins > 0) {
getProxy().getScheduler().schedule(this, new UpdateTask(this), mins, mins, TimeUnit.MINUTES);
}
// 20 times per second (once per "tick")
getProxy().getScheduler().schedule(this, BungeeSenderFactory.get(this), 50L, 50L, TimeUnit.MILLISECONDS);
// run an update instantly.
updateTaskBuffer.requestDirectly();
// register tasks
getProxy().getScheduler().schedule(this, new ExpireTemporaryTask(this), 3L, 3L, TimeUnit.SECONDS);
getProxy().getScheduler().schedule(this, consecutiveExecutor, 1L, 1L, TimeUnit.SECONDS);
getLog().info("Registering API...");
apiProvider = new ApiProvider(this);
ApiHandler.registerProvider(apiProvider);
// Run update task to refresh any online users
getLog().info("Scheduling Update Task to refresh any online users.");
updateTaskBuffer.request();
getLog().info("Successfully loaded.");
}
@Override
public void onDisable() {
getLog().info("Closing datastore...");
datastore.shutdown();
storage.shutdown();
if (redisMessaging != null) {
getLog().info("Closing redis...");
redisMessaging.shutdown();
}
getLog().info("Unregistering API...");
ApiHandler.unregisterProvider();
@@ -179,6 +214,28 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
return getDataFolder();
}
@Override
public ProxiedPlayer getPlayer(User user) {
return getProxy().getPlayer(uuidCache.getExternalUUID(user.getUuid()));
}
@Override
public Contexts getContextForUser(User user) {
ProxiedPlayer player = getPlayer(user);
if (player == null) {
return null;
}
return new Contexts(
getContextManager().getApplicableContext(player),
getConfiguration().isIncludingGlobalPerms(),
getConfiguration().isIncludingGlobalWorldPerms(),
true,
getConfiguration().isApplyingGlobalGroups(),
getConfiguration().isApplyingGlobalWorldGroups(),
false
);
}
@Override
public int getPlayerCount() {
return getProxy().getOnlineCount();
@@ -200,16 +257,15 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
}
@Override
public List<Sender> getNotifyListeners() {
public List<Sender> getSenders() {
return getProxy().getPlayers().stream()
.map(p -> BungeeSenderFactory.get(this).wrap(p, Collections.singleton(Permission.LOG_NOTIFY)))
.filter(Permission.LOG_NOTIFY::isAuthorized)
.map(p -> getSenderFactory().wrap(p))
.collect(Collectors.toList());
}
@Override
public Sender getConsoleSender() {
return BungeeSenderFactory.get(this).wrap(getProxy().getConsole());
return getSenderFactory().wrap(getProxy().getConsole());
}
@Override
@@ -271,7 +327,17 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
@Override
public void doSync(Runnable r) {
r.run();
doAsync(r);
}
@Override
public Executor getSyncExecutor() {
return executor;
}
@Override
public Executor getAsyncExecutor() {
return executor;
}
@Override
@@ -20,18 +20,19 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.commands.migration.subcommands;
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.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.Predicate;
import me.lucko.luckperms.common.commands.Sender;
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.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import net.alpenblock.bungeeperms.*;
@@ -43,11 +44,11 @@ import java.util.Map;
*/
public class MigrationBungeePerms extends SubCommand<Object> {
public MigrationBungeePerms() {
super("bungeeperms", "Migration from BungeePerms", Permission.MIGRATION, Predicate.alwaysFalse(), null);
super("bungeeperms", "Migration from BungeePerms", Permission.MIGRATION, Predicates.alwaysFalse(), null);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) {
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List<String> args, String label) throws CommandException {
final Logger log = plugin.getLog();
BungeePerms bp = BungeePerms.getInstance();
@@ -60,10 +61,10 @@ public class MigrationBungeePerms extends SubCommand<Object> {
log.info("BungeePerms Migration: Starting group migration.");
int groupCount = 0;
for (Group g : bp.getPermissionsManager().getBackEnd().loadGroups()) {
groupCount ++;
groupCount++;
// Make a LuckPerms group for the one being migrated
plugin.getDatastore().createAndLoadGroup(g.getName().toLowerCase()).getUnchecked();
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase()).join();
me.lucko.luckperms.common.groups.Group group = plugin.getGroupManager().get(g.getName().toLowerCase());
try {
LogEntry.build()
@@ -173,7 +174,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
}
}
plugin.getDatastore().saveGroup(group);
plugin.getStorage().saveGroup(group);
}
log.info("BungeePerms Migration: Migrated " + groupCount + " groups");
@@ -187,7 +188,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
userCount++;
// Make a LuckPerms user for the one being migrated.
plugin.getDatastore().loadUser(u.getUUID(), "null").getUnchecked();
plugin.getStorage().loadUser(u.getUUID(), "null").join();
me.lucko.luckperms.common.users.User user = plugin.getUserManager().get(u.getUUID());
// Migrate global perms
@@ -288,7 +289,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
}
}
plugin.getDatastore().saveUser(user);
plugin.getStorage().saveUser(user);
plugin.getUserManager().cleanup(user);
}
+18 -3
View File
@@ -46,9 +46,6 @@ online-mode: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# If LuckPerms should print to console every time a plugin checks if a player has a permission
debug-permission-checks: false
# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in this list, the value assigned
# will be sent forward for permission calculation instead.
world-rewrite:
@@ -80,6 +77,11 @@ apply-regex: true
# If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# Define special group weights for this server.
# Default is just 0.
group-weight:
# admin: 10
@@ -113,6 +115,19 @@ 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.
#
# If enabled and configured, LuckPerms will use the Redis PubSub 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.
#
# 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.
redis:
enabled: false
address: localhost:6379
password: ''
+8 -48
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.13-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -39,6 +39,13 @@
<version>2.5.1</version>
<scope>compile</scope>
</dependency>
<!-- Jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
<scope>compile</scope>
</dependency>
<!-- SQLite -->
<dependency>
<groupId>org.xerial</groupId>
@@ -95,53 +102,6 @@
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
<!-- **************Migration Plugins************** -->
<dependency>
<groupId>org.tyrannyofheaven.bukkit</groupId>
<artifactId>zPermissions</artifactId>
<version>1.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ru.tehkode</groupId>
<artifactId>PermissionsEx</artifactId>
<version>1.23</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
<exclusion>
<groupId>net.gravitydevelopment.updater</groupId>
<artifactId>updater</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.cheesesoftware</groupId>
<artifactId>PowerfulPermsAPI</artifactId>
<version>1.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.anjocaido</groupId>
<artifactId>GroupManager</artifactId>
<version>1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.alpenblock</groupId>
<artifactId>BungeePerms</artifactId>
<version>3.0-dev-52</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.bananaco</groupId>
<artifactId>bpermissions-api</artifactId>
<version>2.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -27,64 +27,168 @@ import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.common.api.ApiProvider;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.commands.BaseCommand;
import me.lucko.luckperms.common.commands.ConsecutiveExecutor;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.config.LPConfiguration;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.contexts.ContextManager;
import me.lucko.luckperms.common.core.UuidCache;
import me.lucko.luckperms.common.data.Importer;
import me.lucko.luckperms.common.groups.GroupManager;
import me.lucko.luckperms.common.storage.Datastore;
import me.lucko.luckperms.common.messaging.RedisMessaging;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.tracks.TrackManager;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.users.UserManager;
import me.lucko.luckperms.common.utils.BufferedRequest;
import me.lucko.luckperms.common.utils.DebugHandler;
import me.lucko.luckperms.common.utils.LocaleManager;
import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.Executor;
/**
* Main internal interface for LuckPerms plugins, allowing the luckperms-common module to bind with the plugin instance.
* Main internal interface for LuckPerms plugins, providing the base for abstraction throughout the project.
*
* All plugin platforms implement this interface.
*/
public interface LuckPermsPlugin {
/*
* Access to all of the main internal manager classes
/**
* Gets the user manager instance for the platform
* @return the user manager
*/
UserManager getUserManager();
/**
* Gets the group manager instance for the platform
* @return the group manager
*/
GroupManager getGroupManager();
/**
* Gets the track manager instance for the platform
* @return the track manager
*/
TrackManager getTrackManager();
/**
* Gets the plugin's configuration
* @return the plugin config
*/
LPConfiguration getConfiguration();
Datastore getDatastore();
/**
* Gets the primary data storage instance. This is likely to be wrapped with extra layers for caching, etc.
* @return the storage handler instance
*/
Storage getStorage();
/**
* Gets the redis messaging instance if present. Could return null if redis is not enabled.
* @return the redis messaging service
*/
RedisMessaging getRedisMessaging();
/**
* Gets a wrapped logger instance for the platform.
* @return the plugin's logger
*/
Logger getLog();
/**
* Gets the UUID caching store for the platform
* @return the uuid cache
*/
UuidCache getUuidCache();
/**
* Returns the class implementing the LuckPermsAPI on this platform.
* @return the api
*/
ApiProvider getApiProvider();
/**
* Gets the importer instance
* @return the importer
*/
Importer getImporter();
/**
* Gets the consecutive command executor instance
* @return the consecutive executor
*/
ConsecutiveExecutor getConsecutiveExecutor();
/**
* Gets the instance providing locale translations for the plugin
* @return the locale manager
*/
LocaleManager getLocaleManager();
/**
* Gets the context manager.
* This object handles context accumulation for all players on the platform.
* @return the context manager
*/
ContextManager getContextManager();
/**
* Gets the class responsible for constructing PermissionCalculators on this platform.
* @return the permission calculator factory
*/
CalculatorFactory getCalculatorFactory();
/**
* Gets the verbose debug handler instance.
* @return the debug handler instance
*/
DebugHandler getDebugHandler();
/**
* Execute a runnable asynchronously
* @param r the task to run
*/
void doAsync(Runnable r);
/**
* Execute a runnable synchronously
* @param r the task to run
*/
void doSync(Runnable r);
Executor getSyncExecutor();
Executor getAsyncExecutor();
/**
* Execute a runnable asynchronously on a loop
* @param r the task to run
* @param interval the time between runs in ticks
*/
void doAsyncRepeating(Runnable r, long interval);
/**
* Gets a string of the plugin's version
* @return the version of the plugin
*/
String getVersion();
/**
* Gets the platform type this instance of LuckPerms is running on.
* @return the platform type
*/
PlatformType getType();
/**
* Gets the plugins main directory
* @return the main plugin directory
*/
File getMainDir();
/**
* Gets the plugins main data storage directory
* @return the platforms data folder
*/
File getDataFolder();
@@ -99,6 +203,21 @@ public interface LuckPermsPlugin {
return isOnline(external) ? Message.PLAYER_ONLINE : Message.PLAYER_OFFLINE;
}
/**
* Gets a player object linked to this User. The returned object must be the same type
* as the instance used in the platforms {@link ContextManager}
* @param user the user instance
* @return a player object, or null, if one couldn't be found.
*/
Object getPlayer(User user);
/**
* Gets a calculated context instance for the user using the rules of the platform.
* @param user the user instance
* @return a contexts object, or null if one couldn't be generated
*/
Contexts getContextForUser(User user);
/**
* Gets the number of users online on the platform
* @return the number of users
@@ -125,11 +244,13 @@ public interface LuckPermsPlugin {
boolean isOnline(UUID external);
/**
* Gets a list of online Senders on the platform
* @return a {@link List} of senders online on the platform
*/
List<Sender> getNotifyListeners();
List<Sender> getSenders();
/**
* Gets the console.
* @return the console sender of the instance
*/
Sender getConsoleSender();
@@ -141,9 +262,21 @@ public interface LuckPermsPlugin {
*/
Set<Contexts> getPreProcessContexts(boolean op);
default List<BaseCommand> getExtraCommands() {
return Collections.emptyList();
}
/**
* Gets a map of extra information to be shown in the info command
* @return a map of options, or null
*/
default LinkedHashMap<String, Object> getExtraInfo() {
return null;
}
/**
* Gets a set of players ignoring logging output
* @return a {@link Set} of uuids
* @return a {@link Set} of {@link UUID}s
*/
Set<UUID> getIgnoringLogs();
@@ -162,7 +295,7 @@ public interface LuckPermsPlugin {
Object getService(Class clazz);
/**
* Used as a backup for migration
* Gets the UUID of a player. Used as a backup for migration
* @param playerName the players name
* @return a uuid if found, or null if not
*/
@@ -176,27 +309,9 @@ public interface LuckPermsPlugin {
boolean isPluginLoaded(String name);
/**
* Runs an update task
* Gets the update task buffer of the platform, used for scheduling and running update tasks.
* @return the update task buffer instance
*/
BufferedRequest<Void> getUpdateTaskBuffer();
/**
* Execute a runnable asynchronously
* @param r the task to run
*/
void doAsync(Runnable r);
/**
* Execute a runnable synchronously
* @param r the task to run
*/
void doSync(Runnable r);
/**
* Execute a runnable asynchronously on a loop
* @param r the task to run
* @param interval the time between runs in ticks
*/
void doAsyncRepeating(Runnable r, long interval);
}
@@ -31,6 +31,8 @@ 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.internal.*;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.users.UserIdentifier;
import java.util.Optional;
@@ -69,7 +71,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public double getApiVersion() {
return 2.13;
return 2.15;
}
@Override
@@ -94,17 +96,28 @@ public class ApiProvider implements LuckPermsApi {
@Override
public LPConfiguration getConfiguration() {
return new me.lucko.luckperms.common.api.internal.LPConfigurationLink(plugin.getConfiguration());
return new LPConfigurationLink(plugin.getConfiguration());
}
@Override
public Storage getStorage() {
return new StorageLink(plugin, plugin.getStorage());
}
@SuppressWarnings("deprecation")
@Override
public Datastore getDatastore() {
return new me.lucko.luckperms.common.api.internal.DatastoreLink(plugin, plugin.getDatastore());
return new DatastoreLink(plugin, plugin.getStorage());
}
@Override
public Optional<MessagingService> getMessagingService() {
return Optional.ofNullable(plugin.getRedisMessaging());
}
@Override
public UuidCache getUuidCache() {
return new me.lucko.luckperms.common.api.internal.UuidCacheLink(plugin.getUuidCache());
return new UuidCacheLink(plugin.getUuidCache());
}
@Override
@@ -115,11 +128,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public User getUser(@NonNull UUID uuid) {
final me.lucko.luckperms.common.users.User user = plugin.getUserManager().get(uuid);
if (user == null) {
return null;
}
return new me.lucko.luckperms.common.api.internal.UserLink(user);
return user == null ? null : new UserLink(user);
}
@Override
@@ -130,11 +139,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public User getUser(@NonNull String name) {
final me.lucko.luckperms.common.users.User user = plugin.getUserManager().get(name);
if (user == null) {
return null;
}
return new me.lucko.luckperms.common.api.internal.UserLink(user);
return user == null ? null : new UserLink(user);
}
@Override
@@ -144,7 +149,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Set<User> getUsers() {
return plugin.getUserManager().getAll().values().stream().map(me.lucko.luckperms.common.api.internal.UserLink::new).collect(Collectors.toSet());
return plugin.getUserManager().getAll().values().stream().map(UserLink::new).collect(Collectors.toSet());
}
@Override
@@ -154,18 +159,14 @@ public class ApiProvider implements LuckPermsApi {
@Override
public void cleanupUser(@NonNull User user) {
me.lucko.luckperms.common.api.internal.Utils.checkUser(user);
plugin.getUserManager().cleanup(((me.lucko.luckperms.common.api.internal.UserLink) user).getMaster());
Utils.checkUser(user);
plugin.getUserManager().cleanup(((UserLink) user).getMaster());
}
@Override
public Group getGroup(@NonNull String name) {
final me.lucko.luckperms.common.groups.Group group = plugin.getGroupManager().get(name);
if (group == null) {
return null;
}
return new me.lucko.luckperms.common.api.internal.GroupLink(group);
return group == null ? null : new GroupLink(group);
}
@Override
@@ -175,7 +176,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Set<Group> getGroups() {
return plugin.getGroupManager().getAll().values().stream().map(me.lucko.luckperms.common.api.internal.GroupLink::new).collect(Collectors.toSet());
return plugin.getGroupManager().getAll().values().stream().map(GroupLink::new).collect(Collectors.toSet());
}
@Override
@@ -186,11 +187,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Track getTrack(@NonNull String name) {
final me.lucko.luckperms.common.tracks.Track track = plugin.getTrackManager().get(name);
if (track == null) {
return null;
}
return new me.lucko.luckperms.common.api.internal.TrackLink(track);
return track == null ? null : new TrackLink(track);
}
@Override
@@ -200,7 +197,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Set<Track> getTracks() {
return plugin.getTrackManager().getAll().values().stream().map(me.lucko.luckperms.common.api.internal.TrackLink::new).collect(Collectors.toSet());
return plugin.getTrackManager().getAll().values().stream().map(TrackLink::new).collect(Collectors.toSet());
}
@Override
@@ -210,7 +207,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Node.Builder buildNode(@NonNull String permission) throws IllegalArgumentException {
return new me.lucko.luckperms.common.core.Node.Builder(checkNode(permission));
return new NodeBuilder(checkNode(permission));
}
@SuppressWarnings("unchecked")
@@ -224,4 +221,10 @@ public class ApiProvider implements LuckPermsApi {
public void registerContextListener(ContextListener<?> contextListener) {
plugin.getContextManager().registerListener(contextListener);
}
@Override
public Optional<Contexts> getContextForUser(User user) {
Utils.checkUser(user);
return Optional.ofNullable(plugin.getContextForUser(((UserLink) user).getMaster()));
}
}
@@ -27,26 +27,29 @@ import lombok.NonNull;
import me.lucko.luckperms.api.*;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.AbstractFuture;
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.internal.Utils.*;
/**
* Provides a link between {@link Datastore} and {@link me.lucko.luckperms.common.storage.Datastore}
* Provides a link between {@link Datastore} and {@link Storage}
*
* Note that this class only provides for the old deprecated interface, see {@link StorageLink} for the new one.
*/
@SuppressWarnings({"unused", "WeakerAccess"})
@SuppressWarnings({"unused", "WeakerAccess", "deprecation"})
public class DatastoreLink implements Datastore {
private final LuckPermsPlugin plugin;
private final me.lucko.luckperms.common.storage.Datastore master;
private final Storage master;
private final Async async;
private final Sync sync;
private final Future future;
public DatastoreLink(@NonNull LuckPermsPlugin plugin, @NonNull me.lucko.luckperms.common.storage.Datastore master) {
public DatastoreLink(@NonNull LuckPermsPlugin plugin, @NonNull Storage master) {
this.plugin = plugin;
this.master = master;
this.async = new Async(master);
@@ -54,12 +57,10 @@ public class DatastoreLink implements Datastore {
this.future = new Future(master);
}
private static <T> Callback<T> checkCallback(Callback<T> c) {
// If no callback was given, just send an empty one
if (c == null) {
c = Callback.empty();
private <T> void registerCallback(CompletableFuture<T> fut, Callback<T> c) {
if (c != null) {
fut.thenAcceptAsync(Callback.convertToConsumer(c), plugin.getSyncExecutor());
}
return c;
}
@Override
@@ -89,68 +90,68 @@ public class DatastoreLink implements Datastore {
@AllArgsConstructor
public class Async implements Datastore.Async {
private final me.lucko.luckperms.common.storage.Datastore master;
private final me.lucko.luckperms.common.storage.Storage master;
@Override
public void logAction(@NonNull LogEntry entry, Callback<Boolean> callback) {
master.logAction(entry, checkCallback(callback));
registerCallback(master.force().logAction(entry), callback);
}
@Override
public void getLog(Callback<Log> callback) {
master.getLog(log -> callback.onComplete(new LogLink(log)));
public void getLog(@NonNull Callback<Log> callback) {
master.force().getLog().thenAcceptAsync(log -> callback.onComplete(new LogLink(log)), plugin.getSyncExecutor());
}
@Override
public void loadOrCreateUser(@NonNull UUID uuid, @NonNull String username, Callback<Boolean> callback) {
master.loadUser(uuid, checkUsername(username), checkCallback(callback));
registerCallback(master.force().loadUser(uuid, checkUsername(username)) , callback);
}
@Override
public void loadUser(@NonNull UUID uuid, Callback<Boolean> callback) {
master.loadUser(uuid, "null", checkCallback(callback));
registerCallback(master.force().loadUser(uuid, "null"), callback);
}
@Override
public void loadUser(@NonNull UUID uuid, @NonNull String username, Callback<Boolean> callback) {
master.loadUser(uuid, checkUsername(username), checkCallback(callback));
registerCallback(master.force().loadUser(uuid, checkUsername(username)), callback);
}
@Override
public void saveUser(@NonNull User user, Callback<Boolean> callback) {
checkUser(user);
master.saveUser(((UserLink) user).getMaster(), checkCallback(callback));
registerCallback(master.force().saveUser(((UserLink) user).getMaster()), callback);
}
@Override
public void cleanupUsers(Callback<Boolean> callback) {
master.cleanupUsers(checkCallback(callback));
registerCallback(master.force().cleanupUsers(), callback);
}
@Override
public void getUniqueUsers(Callback<Set<UUID>> callback) {
master.getUniqueUsers(checkCallback(callback));
registerCallback(master.force().getUniqueUsers(), callback);
}
@Override
public void createAndLoadGroup(@NonNull String name, Callback<Boolean> callback) {
master.createAndLoadGroup(checkName(name), checkCallback(callback));
registerCallback(master.force().createAndLoadGroup(checkName(name)), callback);
}
@Override
public void loadGroup(@NonNull String name, Callback<Boolean> callback) {
master.loadGroup(checkName(name), checkCallback(callback));
registerCallback(master.force().loadGroup(checkName(name)), callback);
}
@Override
public void loadAllGroups(Callback<Boolean> callback) {
master.loadAllGroups(checkCallback(callback));
registerCallback(master.force().loadAllGroups(), callback);
}
@Override
public void saveGroup(@NonNull Group group, Callback<Boolean> callback) {
checkGroup(group);
master.saveGroup(((GroupLink) group).getMaster(), checkCallback(callback));
registerCallback(master.force().saveGroup(((GroupLink) group).getMaster()), callback);
}
@Override
@@ -159,59 +160,59 @@ public class DatastoreLink implements Datastore {
if (group.getName().equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
master.deleteGroup(((GroupLink) group).getMaster(), checkCallback(callback));
registerCallback(master.force().deleteGroup(((GroupLink) group).getMaster()), callback);
}
@Override
public void createAndLoadTrack(@NonNull String name, Callback<Boolean> callback) {
master.createAndLoadTrack(checkName(name), checkCallback(callback));
registerCallback(master.force().createAndLoadTrack(checkName(name)), callback);
}
@Override
public void loadTrack(@NonNull String name, Callback<Boolean> callback) {
master.loadTrack(checkName(name), checkCallback(callback));
registerCallback(master.force().loadTrack(checkName(name)), callback);
}
@Override
public void loadAllTracks(Callback<Boolean> callback) {
master.loadAllTracks(checkCallback(callback));
registerCallback(master.force().loadAllTracks(), callback);
}
@Override
public void saveTrack(@NonNull Track track, Callback<Boolean> callback) {
checkTrack(track);
master.saveTrack(((TrackLink) track).getMaster(), checkCallback(callback));
registerCallback(master.force().saveTrack(((TrackLink) track).getMaster()), callback);
}
@Override
public void deleteTrack(@NonNull Track track, Callback<Boolean> callback) {
checkTrack(track);
master.deleteTrack(((TrackLink) track).getMaster(), checkCallback(callback));
registerCallback(master.force().deleteTrack(((TrackLink) track).getMaster()), callback);
}
@Override
public void saveUUIDData(@NonNull String username, @NonNull UUID uuid, Callback<Boolean> callback) {
master.saveUUIDData(checkUsername(username), uuid, checkCallback(callback));
registerCallback(master.force().saveUUIDData(checkUsername(username), uuid), callback);
}
@Override
public void getUUID(@NonNull String username, Callback<UUID> callback) {
master.getUUID(checkUsername(username), checkCallback(callback));
registerCallback(master.force().getUUID(checkUsername(username)), callback);
}
}
@AllArgsConstructor
public class Sync implements Datastore.Sync {
private final me.lucko.luckperms.common.storage.Datastore master;
private final Storage master;
@Override
public boolean logAction(@NonNull LogEntry entry) {
return master.logAction(entry).getUnchecked();
return master.force().logAction(entry).join();
}
@Override
public Log getLog() {
me.lucko.luckperms.common.data.Log log = master.getLog().getUnchecked();
me.lucko.luckperms.common.data.Log log = master.force().getLog().join();
if (log == null) {
return null;
}
@@ -220,54 +221,54 @@ public class DatastoreLink implements Datastore {
@Override
public boolean loadOrCreateUser(@NonNull UUID uuid, @NonNull String username) {
return master.loadUser(uuid, checkUsername(username)).getUnchecked();
return master.force().loadUser(uuid, checkUsername(username)).join();
}
@Override
public boolean loadUser(@NonNull UUID uuid) {
return master.loadUser(uuid, "null").getUnchecked();
return master.force().loadUser(uuid, "null").join();
}
@Override
public boolean loadUser(@NonNull UUID uuid, @NonNull String username) {
return master.loadUser(uuid, checkUsername(username)).getUnchecked();
return master.force().loadUser(uuid, checkUsername(username)).join();
}
@Override
public boolean saveUser(@NonNull User user) {
checkUser(user);
return master.saveUser(((UserLink) user).getMaster()).getUnchecked();
return master.force().saveUser(((UserLink) user).getMaster()).join();
}
@Override
public boolean cleanupUsers() {
return master.cleanupUsers().getUnchecked();
return master.force().cleanupUsers().join();
}
@Override
public Set<UUID> getUniqueUsers() {
return master.getUniqueUsers().getUnchecked();
return master.force().getUniqueUsers().join();
}
@Override
public boolean createAndLoadGroup(@NonNull String name) {
return master.createAndLoadGroup(checkName(name)).getUnchecked();
return master.force().createAndLoadGroup(checkName(name)).join();
}
@Override
public boolean loadGroup(@NonNull String name) {
return master.loadGroup(checkName(name)).getUnchecked();
return master.force().loadGroup(checkName(name)).join();
}
@Override
public boolean loadAllGroups() {
return master.loadAllGroups().getUnchecked();
return master.force().loadAllGroups().join();
}
@Override
public boolean saveGroup(@NonNull Group group) {
checkGroup(group);
return master.saveGroup(((GroupLink) group).getMaster()).getUnchecked();
return master.force().saveGroup(((GroupLink) group).getMaster()).join();
}
@Override
@@ -276,113 +277,111 @@ public class DatastoreLink implements Datastore {
if (group.getName().equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
return master.deleteGroup(((GroupLink) group).getMaster()).getUnchecked();
return master.force().deleteGroup(((GroupLink) group).getMaster()).join();
}
@Override
public boolean createAndLoadTrack(@NonNull String name) {
return master.createAndLoadTrack(checkName(name)).getUnchecked();
return master.force().createAndLoadTrack(checkName(name)).join();
}
@Override
public boolean loadTrack(@NonNull String name) {
return master.loadTrack(checkName(name)).getUnchecked();
return master.force().loadTrack(checkName(name)).join();
}
@Override
public boolean loadAllTracks() {
return master.loadAllTracks().getUnchecked();
return master.force().loadAllTracks().join();
}
@Override
public boolean saveTrack(@NonNull Track track) {
checkTrack(track);
return master.saveTrack(((TrackLink) track).getMaster()).getUnchecked();
return master.force().saveTrack(((TrackLink) track).getMaster()).join();
}
@Override
public boolean deleteTrack(@NonNull Track track) {
checkTrack(track);
return master.deleteTrack(((TrackLink) track).getMaster()).getUnchecked();
return master.force().deleteTrack(((TrackLink) track).getMaster()).join();
}
@Override
public boolean saveUUIDData(@NonNull String username, @NonNull UUID uuid) {
return master.saveUUIDData(checkUsername(username), uuid).getUnchecked();
return master.force().saveUUIDData(checkUsername(username), uuid).join();
}
@Override
public UUID getUUID(@NonNull String username) {
return master.getUUID(checkUsername(username)).getUnchecked();
return master.force().getUUID(checkUsername(username)).join();
}
}
@AllArgsConstructor
public class Future implements Datastore.Future {
private final me.lucko.luckperms.common.storage.Datastore master;
private final Storage master;
@Override
public java.util.concurrent.Future<Boolean> logAction(@NonNull LogEntry entry) {
return master.logAction(entry);
return master.force().logAction(entry);
}
@Override
public java.util.concurrent.Future<Log> getLog() {
AbstractFuture<Log> fut = new AbstractFuture<>();
master.getLog(log -> fut.complete(new LogLink(log)));
return fut;
return master.force().getLog().thenApply(log -> log == null ? null : new LogLink(log));
}
@Override
public java.util.concurrent.Future<Boolean> loadOrCreateUser(@NonNull UUID uuid, @NonNull String username) {
return master.loadUser(uuid, checkUsername(username));
return master.force().loadUser(uuid, checkUsername(username));
}
@Override
public java.util.concurrent.Future<Boolean> loadUser(@NonNull UUID uuid) {
return master.loadUser(uuid, "null");
return master.force().loadUser(uuid, "null");
}
@Override
public java.util.concurrent.Future<Boolean> loadUser(@NonNull UUID uuid, @NonNull String username) {
return master.loadUser(uuid, checkUsername(username));
return master.force().loadUser(uuid, checkUsername(username));
}
@Override
public java.util.concurrent.Future<Boolean> saveUser(@NonNull User user) {
checkUser(user);
return master.saveUser(((UserLink) user).getMaster());
return master.force().saveUser(((UserLink) user).getMaster());
}
@Override
public java.util.concurrent.Future<Boolean> cleanupUsers() {
return master.cleanupUsers();
return master.force().cleanupUsers();
}
@Override
public java.util.concurrent.Future<Set<UUID>> getUniqueUsers() {
return master.getUniqueUsers();
return master.force().getUniqueUsers();
}
@Override
public java.util.concurrent.Future<Boolean> createAndLoadGroup(@NonNull String name) {
return master.createAndLoadGroup(checkName(name));
return master.force().createAndLoadGroup(checkName(name));
}
@Override
public java.util.concurrent.Future<Boolean> loadGroup(@NonNull String name) {
return master.loadGroup(checkName(name));
return master.force().loadGroup(checkName(name));
}
@Override
public java.util.concurrent.Future<Boolean> loadAllGroups() {
return master.loadAllGroups();
return master.force().loadAllGroups();
}
@Override
public java.util.concurrent.Future<Boolean> saveGroup(@NonNull Group group) {
checkGroup(group);
return master.saveGroup(((GroupLink) group).getMaster());
return master.force().saveGroup(((GroupLink) group).getMaster());
}
@Override
@@ -391,44 +390,44 @@ public class DatastoreLink implements Datastore {
if (group.getName().equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
return master.deleteGroup(((GroupLink) group).getMaster());
return master.force().deleteGroup(((GroupLink) group).getMaster());
}
@Override
public java.util.concurrent.Future<Boolean> createAndLoadTrack(@NonNull String name) {
return master.createAndLoadTrack(checkName(name));
return master.force().createAndLoadTrack(checkName(name));
}
@Override
public java.util.concurrent.Future<Boolean> loadTrack(@NonNull String name) {
return master.loadTrack(checkName(name));
return master.force().loadTrack(checkName(name));
}
@Override
public java.util.concurrent.Future<Boolean> loadAllTracks() {
return master.loadAllTracks();
return master.force().loadAllTracks();
}
@Override
public java.util.concurrent.Future<Boolean> saveTrack(@NonNull Track track) {
checkTrack(track);
return master.saveTrack(((TrackLink) track).getMaster());
return master.force().saveTrack(((TrackLink) track).getMaster());
}
@Override
public java.util.concurrent.Future<Boolean> deleteTrack(@NonNull Track track) {
checkTrack(track);
return master.deleteTrack(((TrackLink) track).getMaster());
return master.force().deleteTrack(((TrackLink) track).getMaster());
}
@Override
public java.util.concurrent.Future<Boolean> saveUUIDData(@NonNull String username, @NonNull UUID uuid) {
return master.saveUUIDData(checkUsername(username), uuid);
return master.force().saveUUIDData(checkUsername(username), uuid);
}
@Override
public java.util.concurrent.Future<UUID> getUUID(@NonNull String username) {
return master.getUUID(checkUsername(username));
return master.force().getUUID(checkUsername(username));
}
}
@@ -103,7 +103,7 @@ public class LPConfigurationLink implements LPConfiguration {
@Override
public boolean getDebugPermissionChecks() {
return master.isDebugPermissionChecks();
return false;
}
@Override
@@ -26,6 +26,7 @@ import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.api.*;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
@@ -40,8 +41,6 @@ import static me.lucko.luckperms.common.core.PermissionHolder.exportToLegacy;
@SuppressWarnings("unused")
@AllArgsConstructor
public class PermissionHolderLink implements PermissionHolder {
@NonNull
private final me.lucko.luckperms.common.core.PermissionHolder master;
@Override
@@ -66,17 +65,17 @@ public class PermissionHolderLink implements PermissionHolder {
@Override
public Set<Node> getAllNodes() {
return Collections.unmodifiableSet(master.getAllNodes(null, Contexts.allowAll()));
return Collections.unmodifiableSet(master.getAllNodes(null, ExtractedContexts.generate(Contexts.allowAll())));
}
@Override
public SortedSet<LocalizedNode> getAllNodes(@NonNull Contexts contexts) {
return master.getAllNodes(null, contexts);
return master.getAllNodes(null, ExtractedContexts.generate(contexts));
}
@Override
public Set<LocalizedNode> getAllNodesFiltered(@NonNull Contexts contexts) {
return master.getAllNodesFiltered(contexts);
return master.getAllNodesFiltered(ExtractedContexts.generate(contexts));
}
@Override
@@ -0,0 +1,162 @@
/*
* 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.internal;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.api.*;
import me.lucko.luckperms.common.LuckPermsPlugin;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import static me.lucko.luckperms.common.api.internal.Utils.*;
/**
* Provides a link between {@link Storage} and {@link me.lucko.luckperms.common.storage.Storage}
*/
@AllArgsConstructor
public class StorageLink implements Storage {
private final LuckPermsPlugin plugin;
private final me.lucko.luckperms.common.storage.Storage master;
@Override
public String getName() {
return master.getName();
}
@Override
public boolean isAcceptingLogins() {
return master.isAcceptingLogins();
}
@Override
public Executor getSyncExecutor() {
return plugin.getSyncExecutor();
}
@Override
public Executor getAsyncExecutor() {
return plugin.getAsyncExecutor();
}
@Override
public CompletableFuture<Boolean> logAction(@NonNull LogEntry entry) {
return master.force().logAction(entry);
}
@Override
public CompletableFuture<Log> getLog() {
return master.force().getLog().thenApply(log -> log == null ? null : new LogLink(log));
}
@Override
public CompletableFuture<Boolean> loadUser(UUID uuid, String username) {
return master.force().loadUser(uuid, checkUsername(username));
}
@Override
public CompletableFuture<Boolean> saveUser(User user) {
checkUser(user);
return master.force().saveUser(((UserLink) user).getMaster());
}
@Override
public CompletableFuture<Boolean> cleanupUsers() {
return master.force().cleanupUsers();
}
@Override
public CompletableFuture<Set<UUID>> getUniqueUsers() {
return master.force().getUniqueUsers();
}
@Override
public CompletableFuture<Boolean> createAndLoadGroup(String name) {
return master.force().createAndLoadGroup(checkName(name));
}
@Override
public CompletableFuture<Boolean> loadGroup(String name) {
return master.force().loadGroup(checkName(name));
}
@Override
public CompletableFuture<Boolean> loadAllGroups() {
return master.force().loadAllGroups();
}
@Override
public CompletableFuture<Boolean> saveGroup(Group group) {
checkGroup(group);
return master.force().saveGroup(((GroupLink) group).getMaster());
}
@Override
public CompletableFuture<Boolean> deleteGroup(Group group) {
checkGroup(group);
if (group.getName().equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
return master.force().deleteGroup(((GroupLink) group).getMaster());
}
@Override
public CompletableFuture<Boolean> createAndLoadTrack(String name) {
return master.force().createAndLoadTrack(checkName(name));
}
@Override
public CompletableFuture<Boolean> loadTrack(String name) {
return master.force().loadTrack(checkName(name));
}
@Override
public CompletableFuture<Boolean> loadAllTracks() {
return master.force().loadAllTracks();
}
@Override
public CompletableFuture<Boolean> saveTrack(Track track) {
checkTrack(track);
return master.force().saveTrack(((TrackLink) track).getMaster());
}
@Override
public CompletableFuture<Boolean> deleteTrack(Track track) {
checkTrack(track);
return master.force().deleteTrack(((TrackLink) track).getMaster());
}
@Override
public CompletableFuture<Boolean> saveUUIDData(String username, UUID uuid) {
return master.force().saveUUIDData(checkUsername(username), uuid);
}
@Override
public CompletableFuture<UUID> getUUID(String username) {
return master.force().getUUID(checkUsername(username));
}
}
@@ -22,6 +22,7 @@
package me.lucko.luckperms.common.api.internal;
import com.google.common.base.Preconditions;
import lombok.experimental.UtilityClass;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.Track;
@@ -32,57 +33,51 @@ import me.lucko.luckperms.common.utils.ArgumentChecker;
public class Utils {
public static void checkUser(User user) {
if (!(user instanceof UserLink)) {
throw new IllegalStateException("User instance cannot be handled by this implementation.");
}
Preconditions.checkState(user instanceof UserLink, "User instance cannot be handled by this implementation.");
}
public static void checkGroup(Group group) {
if (!(group instanceof GroupLink)) {
throw new IllegalStateException("Group instance cannot be handled by this implementation.");
}
Preconditions.checkState(group instanceof GroupLink, "Group instance cannot be handled by this implementation.");
}
public static void checkTrack(Track track) {
if (!(track instanceof TrackLink)) {
throw new IllegalStateException("Track instance cannot be handled by this implementation.");
}
Preconditions.checkState(track instanceof TrackLink, "Track instance cannot be handled by this implementation.");
}
public static String checkUsername(String s) {
if (ArgumentChecker.checkUsername(s)) {
throw new IllegalArgumentException("Invalid username entry '" + s + "'. Usernames must be less than 16 chars" +
" and only contain 'a-z A-Z 1-9 _'.");
}
Preconditions.checkArgument(
!ArgumentChecker.checkUsername(s),
"Invalid username entry '" + s + "'. Usernames must be less than 16 chars and only contain 'a-z A-Z 1-9 _'."
);
return s;
}
public static String checkName(String s) {
if (ArgumentChecker.checkName(s)) {
throw new IllegalArgumentException("Invalid name entry '" + s + "'. Names must be less than 37 chars" +
" and only contain 'a-z A-Z 1-9'.");
}
Preconditions.checkArgument(
!ArgumentChecker.checkName(s),
"Invalid name entry '" + s + "'. Names must be less than 37 chars and only contain 'a-z A-Z 1-9'."
);
return s.toLowerCase();
}
public static String checkServer(String s) {
if (ArgumentChecker.checkServer(s)) {
throw new IllegalArgumentException("Invalid server entry '" + s + "'. Server names can only contain alphanumeric characters.");
}
Preconditions.checkArgument(
!ArgumentChecker.checkServer(s),
"Invalid server entry '" + s + "'. Server names can only contain alphanumeric characters."
);
return s;
}
public static String checkNode(String s) {
if (ArgumentChecker.checkNode(s)) {
throw new IllegalArgumentException("Invalid node entry '" + s + "'. Nodes cannot contain '/' or '$' characters.");
}
Preconditions.checkArgument(
!ArgumentChecker.checkNode(s),
"Invalid node entry '" + s + "'. Nodes cannot contain '/' or '$' characters."
);
return s;
}
public static long checkTime(long l) {
if (ArgumentChecker.checkTime(l)) {
throw new IllegalArgumentException("Unix time '" + l + "' is invalid, as it has already passed.");
}
Preconditions.checkArgument(!ArgumentChecker.checkTime(l), "Unix time '" + l + "' is invalid, as it has already passed.");
return l;
}
@@ -23,6 +23,7 @@
package me.lucko.luckperms.common.api.internal;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.api.UuidCache;
import java.util.UUID;
@@ -35,12 +36,12 @@ public class UuidCacheLink implements UuidCache {
private final me.lucko.luckperms.common.core.UuidCache master;
@Override
public UUID getUUID(UUID external) {
public UUID getUUID(@NonNull UUID external) {
return master.getUUID(external);
}
@Override
public UUID getExternalUUID(UUID internal) {
public UUID getExternalUUID(@NonNull UUID internal) {
return master.getExternalUUID(internal);
}
}
@@ -24,143 +24,67 @@ package me.lucko.luckperms.common.caching;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
import lombok.Getter;
import lombok.NoArgsConstructor;
import me.lucko.luckperms.api.caching.MetaData;
import me.lucko.luckperms.api.context.MutableContextSet;
import java.util.*;
import java.util.Map;
import java.util.SortedMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Holds a user's cached meta for a given context
*/
@RequiredArgsConstructor
@NoArgsConstructor
public class MetaCache implements MetaData {
private final Contexts contexts;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final SortedMap<Integer, String> prefixes = new TreeMap<>(Comparator.reverseOrder());
private final SortedMap<Integer, String> suffixes = new TreeMap<>(Comparator.reverseOrder());
@Getter
private Map<String, String> meta = ImmutableMap.of();
private final Map<String, String> meta = new HashMap<>();
@Getter
private SortedMap<Integer, String> prefixes = ImmutableSortedMap.of();
public void loadMeta(SortedSet<LocalizedNode> nodes) {
invalidateCache();
@Getter
private SortedMap<Integer, String> suffixes = ImmutableSortedMap.of();
MutableContextSet contexts = MutableContextSet.fromSet(this.contexts.getContexts());
String server = contexts.getValues("server").stream().findAny().orElse(null);
String world = contexts.getValues("world").stream().findAny().orElse(null);
contexts.removeAll("server");
contexts.removeAll("world");
for (LocalizedNode ln : nodes) {
Node n = ln.getNode();
if (!n.getValue()) {
continue;
}
if (!n.isMeta() && !n.isPrefix() && n.isSuffix()) {
continue;
}
if (!n.shouldApplyOnServer(server, this.contexts.isIncludeGlobal(), false)) {
continue;
}
if (!n.shouldApplyOnWorld(world, this.contexts.isIncludeGlobalWorld(), false)) {
continue;
}
if (!n.shouldApplyWithContext(contexts, false)) {
continue;
}
if (n.isPrefix()) {
Map.Entry<Integer, String> value = n.getPrefix();
synchronized (this.prefixes) {
if (!this.prefixes.containsKey(value.getKey())) {
this.prefixes.put(value.getKey(), value.getValue());
}
}
continue;
}
if (n.isSuffix()) {
Map.Entry<Integer, String> value = n.getSuffix();
synchronized (this.suffixes) {
if (!this.suffixes.containsKey(value.getKey())) {
this.suffixes.put(value.getKey(), value.getValue());
}
}
continue;
}
if (n.isMeta()) {
Map.Entry<String, String> meta = n.getMeta();
synchronized (this.meta) {
if (!this.meta.containsKey(meta.getKey())) {
this.meta.put(meta.getKey(), meta.getValue());
}
}
this.meta.put(meta.getKey(), meta.getValue());
}
}
}
private void invalidateCache() {
synchronized (meta) {
meta.clear();
}
synchronized (prefixes) {
prefixes.clear();
}
synchronized (suffixes) {
suffixes.clear();
}
}
@Override
public Map<String, String> getMeta() {
synchronized (meta) {
return ImmutableMap.copyOf(meta);
}
}
@Override
public SortedMap<Integer, String> getPrefixes() {
synchronized (prefixes) {
return ImmutableSortedMap.copyOfSorted(prefixes);
}
}
@Override
public SortedMap<Integer, String> getSuffixes() {
synchronized (suffixes) {
return ImmutableSortedMap.copyOfSorted(suffixes);
public void loadMeta(MetaHolder meta) {
lock.writeLock().lock();
try {
this.meta = ImmutableMap.copyOf(meta.getMeta());
this.prefixes = ImmutableSortedMap.copyOfSorted(meta.getPrefixes());
this.suffixes = ImmutableSortedMap.copyOfSorted(meta.getSuffixes());
} finally {
lock.writeLock().unlock();
}
}
@Override
public String getPrefix() {
synchronized (prefixes) {
lock.readLock().lock();
try {
if (prefixes.isEmpty()) {
return null;
}
return prefixes.get(prefixes.firstKey());
} finally {
lock.readLock().unlock();
}
}
@Override
public String getSuffix() {
synchronized (suffixes) {
lock.readLock().lock();
try {
if (suffixes.isEmpty()) {
return null;
}
return suffixes.get(suffixes.firstKey());
} finally {
lock.readLock().unlock();
}
}
@@ -0,0 +1,65 @@
/*
* 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.caching;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.api.Node;
import java.util.*;
/**
* Holds temporary mutable meta whilst this object is passed up the inheritance tree to accumulate meta from parents
*/
@Getter
@ToString
public class MetaHolder {
private final Map<String, String> meta = new HashMap<>();
private final SortedMap<Integer, String> prefixes = new TreeMap<>(Comparator.reverseOrder());
private final SortedMap<Integer, String> suffixes = new TreeMap<>(Comparator.reverseOrder());
public void accumulateNode(Node n) {
if (n.isMeta()) {
Map.Entry<String, String> entry = n.getMeta();
if (!meta.containsKey(entry.getKey())) {
meta.put(entry.getKey(), entry.getValue());
}
}
if (n.isPrefix()) {
Map.Entry<Integer, String> value = n.getPrefix();
if (!prefixes.containsKey(value.getKey())) {
prefixes.put(value.getKey(), value.getValue());
}
}
if (n.isSuffix()) {
Map.Entry<Integer, String> value = n.getSuffix();
if (!suffixes.containsKey(value.getKey())) {
suffixes.put(value.getKey(), value.getValue());
}
}
}
}
@@ -53,7 +53,8 @@ public class PermissionCache implements PermissionData {
public PermissionCache(Contexts contexts, User user, CalculatorFactory calculatorFactory) {
permissions = new ConcurrentHashMap<>();
calculator = calculatorFactory.build(contexts, user, permissions);
calculator = calculatorFactory.build(contexts, user);
calculator.updateBacking(permissions); // Initial setup.
}
@Override
@@ -64,6 +65,7 @@ public class PermissionCache implements PermissionData {
public void setPermissions(Map<String, Boolean> permissions) {
this.permissions.clear();
this.permissions.putAll(permissions);
calculator.updateBacking(this.permissions);
invalidateCache();
}
@@ -36,6 +36,7 @@ import me.lucko.luckperms.api.caching.PermissionData;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import java.util.Set;
@@ -78,7 +79,7 @@ public class UserCache implements UserData {
@Override
public ListenableFuture<MetaCache> reload(Contexts contexts, MetaCache oldData) {
oldData.loadMeta(user.getAllNodes(null, contexts));
oldData.loadMeta(user.accumulateMeta(null, null, ExtractedContexts.generate(contexts)));
return Futures.immediateFuture(oldData);
}
});
@@ -102,8 +103,8 @@ public class UserCache implements UserData {
@Override
public MetaCache calculateMeta(@NonNull Contexts contexts) {
MetaCache data = new MetaCache(contexts);
data.loadMeta(user.getAllNodes(null, contexts));
MetaCache data = new MetaCache();
data.loadMeta(user.accumulateMeta(null, null, ExtractedContexts.generate(contexts)));
return data;
}
@@ -25,13 +25,11 @@ package me.lucko.luckperms.common.calculators;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.common.users.User;
import java.util.Map;
/**
* Creates a calculator instance given a set of contexts
*/
public interface CalculatorFactory {
PermissionCalculator build(Contexts contexts, User user, Map<String, Boolean> map);
PermissionCalculator build(Contexts contexts, User user);
}
@@ -30,6 +30,7 @@ import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.LuckPermsPlugin;
import java.util.List;
import java.util.Map;
/**
* Calculates and caches permissions
@@ -38,7 +39,6 @@ import java.util.List;
public class PermissionCalculator {
private final LuckPermsPlugin plugin;
private final String objectName;
private final boolean debug;
private final List<PermissionProcessor> processors;
private final LoadingCache<String, Tristate> cache = CacheBuilder.newBuilder()
@@ -56,11 +56,7 @@ public class PermissionCalculator {
public Tristate getPermissionValue(String permission) {
permission = permission.toLowerCase();
Tristate t = cache.getUnchecked(permission);
if (debug) {
plugin.getLog().info("Checking if " + objectName + " has permission: " + permission + " - (" + t.toString() + ")");
}
plugin.getDebugHandler().printOutput(objectName, permission, t);
return t;
}
@@ -76,4 +72,10 @@ public class PermissionCalculator {
return Tristate.UNDEFINED;
}
public synchronized void updateBacking(Map<String, Boolean> map) {
for (PermissionProcessor processor : processors) {
processor.updateBacking(map);
}
}
}
@@ -24,8 +24,11 @@ package me.lucko.luckperms.common.calculators;
import me.lucko.luckperms.api.Tristate;
import java.util.Map;
public interface PermissionProcessor {
Tristate hasPermission(String permission);
void updateBacking(Map<String, Boolean> map);
}
@@ -20,23 +20,26 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.calculators;
package me.lucko.luckperms.common.calculators.processors;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import java.util.Map;
@AllArgsConstructor
public class MapProcessor implements PermissionProcessor {
@Getter
private final Map<String, Boolean> map;
private Map<String, Boolean> map = null;
@Override
public Tristate hasPermission(String permission) {
Boolean b = map.get(permission);
return b == null ? Tristate.UNDEFINED : Tristate.fromBoolean(b);
}
@Override
public void updateBacking(Map<String, Boolean> map) {
if (this.map == null) {
this.map = map;
}
}
}
@@ -20,37 +20,44 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.calculators;
package me.lucko.luckperms.common.calculators.processors;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import me.lucko.luckperms.common.constants.Patterns;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
@AllArgsConstructor
public class RegexProcessor implements PermissionProcessor {
@Getter
private final Map<String, Boolean> map;
private Map<String, Boolean> regexPermissions = new ConcurrentHashMap<>();
@Override
public Tristate hasPermission(String permission) {
for (Map.Entry<String, Boolean> e : map.entrySet()) {
if (e.getKey().toLowerCase().startsWith("r=")) {
Pattern p = Patterns.compile(e.getKey().substring(2));
if (p == null) {
continue;
}
for (Map.Entry<String, Boolean> e : regexPermissions.entrySet()) {
Pattern p = Patterns.compile(e.getKey());
if (p == null) {
continue;
}
if (p.matcher(permission).matches()) {
return Tristate.fromBoolean(e.getValue());
}
if (p.matcher(permission).matches()) {
return Tristate.fromBoolean(e.getValue());
}
}
return Tristate.UNDEFINED;
}
@Override
public void updateBacking(Map<String, Boolean> map) {
regexPermissions.clear();
for (Map.Entry<String, Boolean> e : map.entrySet()) {
if (!e.getKey().startsWith("r=") && !e.getKey().startsWith("R=")) {
continue;
}
regexPermissions.put(e.getKey().substring(2), e.getValue());
}
}
}
@@ -20,19 +20,15 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.calculators;
package me.lucko.luckperms.common.calculators.processors;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import java.util.Map;
@AllArgsConstructor
public class WildcardProcessor implements PermissionProcessor {
@Getter
private final Map<String, Boolean> map;
private Map<String, Boolean> map = null;
@Override
public Tristate hasPermission(String permission) {
@@ -65,4 +61,11 @@ public class WildcardProcessor implements PermissionProcessor {
return Tristate.UNDEFINED;
}
@Override
public void updateBacking(Map<String, Boolean> map) {
if (this.map == null) {
this.map = map;
}
}
}
@@ -43,11 +43,7 @@ public class Arg {
private final String description;
public String asPrettyString() {
if (required) {
return "&8<&7" + name + "&8>";
} else {
return "&8[&7" + name + "&8]";
}
return required ? "&8<&7" + name + "&8>" : "&8[&7" + name + "&8]";
}
}
@@ -22,20 +22,17 @@
package me.lucko.luckperms.common.commands;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.constants.Permission;
import java.util.UUID;
import java.util.List;
import java.util.function.Predicate;
/**
* Wrapper interface to represent a CommandSender/CommandSource within the luckperms-common command implementations.
*/
public interface Sender {
public abstract class BaseCommand<T, S> extends Command<T, S> {
LuckPermsPlugin getPlatform();
String getName();
UUID getUuid();
void sendMessage(String s);
boolean hasPermission(Permission permission);
public BaseCommand(String name, String description, Permission permission, Predicate<Integer> argumentCheck, List<Arg> args, List<Command<S, ?>> children) {
super(name, description, permission, argumentCheck, args, children);
}
public abstract String getUsage();
}
@@ -0,0 +1,98 @@
/*
* 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.commands;
import com.google.common.collect.ImmutableList;
import lombok.Getter;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.constants.Permission;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
public abstract class Command<T, S> {
@Getter
private final String name;
@Getter
private final String description;
// Could be null
private final Permission permission;
@Getter
private final Predicate<Integer> argumentCheck;
// Could be null
private final List<Arg> args;
// Could be null
private final List<Command<S, ?>> children;
public Command(String name, String description, Permission permission, Predicate<Integer> argumentCheck, List<Arg> args, List<Command<S, ?>> children) {
this.name = name;
this.description = description;
this.permission = permission;
this.argumentCheck = argumentCheck;
this.args = args == null ? null : ImmutableList.copyOf(args);
this.children = children == null ? null : ImmutableList.copyOf(children);
}
public Command(String name, String description, Permission permission, Predicate<Integer> argumentCheck, List<Arg> args) {
this(name, description, permission, argumentCheck, args, null);
}
public Command(String name, String description, Predicate<Integer> argumentCheck) {
this(name, description, null, argumentCheck, null, null);
}
public abstract CommandResult execute(LuckPermsPlugin plugin, Sender sender, T t, List<String> args, String label) throws CommandException;
public List<String> tabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
return Collections.emptyList();
}
public abstract void sendUsage(Sender sender, String label);
public abstract void sendDetailedUsage(Sender sender, String label);
public boolean isAuthorized(Sender sender) {
return permission == null || permission.isAuthorized(sender);
}
public Optional<Permission> getPermission() {
return Optional.ofNullable(permission);
}
public Optional<List<Arg>> getArgs() {
return Optional.ofNullable(args);
}
public Optional<List<Command<S, ?>>> getChildren() {
return Optional.ofNullable(children);
}
}
@@ -20,16 +20,11 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.utils;
package me.lucko.luckperms.common.commands;
import com.google.common.util.concurrent.Futures;
import java.util.concurrent.Future;
public interface LPFuture<T> extends Future<T> {
default T getUnchecked() {
return Futures.getUnchecked(this);
}
/**
* Exception to be thrown if there is an error processing a command
*/
public class CommandException extends Exception {
}
@@ -23,9 +23,7 @@
package me.lucko.luckperms.common.commands;
import com.google.common.collect.ImmutableList;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.group.CreateGroup;
import me.lucko.luckperms.common.commands.group.DeleteGroup;
@@ -34,46 +32,58 @@ import me.lucko.luckperms.common.commands.group.ListGroups;
import me.lucko.luckperms.common.commands.log.LogMainCommand;
import me.lucko.luckperms.common.commands.migration.MigrationMainCommand;
import me.lucko.luckperms.common.commands.misc.*;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.track.CreateTrack;
import me.lucko.luckperms.common.commands.track.DeleteTrack;
import me.lucko.luckperms.common.commands.track.ListTracks;
import me.lucko.luckperms.common.commands.track.TrackMainCommand;
import me.lucko.luckperms.common.commands.user.UserMainCommand;
import me.lucko.luckperms.common.commands.usersbulkedit.UsersBulkEditMainCommand;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Message;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@AllArgsConstructor
public class CommandManager {
@Getter
private final LuckPermsPlugin plugin;
@Getter
private final List<MainCommand> mainCommands = ImmutableList.<MainCommand>builder()
.add(new UserMainCommand())
.add(new GroupMainCommand())
.add(new TrackMainCommand())
.add(new LogMainCommand())
.add(new SyncCommand())
.add(new InfoCommand())
.add(new DebugCommand())
.add(new ImportCommand())
.add(new ExportCommand())
.add(new QueueCommand())
.add(new MigrationMainCommand())
.add(new UsersBulkEditMainCommand())
.add(new CreateGroup())
.add(new DeleteGroup())
.add(new ListGroups())
.add(new CreateTrack())
.add(new DeleteTrack())
.add(new ListTracks())
.build();
private final List<BaseCommand> mainCommands;
public CommandManager(LuckPermsPlugin plugin) {
this.plugin = plugin;
ImmutableList.Builder<BaseCommand> l = ImmutableList.builder();
l.add(new UserMainCommand())
.add(new GroupMainCommand())
.add(new TrackMainCommand())
.addAll(plugin.getExtraCommands())
.add(new LogMainCommand())
.add(new SyncCommand())
.add(new NetworkSyncCommand())
.add(new InfoCommand())
.add(new VerboseCommand())
.add(new ImportCommand())
.add(new ExportCommand())
.add(new QueueCommand())
.add(new MigrationMainCommand())
.add(new UsersBulkEditMainCommand())
.add(new CreateGroup())
.add(new DeleteGroup())
.add(new ListGroups())
.add(new CreateTrack())
.add(new DeleteTrack())
.add(new ListTracks());
mainCommands = l.build();
}
/**
* Generic on command method to be called from the command executor object of the platform
@@ -83,10 +93,12 @@ public class CommandManager {
* @param args the arguments provided
* @param result the callback to be called when the command has fully executed
*/
public void onCommand(Sender sender, String label, List<String> args, Callback<CommandResult> result) {
public void onCommand(Sender sender, String label, List<String> args, Consumer<CommandResult> result) {
plugin.doAsync(() -> {
CommandResult r = onCommand(sender, label, args);
plugin.doSync(() -> result.onComplete(r));
if (result != null) {
plugin.doSync(() -> result.accept(r));
}
});
}
@@ -97,51 +109,93 @@ public class CommandManager {
* @param args the arguments provided
* @return if the command was successful
*/
@SuppressWarnings("unchecked")
public CommandResult onCommand(Sender sender, String label, List<String> args) {
// Handle no arguments
if (args.size() == 0) {
sendCommandUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
Optional<MainCommand> o = mainCommands.stream()
// Look for the main command.
Optional<BaseCommand> o = mainCommands.stream()
.filter(m -> m.getName().equalsIgnoreCase(args.get(0)))
.limit(1)
.findAny();
// Main command not found
if (!o.isPresent()) {
sendCommandUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
final MainCommand main = o.get();
// Check the Sender has permission to use the main command.
final Command main = o.get();
if (!main.isAuthorized(sender)) {
sendCommandUsage(sender, label);
return CommandResult.NO_PERMISSION;
}
if (main.getRequiredArgsLength() == 0) {
try {
return main.execute(plugin, sender, null, label);
} catch (Exception e) {
e.printStackTrace();
return CommandResult.FAILURE;
}
}
List<String> arguments = new ArrayList<>(args);
handleRewrites(arguments);
arguments.remove(0); // remove the main command arg.
if (args.size() == 1) {
// Check the correct number of args were given for the main command
if (main.getArgumentCheck().test(arguments.size())) {
main.sendUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
List<String> arguments = new ArrayList<>(args);
handleRewrites(arguments);
// Try to execute the command.
CommandResult result;
try {
return main.execute(plugin, sender, arguments.subList(1, arguments.size()), label);
result = main.execute(plugin, sender, null, arguments, label);
} catch (CommandException e) {
result = handleException(e, sender, label, main);
} catch (Exception e) {
e.printStackTrace();
return CommandResult.FAILURE;
result = CommandResult.FAILURE;
}
return result;
}
public static CommandResult handleException(CommandException e, Sender sender, String label, Command command) {
if (e instanceof ArgumentUtils.ArgumentException) {
if (e instanceof ArgumentUtils.DetailedUsageException) {
command.sendDetailedUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
if (e instanceof ArgumentUtils.UseInheritException) {
Message.USE_INHERIT_COMMAND.send(sender);
return CommandResult.INVALID_ARGS;
}
if (e instanceof ArgumentUtils.InvalidServerException) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (e instanceof ArgumentUtils.PastDateException) {
Message.PAST_DATE_ERROR.send(sender);
return CommandResult.INVALID_ARGS;
}
if (e instanceof ArgumentUtils.InvalidDateException) {
Message.ILLEGAL_DATE_ERROR.send(sender, ((ArgumentUtils.InvalidDateException) e).getInvalidDate());
return CommandResult.INVALID_ARGS;
}
if (e instanceof ArgumentUtils.InvalidPriorityException) {
Message.META_INVALID_PRIORITY.send(sender, ((ArgumentUtils.InvalidPriorityException) e).getInvalidPriority());
return CommandResult.INVALID_ARGS;
}
}
// Not something we can catch.
e.printStackTrace();
return CommandResult.FAILURE;
}
/**
@@ -152,24 +206,29 @@ public class CommandManager {
*/
@SuppressWarnings("unchecked")
public List<String> onTabComplete(Sender sender, List<String> args) {
final List<MainCommand> mains = mainCommands.stream()
final List<Command> mains = mainCommands.stream()
.filter(m -> m.isAuthorized(sender))
.collect(Collectors.toList());
// Not yet past the point of entering a main command
if (args.size() <= 1) {
// Nothing yet entered
if (args.isEmpty() || args.get(0).equalsIgnoreCase("")) {
return mains.stream()
.map(m -> m.getName().toLowerCase())
.collect(Collectors.toList());
}
// Started typing a main command
return mains.stream()
.map(m -> m.getName().toLowerCase())
.filter(s -> s.startsWith(args.get(0).toLowerCase()))
.collect(Collectors.toList());
}
Optional<MainCommand> o = mains.stream()
// Find a main command matching the first arg
Optional<Command> o = mains.stream()
.filter(m -> m.getName().equalsIgnoreCase(args.get(0)))
.limit(1)
.findAny();
@@ -178,7 +237,8 @@ public class CommandManager {
return Collections.emptyList();
}
return o.get().onTabComplete(sender, args.subList(1, args.size()), plugin);
// Pass the processing onto the main command
return o.get().tabComplete(plugin, sender, args.subList(1, args.size()));
}
private void sendCommandUsage(Sender sender, String label) {
@@ -194,7 +254,6 @@ public class CommandManager {
return;
}
String s = args.get(2).toLowerCase();
switch (s) {
// Provide aliases
@@ -204,6 +263,7 @@ public class CommandManager {
args.remove(2);
args.add(2, "permission");
break;
case "chat":
case "m":
args.remove(2);
args.add(2, "meta");
@@ -212,12 +272,19 @@ public class CommandManager {
case "inherit":
case "inheritances":
case "group":
case "groups":
case "rank":
case "ranks":
case "parents":
args.remove(2);
args.add(2, "parent");
break;
// Provide backwards compatibility
case "setprimarygroup":
args.remove(2);
args.add(2, "switchprimarygroup");
break;
case "listnodes":
args.remove(2);
args.add(2, "permission");
@@ -229,6 +296,16 @@ public class CommandManager {
case "unsettemp":
args.add(2, "permission");
break;
case "haspermission":
args.remove(2);
args.add(2, "permission");
args.add(3, "check");
break;
case "inheritspermission":
args.remove(2);
args.add(2, "permission");
args.add(3, "checkinherits");
break;
case "listgroups":
args.remove(2);
args.add(2, "parent");
@@ -240,6 +317,11 @@ public class CommandManager {
args.add(2, "parent");
args.add(3, "add");
break;
case "setgroup":
args.remove(2);
args.add(2, "parent");
args.add(3, "set");
break;
case "removegroup":
case "unsetinherit":
args.remove(2);
@@ -273,6 +355,22 @@ public class CommandManager {
case "removetempsuffix":
args.add(2, "meta");
break;
default:
break;
}
// Provide lazy set rewrite
boolean lazySet = (
args.size() >= 6 &&
args.get(2).equalsIgnoreCase("permission") &&
args.get(3).toLowerCase().startsWith("set") &&
(args.get(5).equalsIgnoreCase("none") || args.get(5).equalsIgnoreCase("0"))
);
if (lazySet) {
args.remove(5);
args.remove(3);
args.add(3, "unset");
}
}
}
@@ -34,13 +34,13 @@ public enum CommandResult {
INVALID_ARGS(false),
NO_PERMISSION(false);
private boolean booleanValue;
private boolean value;
public boolean booleanValue() {
return booleanValue;
public boolean asBoolean() {
return value;
}
static CommandResult of(boolean b) {
public static CommandResult of(boolean b) {
return b ? SUCCESS : FAILURE;
}
@@ -25,6 +25,7 @@ package me.lucko.luckperms.common.commands;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.common.commands.sender.Sender;
import java.util.ArrayList;
import java.util.List;
@@ -22,11 +22,12 @@
package me.lucko.luckperms.common.commands;
import com.google.common.collect.ImmutableList;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.ArrayList;
import java.util.Collections;
@@ -34,50 +35,27 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Getter
@AllArgsConstructor
public abstract class MainCommand<T> {
public abstract class MainCommand<T> extends BaseCommand<Void, T> {
/**
* The name of the main command
*/
private final String name;
/**
* The command usage
*/
private final String usage;
/**
* How many arguments are required for the command to run
*/
private final int requiredArgsLength;
/**
* A list of the sub commands under this main command
*/
@Getter
private final List<SubCommand<T>> subCommands;
private final String usage;
private final int minArgs; // equals 1 if the command doesn't take a mid argument, e.g. /lp user <USER> sub-command....
MainCommand(String name, String usage, int requiredArgsLength) {
this(name, usage, requiredArgsLength, ImmutableList.of());
public MainCommand(String name, String description, String usage, int minArgs, List<Command<T, ?>> children) {
super(name, description, null, Predicates.alwaysFalse(), null, children);
this.usage = usage;
this.minArgs = minArgs;
}
/**
* Called when this main command is ran
* @param plugin a link to the main plugin instance
* @param sender the sender to executed the command
* @param args the stripped arguments given
* @param label the command label used
*/
protected CommandResult execute(LuckPermsPlugin plugin, Sender sender, List<String> args, String label) {
if (args.size() < requiredArgsLength) {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Void v, List<String> args, String label) throws CommandException {
if (args.size() < minArgs) {
sendUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
Optional<SubCommand<T>> o = getSubCommands().stream()
.filter(s -> s.getName().equalsIgnoreCase(args.get(requiredArgsLength - 1)))
Optional<Command<T, ?>> o = getSubCommands().stream()
.filter(s -> s.getName().equalsIgnoreCase(args.get(minArgs - 1)))
.limit(1)
.findAny();
@@ -86,26 +64,32 @@ public abstract class MainCommand<T> {
return CommandResult.INVALID_ARGS;
}
final SubCommand<T> sub = o.get();
final Command<T, ?> sub = o.get();
if (!sub.isAuthorized(sender)) {
Message.COMMAND_NO_PERMISSION.send(sender);
return CommandResult.NO_PERMISSION;
}
List<String> strippedArgs = new ArrayList<>();
if (args.size() > requiredArgsLength) {
strippedArgs.addAll(args.subList(requiredArgsLength, args.size()));
if (args.size() > minArgs) {
strippedArgs.addAll(args.subList(minArgs, args.size()));
}
if (sub.getIsArgumentInvalid().test(strippedArgs.size())) {
sub.sendDetailedUsage(sender);
if (sub.getArgumentCheck().test(strippedArgs.size())) {
sub.sendDetailedUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
final String name = args.get(0).toLowerCase();
T t = getTarget(name, plugin, sender);
if (t != null) {
CommandResult result = sub.execute(plugin, sender, t, strippedArgs, label);
CommandResult result;
try {
result = sub.execute(plugin, sender, t, strippedArgs, label);
} catch (CommandException e) {
result = CommandManager.handleException(e, sender, label, sub);
}
cleanup(t, plugin);
return result;
}
@@ -113,61 +97,9 @@ public abstract class MainCommand<T> {
return CommandResult.LOADING_ERROR;
}
/**
* Gets the object the command is acting upon, and runs the callback if successful
* @param target the name of the object to be looked up
* @param plugin a link to the main plugin instance
* @param sender the user who send the command (used to send error messages if the lookup was unsuccessful)
*/
protected abstract T getTarget(String target, LuckPermsPlugin plugin, Sender sender);
protected abstract void cleanup(T t, LuckPermsPlugin plugin);
/**
* Get a list of {@link T} objects for tab completion
* @param plugin a link to the main plugin instance
* @return a list of strings
*/
protected abstract List<String> getObjects(LuckPermsPlugin plugin);
/**
* Send the command usage to a sender
* @param sender the sender to send the usage to
* @param label the command label used
*/
protected void sendUsage(Sender sender, String label) {
if (getSubCommands().isEmpty()) {
Util.sendPluginMessage(sender, "&3> &a" + String.format(getUsage(), label));
return;
}
List<SubCommand> subs = getSubCommands().stream()
.filter(s -> s.isAuthorized(sender))
.collect(Collectors.toList());
if (subs.size() > 0) {
Util.sendPluginMessage(sender, "&b" + getName() + " Sub Commands: &7(" + String.format(getUsage(), label) + " ...)");
for (SubCommand s : subs) {
s.sendUsage(sender);
}
} else {
Message.COMMAND_NO_PERMISSION.send(sender);
}
}
/**
* If a sender has permission to use this command
* @param sender the sender trying to use the command
* @return true if the sender can use the command
*/
protected boolean isAuthorized(Sender sender) {
return getSubCommands().stream().filter(sc -> sc.isAuthorized(sender)).count() != 0;
}
protected List<String> onTabComplete(Sender sender, List<String> args, LuckPermsPlugin plugin) {
final List<String> objects = getObjects(plugin);
@Override
public List<String> tabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
final List<String> objects = getTargets(plugin);
if (args.size() <= 1) {
if (args.isEmpty() || args.get(0).equalsIgnoreCase("")) {
@@ -179,7 +111,7 @@ public abstract class MainCommand<T> {
.collect(Collectors.toList());
}
final List<SubCommand<T>> subs = getSubCommands().stream()
final List<Command<T, ?>> subs = getSubCommands().stream()
.filter(s -> s.isAuthorized(sender))
.collect(Collectors.toList());
@@ -196,7 +128,7 @@ public abstract class MainCommand<T> {
.collect(Collectors.toList());
}
Optional<SubCommand<T>> o = subs.stream()
Optional<Command<T, ?>> o = subs.stream()
.filter(s -> s.getName().equalsIgnoreCase(args.get(1)))
.limit(1)
.findAny();
@@ -205,6 +137,56 @@ public abstract class MainCommand<T> {
return Collections.emptyList();
}
return o.get().onTabComplete(plugin, sender, args.subList(2, args.size()));
return o.get().tabComplete(plugin, sender, args.subList(2, args.size()));
}
protected abstract List<String> getTargets(LuckPermsPlugin plugin);
protected abstract T getTarget(String target, LuckPermsPlugin plugin, Sender sender);
protected abstract void cleanup(T t, LuckPermsPlugin plugin);
@Override
public void sendUsage(Sender sender, String label) {
/*
if (getSubCommands().isEmpty()) {
Util.sendPluginMessage(sender, "&3> &a" + String.format(getUsage(), label));
return;
*/
List<Command> subs = getSubCommands().stream()
.filter(s -> s.isAuthorized(sender))
.collect(Collectors.toList());
if (subs.size() > 0) {
Util.sendPluginMessage(sender, "&b" + getName() + " Sub Commands: &7(" + String.format(usage, label) + " ...)");
for (Command s : subs) {
s.sendUsage(sender, label);
}
} else {
Message.COMMAND_NO_PERMISSION.send(sender);
}
}
@Override
public void sendDetailedUsage(Sender sender, String label) {
}
@Override
public boolean isAuthorized(Sender sender) {
return getSubCommands().stream().filter(sc -> sc.isAuthorized(sender)).count() != 0;
}
@Deprecated
@Override
public Optional<List<Command<T, ?>>> getChildren() {
return super.getChildren();
}
@SuppressWarnings("deprecation")
public List<Command<T, ?>> getSubCommands() {
return getChildren().get();
}
}
@@ -1,134 +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.commands;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Factory class to make a thread-safe sender instance
* @param <T> the command sender type
*/
@RequiredArgsConstructor
public abstract class SenderFactory<T> implements Runnable {
private final LuckPermsPlugin plugin;
private final Map<T, List<String>> messages = new HashMap<>();
private final AtomicBoolean shouldSend = new AtomicBoolean(false);
private final SenderFactory<T> factory = this;
protected abstract String getName(T t);
protected abstract UUID getUuid(T t);
protected abstract void sendMessage(T t, String s);
protected abstract boolean hasPermission(T t, String node);
public final Sender wrap(T t) {
return new SenderImp(plugin, t, null);
}
public final Sender wrap(T t, Set<Permission> toCheck) {
return new SenderImp(plugin, t, toCheck);
}
@Override
public final void run() {
if (!shouldSend.getAndSet(false)) {
return;
}
synchronized (messages) {
for (Map.Entry<T, List<String>> e : messages.entrySet()) {
for (String s : e.getValue()) {
factory.sendMessage(e.getKey(), s);
}
}
messages.clear();
}
}
private class SenderImp implements Sender {
private final WeakReference<T> tRef;
// Cache these permissions, so they can be accessed async
private Map<Permission, Boolean> perms;
@Getter
private final String name;
@Getter
private final UUID uuid;
private final boolean console;
@Getter
private final LuckPermsPlugin platform;
private SenderImp(LuckPermsPlugin platform, T t, Set<Permission> toCheck) {
this.platform = platform;
this.tRef = new WeakReference<>(t);
this.name = factory.getName(t);
this.uuid = factory.getUuid(t);
this.console = this.uuid.equals(Constants.getConsoleUUID()) || this.uuid.equals(Constants.getImporterUUID());
if (!this.console) {
this.perms = ((toCheck == null || toCheck.isEmpty()) ? Arrays.stream(Permission.values()) : toCheck.stream())
.collect(ImmutableCollectors.toImmutableMap(p -> p, p -> {
for (String s : p.getNodes()) {
if (factory.hasPermission(t, s)) {
return true;
}
}
return false;
}));
}
}
@Override
public void sendMessage(String s) {
final T t = tRef.get();
if (t != null) {
synchronized (messages) {
if (!messages.containsKey(t)) {
messages.put(t, new ArrayList<>());
}
messages.get(t).add(s);
}
shouldSend.set(true);
}
}
@Override
public boolean hasPermission(Permission permission) {
return console || perms.get(permission);
}
}
}
@@ -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.common.commands;
import lombok.Getter;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import java.util.List;
import java.util.function.Predicate;
public abstract class SingleCommand extends BaseCommand<Void, Void> {
@Getter
private final String usage;
public SingleCommand(String name, String description, String usage, Permission permission, Predicate<Integer> argumentCheck, List<Arg> args) {
super(name, description, permission, argumentCheck, args, null);
this.usage = usage;
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Void v, List<String> args, String label) throws CommandException {
return execute(plugin, sender, args, label);
}
public abstract CommandResult execute(LuckPermsPlugin plugin, Sender sender, List<String> args, String label) throws CommandException;
@Override
public void sendUsage(Sender sender, String label) {
StringBuilder sb = new StringBuilder();
if (getArgs().isPresent()) {
sb.append("&3 - &7");
for (Arg arg : getArgs().get()) {
sb.append(arg.asPrettyString()).append(" ");
}
}
Util.sendPluginMessage(sender, "&3> &a" + getName().toLowerCase() + sb.toString());
}
@Override
public void sendDetailedUsage(Sender sender, String label) {
Util.sendPluginMessage(sender, "&3&lCommand Usage &3- &b" + getName());
Util.sendPluginMessage(sender, "&b> &7" + getDescription());
if (getArgs().isPresent()) {
Util.sendPluginMessage(sender, "&3Arguments:");
for (Arg arg : getArgs().get()) {
Util.sendPluginMessage(sender, "&b- " + arg.asPrettyString() + "&3 -> &7" + arg.getDescription());
}
}
}
}
@@ -1,77 +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.commands;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.constants.Permission;
import java.util.Collections;
import java.util.List;
/**
* An extension of {@link MainCommand} for implementations without any subcommands
*/
public class SingleMainCommand extends MainCommand<Object> {
private final Permission permission;
public SingleMainCommand(String name, String usage, int requiredArgsLength, Permission permission) {
super(name, usage, requiredArgsLength);
this.permission = permission;
}
@Override
protected CommandResult execute(LuckPermsPlugin plugin, Sender sender, List<String> args, String label) {
// Do nothing, allow the implementation to override this
return null;
}
@Override
protected Object getTarget(String target, LuckPermsPlugin plugin, Sender sender) {
return null;
}
@Override
protected void cleanup(Object o, LuckPermsPlugin plugin) {
// Do nothing
}
@Override
protected List<String> getObjects(LuckPermsPlugin plugin) {
return Collections.emptyList();
}
@Override
protected List<String> onTabComplete(Sender sender, List<String> args, LuckPermsPlugin plugin) {
return Collections.emptyList();
}
@Override
public List<SubCommand<Object>> getSubCommands() {
return Collections.emptyList();
}
@Override
protected boolean isAuthorized(Sender sender) {
return permission.isAuthorized(sender);
}
}
@@ -22,10 +22,10 @@
package me.lucko.luckperms.common.commands;
import com.google.common.collect.ImmutableList;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.groups.Group;
@@ -43,93 +43,45 @@ import java.util.stream.Collectors;
* Abstract SubCommand class
*/
@Getter
@AllArgsConstructor
public abstract class SubCommand<T> {
public abstract class SubCommand<T> extends Command<T, Void> {
/**
* The name of the sub command
*/
private final String name;
/**
* A brief description of what the sub command does
*/
private final String description;
/**
* The permission needed to use this command
*/
private final Permission permission;
/**
* Predicate to test if the argument length given is invalid
*/
private final Predicate<? super Integer> isArgumentInvalid;
private final ImmutableList<Arg> args;
/**
* Called when this sub command is ran
* @param plugin a link to the main plugin instance
* @param sender the sender to executed the command
* @param t the object the command is operating on
* @param args the stripped arguments given
* @param label the command label used
*/
public abstract CommandResult execute(LuckPermsPlugin plugin, Sender sender, T t, List<String> args, String label);
/**
* Returns a list of suggestions, which are empty by default. Sub classes that give tab complete suggestions override
* this method to give their own list.
* @param plugin the plugin instance
* @param sender who is tab completing
* @param args the arguments so far
* @return a list of suggestions
*/
public List<String> onTabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
return Collections.emptyList();
public SubCommand(String name, String description, Permission permission, Predicate<Integer> argumentCheck, List<Arg> args) {
super(name, description, permission, argumentCheck, args);
}
/**
* Send the command usage to a sender
* @param sender the sender to send the usage to
*/
public void sendUsage(Sender sender) {
String usage = "";
if (args != null) {
usage += "&3 - &7";
for (Arg arg : args) {
usage += arg.asPrettyString() + " ";
@Override
public void sendUsage(Sender sender, String label) {
StringBuilder sb = new StringBuilder();
if (getArgs().isPresent()) {
sb.append("&3 - &7");
for (Arg arg : getArgs().get()) {
sb.append(arg.asPrettyString()).append(" ");
}
}
Util.sendPluginMessage(sender, "&3> &a" + getName().toLowerCase() + usage);
Util.sendPluginMessage(sender, "&3> &a" + getName().toLowerCase() + sb.toString());
}
public void sendDetailedUsage(Sender sender) {
@Override
public void sendDetailedUsage(Sender sender, String label) {
Util.sendPluginMessage(sender, "&3&lCommand Usage &3- &b" + getName());
Util.sendPluginMessage(sender, "&b> &7" + getDescription());
if (args != null) {
if (getArgs().isPresent()) {
Util.sendPluginMessage(sender, "&3Arguments:");
for (Arg arg : args) {
for (Arg arg : getArgs().get()) {
Util.sendPluginMessage(sender, "&b- " + arg.asPrettyString() + "&3 -> &7" + arg.getDescription());
}
}
}
/**
* If a sender has permission to use this command
* @param sender the sender trying to use the command
* @return true if the sender can use the command
*/
public boolean isAuthorized(Sender sender) {
return permission.isAuthorized(sender);
}
/*
* ----------------------------------------------------------------------------------
* Utility methods used by #onTabComplete and #execute implementations in sub classes
* Utility methods used by #tabComplete and #execute implementations in sub classes
* ----------------------------------------------------------------------------------
*/
@@ -162,32 +114,35 @@ public abstract class SubCommand<T> {
}
public static void save(User user, Sender sender, LuckPermsPlugin plugin) {
if (plugin.getDatastore().saveUser(user).getUnchecked()) {
boolean success = plugin.getStorage().force().saveUser(user).join();
user.getRefreshBuffer().requestDirectly();
if (success) {
Message.USER_SAVE_SUCCESS.send(sender);
} else {
Message.USER_SAVE_ERROR.send(sender);
}
user.getRefreshBuffer().request().getUnchecked();
}
public static void save(Group group, Sender sender, LuckPermsPlugin plugin) {
if (plugin.getDatastore().saveGroup(group).getUnchecked()) {
boolean success = plugin.getStorage().force().saveGroup(group).join();
plugin.getUpdateTaskBuffer().requestDirectly();
if (success) {
Message.GROUP_SAVE_SUCCESS.send(sender);
} else {
Message.GROUP_SAVE_ERROR.send(sender);
}
plugin.getUpdateTaskBuffer().request();
}
public static void save(Track track, Sender sender, LuckPermsPlugin plugin) {
if (plugin.getDatastore().saveTrack(track).getUnchecked()) {
boolean success = plugin.getStorage().force().saveTrack(track).join();
plugin.getUpdateTaskBuffer().requestDirectly();
if (success) {
Message.TRACK_SAVE_SUCCESS.send(sender);
} else {
Message.TRACK_SAVE_ERROR.send(sender);
}
plugin.getUpdateTaskBuffer().request();
}
}
@@ -22,11 +22,16 @@
package me.lucko.luckperms.common.commands.generic;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.*;
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.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.ArrayList;
import java.util.Collections;
@@ -34,29 +39,24 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class SecondaryMainCommand<T extends PermissionHolder> extends SubCommand<T> {
public class SharedMainCommand<T extends PermissionHolder> extends SubCommand<T> {
private boolean user;
private final List<SecondarySubCommand> secondaryCommands;
private final List<SharedSubCommand> secondaryCommands;
public SecondaryMainCommand(String name, String description, boolean user, List<SecondarySubCommand> secondaryCommands) {
super(name, description, null, Predicate.alwaysFalse(),
!name.equals("Meta") ? ImmutableList.copyOf(secondaryCommands.stream()
.map(s -> Arg.create(s.getName(), false, s.getDescription()))
.collect(Collectors.toList())
) : null
);
public SharedMainCommand(String name, String description, boolean user, List<SharedSubCommand> secondaryCommands) {
super(name, description, null, Predicates.alwaysFalse(), null);
this.secondaryCommands = secondaryCommands;
this.user = user;
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, T t, List<String> args, String label) {
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, T t, List<String> args, String label) throws CommandException {
if (args.size() == 0) {
sendUsageDetailed(sender, user, label);
return CommandResult.INVALID_ARGS;
}
Optional<SecondarySubCommand> o = secondaryCommands.stream()
Optional<SharedSubCommand> o = secondaryCommands.stream()
.filter(s -> s.getName().equalsIgnoreCase(args.get(0)))
.limit(1)
.findAny();
@@ -66,7 +66,7 @@ public class SecondaryMainCommand<T extends PermissionHolder> extends SubCommand
return CommandResult.INVALID_ARGS;
}
final SecondarySubCommand sub = o.get();
final SharedSubCommand sub = o.get();
if (!sub.isAuthorized(sender, user)) {
Message.COMMAND_NO_PERMISSION.send(sender);
return CommandResult.NO_PERMISSION;
@@ -82,12 +82,56 @@ public class SecondaryMainCommand<T extends PermissionHolder> extends SubCommand
return CommandResult.INVALID_ARGS;
}
return sub.execute(plugin, sender, t, strippedArgs);
CommandResult result;
try {
result = sub.execute(plugin, sender, t, strippedArgs);
} catch (CommandException e) {
result = handleException(e, sender, sub);
}
return result;
}
private static CommandResult handleException(CommandException e, Sender sender, SharedSubCommand command) {
if (e instanceof ArgumentUtils.ArgumentException) {
if (e instanceof ArgumentUtils.DetailedUsageException) {
command.sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (e instanceof ArgumentUtils.UseInheritException) {
Message.USE_INHERIT_COMMAND.send(sender);
return CommandResult.INVALID_ARGS;
}
if (e instanceof ArgumentUtils.InvalidServerException) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (e instanceof ArgumentUtils.PastDateException) {
Message.PAST_DATE_ERROR.send(sender);
return CommandResult.INVALID_ARGS;
}
if (e instanceof ArgumentUtils.InvalidDateException) {
Message.ILLEGAL_DATE_ERROR.send(sender, ((ArgumentUtils.InvalidDateException) e).getInvalidDate());
return CommandResult.INVALID_ARGS;
}
if (e instanceof ArgumentUtils.InvalidPriorityException) {
Message.META_INVALID_PRIORITY.send(sender, ((ArgumentUtils.InvalidPriorityException) e).getInvalidPriority());
return CommandResult.INVALID_ARGS;
}
}
// Not something we can catch.
e.printStackTrace();
return CommandResult.FAILURE;
}
@Override
public List<String> onTabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
final List<SecondarySubCommand> subs = secondaryCommands.stream()
public List<String> tabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
final List<SharedSubCommand> subs = secondaryCommands.stream()
.filter(s -> s.isAuthorized(sender, user))
.collect(Collectors.toList());
@@ -104,7 +148,7 @@ public class SecondaryMainCommand<T extends PermissionHolder> extends SubCommand
.collect(Collectors.toList());
}
Optional<SecondarySubCommand> o = subs.stream()
Optional<SharedSubCommand> o = subs.stream()
.filter(s -> s.getName().equalsIgnoreCase(args.get(0)))
.limit(1)
.findAny();
@@ -118,7 +162,7 @@ public class SecondaryMainCommand<T extends PermissionHolder> extends SubCommand
@Override
public boolean isAuthorized(Sender sender) {
for (SecondarySubCommand subCommand : secondaryCommands) {
for (SharedSubCommand subCommand : secondaryCommands) {
if (subCommand.isAuthorized(sender, user)) {
return true;
}
@@ -127,7 +171,7 @@ public class SecondaryMainCommand<T extends PermissionHolder> extends SubCommand
}
private void sendUsageDetailed(Sender sender, boolean user, String label) {
List<SecondarySubCommand> subs = secondaryCommands.stream()
List<SharedSubCommand> subs = secondaryCommands.stream()
.filter(s -> s.isAuthorized(sender, user))
.collect(Collectors.toList());
@@ -138,7 +182,7 @@ public class SecondaryMainCommand<T extends PermissionHolder> extends SubCommand
Util.sendPluginMessage(sender, "&b" + getName() + " Sub Commands: &7(" + String.format("/%s group <group> " + getName().toLowerCase() + " ...)", label));
}
for (SecondarySubCommand s : subs) {
for (SharedSubCommand s : subs) {
s.sendUsage(sender);
}
@@ -26,7 +26,12 @@ import com.google.common.collect.ImmutableList;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.*;
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.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.groups.Group;
@@ -38,7 +43,7 @@ import java.util.function.Predicate;
@Getter
@AllArgsConstructor
public abstract class SecondarySubCommand {
public abstract class SharedSubCommand {
/**
* The name of the sub command
@@ -63,22 +68,22 @@ public abstract class SecondarySubCommand {
private final ImmutableList<Arg> args;
public abstract CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args);
public abstract CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException;
public List<String> onTabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
return Collections.emptyList();
}
public void sendUsage(Sender sender) {
String usage = "";
StringBuilder sb = new StringBuilder();
if (args != null) {
usage += "&3 - &7";
sb.append("&3 - &7");
for (Arg arg : args) {
usage += arg.asPrettyString() + " ";
sb.append(arg.asPrettyString()).append(" ");
}
}
Util.sendPluginMessage(sender, "&3> &a" + getName() + usage);
Util.sendPluginMessage(sender, "&3> &a" + getName() + sb.toString());
}
public void sendDetailedUsage(Sender sender) {
@@ -23,13 +23,13 @@
package me.lucko.luckperms.common.commands.generic.meta;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.common.commands.generic.SecondaryMainCommand;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedMainCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.core.PermissionHolder;
public class CommandMeta<T extends PermissionHolder> extends SecondaryMainCommand<T> {
public class CommandMeta<T extends PermissionHolder> extends SharedMainCommand<T> {
public CommandMeta(boolean user) {
super("Meta", "Edit metadata values", user, ImmutableList.<SecondarySubCommand>builder()
super("Meta", "Edit metadata values", user, ImmutableList.<SharedSubCommand>builder()
.add(new MetaInfo())
.add(new MetaSet())
.add(new MetaUnset())
@@ -25,22 +25,26 @@ package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import java.util.List;
import java.util.stream.Collectors;
public class MetaAddPrefix extends SecondarySubCommand {
public class MetaAddPrefix extends SharedSubCommand {
public MetaAddPrefix() {
super("addprefix", "Adds a prefix", Permission.USER_META_ADDPREFIX, Permission.GROUP_META_ADDPREFIX, Predicate.notInRange(2, 4),
super("addprefix", "Adds a prefix", Permission.USER_META_ADDPREFIX, Permission.GROUP_META_ADDPREFIX,
Predicates.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to add the prefix at"),
Arg.create("prefix", true, "the prefix string"),
@@ -51,51 +55,37 @@ public class MetaAddPrefix extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
final String prefix = args.get(1).replace("{SPACE}", " ");
int priority;
try {
priority = Integer.parseInt(args.get(0));
} catch (NumberFormatException e) {
Message.META_INVALID_PRIORITY.send(sender, args.get(0));
return CommandResult.INVALID_ARGS;
}
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
int priority = ArgumentUtils.handlePriority(0, args);
String prefix = ArgumentUtils.handleNodeWithoutCheck(1, args);
String server = ArgumentUtils.handleServer(2, args);
String world = ArgumentUtils.handleWorld(3, args);
final String node = "prefix." + priority + "." + MetaUtils.escapeCharacters(prefix);
try {
if (args.size() >= 3) {
final String server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() == 3) {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.setPermission(node, true);
Message.ADDPREFIX_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority);
break;
case SERVER:
holder.setPermission(node, true, server);
Message.ADDPREFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server);
LogEntry.build().actor(sender).acted(holder)
.action("meta addprefix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
break;
case SERVER_AND_WORLD:
holder.setPermission(node, true, server, world);
Message.ADDPREFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server, world);
LogEntry.build().actor(sender).acted(holder)
.action("meta addprefix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
holder.setPermission(node, true);
Message.ADDPREFIX_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority);
LogEntry.build().actor(sender).acted(holder)
.action("meta addprefix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta addprefix " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_PREFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
@@ -25,22 +25,26 @@ package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import java.util.List;
import java.util.stream.Collectors;
public class MetaAddSuffix extends SecondarySubCommand {
public class MetaAddSuffix extends SharedSubCommand {
public MetaAddSuffix() {
super("addsuffix", "Adds a suffix", Permission.USER_META_ADDSUFFIX, Permission.GROUP_META_ADDSUFFIX, Predicate.notInRange(2, 4),
super("addsuffix", "Adds a suffix", Permission.USER_META_ADDSUFFIX, Permission.GROUP_META_ADDSUFFIX,
Predicates.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to add the suffix at"),
Arg.create("suffix", true, "the suffix string"),
@@ -51,51 +55,37 @@ public class MetaAddSuffix extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
final String suffix = args.get(1).replace("{SPACE}", " ");
int priority;
try {
priority = Integer.parseInt(args.get(0));
} catch (NumberFormatException e) {
Message.META_INVALID_PRIORITY.send(sender, args.get(0));
return CommandResult.INVALID_ARGS;
}
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
int priority = ArgumentUtils.handlePriority(0, args);
String suffix = ArgumentUtils.handleNodeWithoutCheck(1, args);
String server = ArgumentUtils.handleServer(2, args);
String world = ArgumentUtils.handleWorld(3, args);
final String node = "suffix." + priority + "." + MetaUtils.escapeCharacters(suffix);
try {
if (args.size() >= 3) {
final String server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() == 3) {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.setPermission(node, true);
Message.ADDSUFFIX_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority);
break;
case SERVER:
holder.setPermission(node, true, server);
Message.ADDSUFFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server);
LogEntry.build().actor(sender).acted(holder)
.action("meta addsuffix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
break;
case SERVER_AND_WORLD:
holder.setPermission(node, true, server, world);
Message.ADDSUFFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server, world);
LogEntry.build().actor(sender).acted(holder)
.action("meta addsuffix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
holder.setPermission(node, true);
Message.ADDSUFFIX_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority);
LogEntry.build().actor(sender).acted(holder)
.action("meta addsuffix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta addsuffix " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_SUFFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
@@ -25,23 +25,27 @@ package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import java.util.List;
import java.util.stream.Collectors;
public class MetaAddTempPrefix extends SecondarySubCommand {
public class MetaAddTempPrefix extends SharedSubCommand {
public MetaAddTempPrefix() {
super("addtempprefix", "Adds a prefix temporarily", Permission.USER_META_ADDTEMP_PREFIX, Permission.GROUP_META_ADDTEMP_PREFIX, Predicate.notInRange(3, 5),
super("addtempprefix", "Adds a prefix temporarily", Permission.USER_META_ADDTEMP_PREFIX,
Permission.GROUP_META_ADDTEMP_PREFIX, Predicates.notInRange(3, 5),
Arg.list(
Arg.create("priority", true, "the priority to add the prefix at"),
Arg.create("prefix", true, "the prefix string"),
@@ -53,68 +57,44 @@ public class MetaAddTempPrefix extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
final String prefix = args.get(1).replace("{SPACE}", " ");
int priority;
try {
priority = Integer.parseInt(args.get(0));
} catch (NumberFormatException e) {
Message.META_INVALID_PRIORITY.send(sender, args.get(0));
return CommandResult.INVALID_ARGS;
}
long duration;
try {
duration = Long.parseLong(args.get(2));
} catch (NumberFormatException e) {
try {
duration = DateUtil.parseDateDiff(args.get(2), true);
} catch (DateUtil.IllegalDateException e1) {
Message.ILLEGAL_DATE_ERROR.send(sender, args.get(2));
return CommandResult.INVALID_ARGS;
}
}
if (DateUtil.shouldExpire(duration)) {
Message.PAST_DATE_ERROR.send(sender);
return CommandResult.INVALID_ARGS;
}
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
int priority = ArgumentUtils.handlePriority(0, args);
String prefix = ArgumentUtils.handleNodeWithoutCheck(1, args);
long duration = ArgumentUtils.handleDuration(2, args);
String server = ArgumentUtils.handleServer(3, args);
String world = ArgumentUtils.handleWorld(4, args);
final String node = "prefix." + priority + "." + MetaUtils.escapeCharacters(prefix);
try {
if (args.size() >= 4) {
final String server = args.get(3).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() == 4) {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.setPermission(node, true, duration);
Message.ADD_TEMP_PREFIX_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority,
DateUtil.formatDateDiff(duration)
);
break;
case SERVER:
holder.setPermission(node, true, server, duration);
Message.ADD_TEMP_PREFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(holder)
.action("meta addtempprefix " + priority + " " + args.get(1) + " " + duration + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(4).toLowerCase();
Message.ADD_TEMP_PREFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority,
server, DateUtil.formatDateDiff(duration)
);
break;
case SERVER_AND_WORLD:
holder.setPermission(node, true, server, world, duration);
Message.ADD_TEMP_PREFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server, world, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(holder)
.action("meta addtempprefix " + priority + " " + args.get(1) + " " + duration + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
holder.setPermission(node, true, duration);
Message.ADD_TEMP_PREFIX_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(holder)
.action("meta addtempprefix " + priority + " " + args.get(1) + " " + duration)
.build().submit(plugin, sender);
Message.ADD_TEMP_PREFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority,
server, world, DateUtil.formatDateDiff(duration)
);
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta addtempprefix " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_PREFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
@@ -25,23 +25,27 @@ package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import java.util.List;
import java.util.stream.Collectors;
public class MetaAddTempSuffix extends SecondarySubCommand {
public class MetaAddTempSuffix extends SharedSubCommand {
public MetaAddTempSuffix() {
super("addtempsuffix", "Adds a suffix temporarily", Permission.USER_META_ADDTEMP_SUFFIX, Permission.GROUP_META_ADDTEMP_SUFFIX, Predicate.notInRange(3, 5),
super("addtempsuffix", "Adds a suffix temporarily", Permission.USER_META_ADDTEMP_SUFFIX,
Permission.GROUP_META_ADDTEMP_SUFFIX, Predicates.notInRange(3, 5),
Arg.list(
Arg.create("priority", true, "the priority to add the suffix at"),
Arg.create("suffix", true, "the suffix string"),
@@ -53,68 +57,44 @@ public class MetaAddTempSuffix extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
final String suffix = args.get(1).replace("{SPACE}", " ");
int priority;
try {
priority = Integer.parseInt(args.get(0));
} catch (NumberFormatException e) {
Message.META_INVALID_PRIORITY.send(sender, args.get(0));
return CommandResult.INVALID_ARGS;
}
long duration;
try {
duration = Long.parseLong(args.get(2));
} catch (NumberFormatException e) {
try {
duration = DateUtil.parseDateDiff(args.get(2), true);
} catch (DateUtil.IllegalDateException e1) {
Message.ILLEGAL_DATE_ERROR.send(sender, args.get(2));
return CommandResult.INVALID_ARGS;
}
}
if (DateUtil.shouldExpire(duration)) {
Message.PAST_DATE_ERROR.send(sender);
return CommandResult.INVALID_ARGS;
}
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
int priority = ArgumentUtils.handlePriority(0, args);
String suffix = ArgumentUtils.handleNodeWithoutCheck(1, args);
long duration = ArgumentUtils.handleDuration(2, args);
String server = ArgumentUtils.handleServer(3, args);
String world = ArgumentUtils.handleWorld(4, args);
final String node = "suffix." + priority + "." + MetaUtils.escapeCharacters(suffix);
try {
if (args.size() >= 4) {
final String server = args.get(3).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() == 4) {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.setPermission(node, true, duration);
Message.ADD_TEMP_SUFFIX_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority,
DateUtil.formatDateDiff(duration)
);
break;
case SERVER:
holder.setPermission(node, true, server, duration);
Message.ADD_TEMP_SUFFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(holder)
.action("meta addtempsuffix " + priority + " " + args.get(1) + " " + duration + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(4).toLowerCase();
Message.ADD_TEMP_SUFFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority,
server, DateUtil.formatDateDiff(duration)
);
break;
case SERVER_AND_WORLD:
holder.setPermission(node, true, server, world, duration);
Message.ADD_TEMP_SUFFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server, world, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(holder)
.action("meta addtempsuffix " + priority + " " + args.get(1) + " " + duration + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
holder.setPermission(node, true, duration);
Message.ADD_TEMP_SUFFIX_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(holder)
.action("meta addtempsuffix " + priority + " " + args.get(1) + " " + duration)
.build().submit(plugin, sender);
Message.ADD_TEMP_SUFFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority,
server, world, DateUtil.formatDateDiff(duration)
);
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta addtempsuffix " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_SUFFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
@@ -24,22 +24,24 @@ package me.lucko.luckperms.common.commands.generic.meta;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.List;
import java.util.stream.Collectors;
public class MetaClear extends SecondarySubCommand {
public class MetaClear extends SharedSubCommand {
public MetaClear() {
super("clear", "Clears all chat meta", Permission.USER_META_CLEAR, Permission.GROUP_META_CLEAR, Predicate.notInRange(0, 2),
super("clear", "Clears all chat meta", Permission.USER_META_CLEAR, Permission.GROUP_META_CLEAR, Predicates.notInRange(0, 2),
Arg.list(
Arg.create("server", false, "the server name to filter by"),
Arg.create("world", false, "the world name to filter by")
@@ -48,25 +50,22 @@ public class MetaClear extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
int before = holder.getNodes().size();
if (args.size() == 0) {
holder.clearMeta();
} else {
final String server = args.get(0);
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
String server = ArgumentUtils.handleServer(0, args);
String world = ArgumentUtils.handleWorld(1, args);
if (args.size() == 2) {
final String world = args.get(1);
holder.clearMeta(server, world);
} else {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.clearMeta();
break;
case SERVER:
holder.clearMeta(server);
}
break;
case SERVER_AND_WORLD:
holder.clearMeta(server, world);
break;
}
int changed = before - holder.getNodes().size();
@@ -76,7 +75,10 @@ public class MetaClear extends SecondarySubCommand {
Message.META_CLEAR_SUCCESS.send(sender, holder.getFriendlyName(), changed);
}
LogEntry.build().actor(sender).acted(holder).action("meta clear " + args.stream().collect(Collectors.joining(" "))).build().submit(plugin, sender);
LogEntry.build().actor(sender).acted(holder)
.action("meta clear " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
}
@@ -23,50 +23,44 @@
package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.Util;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.*;
public class MetaInfo extends SecondarySubCommand {
public class MetaInfo extends SharedSubCommand {
public MetaInfo() {
super("info", "Shows all chat meta", Permission.USER_META_INFO, Permission.GROUP_META_INFO, Predicate.alwaysFalse(), null);
super("info", "Shows all chat meta", Permission.USER_META_INFO, Permission.GROUP_META_INFO, Predicates.alwaysFalse(), null);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
SortedSet<Map.Entry<Integer, String>> prefixes = new TreeSet<>(Util.getMetaComparator().reversed());
SortedSet<Map.Entry<Integer, String>> suffixes = new TreeSet<>(Util.getMetaComparator().reversed());
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
SortedSet<Map.Entry<Integer, LocalizedNode>> prefixes = new TreeSet<>(Util.META_COMPARATOR.reversed());
SortedSet<Map.Entry<Integer, LocalizedNode>> suffixes = new TreeSet<>(Util.META_COMPARATOR.reversed());
Set<LocalizedNode> meta = new HashSet<>();
for (Node node : holder.getAllNodes(null, Contexts.allowAll())) {
if (!node.isSuffix() && !node.isPrefix()) {
// Collect data
for (LocalizedNode node : holder.getAllNodes(null, ExtractedContexts.generate(Contexts.allowAll()))) {
if (!node.isSuffix() && !node.isPrefix() && !node.isMeta()) {
continue;
}
StringBuilder sb = new StringBuilder();
if (node.isServerSpecific()) {
if (node.isWorldSpecific()) {
sb.append("&6W=").append(node.getWorld().get()).append(" ");
}
sb.append("&6S=").append(node.getServer().get()).append(" ");
}
if (node.isPrefix()) {
sb.append(node.getPrefix().getValue());
prefixes.add(new AbstractMap.SimpleEntry<>(node.getPrefix().getKey(), sb.toString()));
}
if (node.isSuffix()) {
sb.append(node.getSuffix().getValue());
suffixes.add(new AbstractMap.SimpleEntry<>(node.getSuffix().getKey(), sb.toString()));
prefixes.add(new AbstractMap.SimpleEntry<>(node.getPrefix().getKey(), node));
} else if (node.isSuffix()) {
suffixes.add(new AbstractMap.SimpleEntry<>(node.getSuffix().getKey(), node));
} else if (node.isMeta()) {
meta.add(node);
}
}
@@ -74,8 +68,14 @@ public class MetaInfo extends SecondarySubCommand {
Message.CHAT_META_PREFIX_NONE.send(sender, holder.getFriendlyName());
} else {
Message.CHAT_META_PREFIX_HEADER.send(sender, holder.getFriendlyName());
for (Map.Entry<Integer, String> e : prefixes) {
Message.CHAT_META_ENTRY.send(sender, e.getKey(), e.getValue());
for (Map.Entry<Integer, LocalizedNode> e : prefixes) {
String location = processLocation(e.getValue(), holder);
if (e.getValue().isServerSpecific() || e.getValue().isWorldSpecific() || !e.getValue().getContexts().isEmpty()) {
String context = Util.getNodeContextDescription(e.getValue());
Message.CHAT_META_ENTRY_WITH_CONTEXT.send(sender, e.getKey(), e.getValue().getPrefix().getValue(), location, context);
} else {
Message.CHAT_META_ENTRY.send(sender, e.getKey(), e.getValue().getPrefix().getValue(), location);
}
}
}
@@ -83,11 +83,36 @@ public class MetaInfo extends SecondarySubCommand {
Message.CHAT_META_SUFFIX_NONE.send(sender, holder.getFriendlyName());
} else {
Message.CHAT_META_SUFFIX_HEADER.send(sender, holder.getFriendlyName());
for (Map.Entry<Integer, String> e : suffixes) {
Message.CHAT_META_ENTRY.send(sender, e.getKey(), e.getValue());
for (Map.Entry<Integer, LocalizedNode> e : suffixes) {
String location = processLocation(e.getValue(), holder);
if (e.getValue().isServerSpecific() || e.getValue().isWorldSpecific() || !e.getValue().getContexts().isEmpty()) {
String context = Util.getNodeContextDescription(e.getValue());
Message.CHAT_META_ENTRY_WITH_CONTEXT.send(sender, e.getKey(), e.getValue().getSuffix().getValue(), location, context);
} else {
Message.CHAT_META_ENTRY.send(sender, e.getKey(), e.getValue().getSuffix().getValue(), location);
}
}
}
if (meta.isEmpty()) {
Message.META_NONE.send(sender, holder.getFriendlyName());
} else {
Message.META_HEADER.send(sender, holder.getFriendlyName());
for (LocalizedNode m : meta) {
String location = processLocation(m, holder);
if (m.isServerSpecific() || m.isWorldSpecific() || !m.getContexts().isEmpty()) {
String context = Util.getNodeContextDescription(m);
Message.META_ENTRY_WITH_CONTEXT.send(sender, m.getMeta().getKey(), m.getMeta().getValue(), location, context);
} else {
Message.META_ENTRY.send(sender, m.getMeta().getKey(), m.getMeta().getValue(), location);
}
}
}
return CommandResult.SUCCESS;
}
private static String processLocation(LocalizedNode node, PermissionHolder holder) {
return node.getLocation().equalsIgnoreCase(holder.getObjectName()) ? "self" : node.getLocation();
}
}
@@ -26,23 +26,27 @@ import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class MetaRemovePrefix extends SecondarySubCommand {
public class MetaRemovePrefix extends SharedSubCommand {
public MetaRemovePrefix() {
super("removeprefix", "Removes a prefix", Permission.USER_META_REMOVEPREFIX, Permission.GROUP_META_REMOVEPREFIX, Predicate.notInRange(2, 4),
super("removeprefix", "Removes a prefix", Permission.USER_META_REMOVEPREFIX, Permission.GROUP_META_REMOVEPREFIX,
Predicates.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to add the prefix at"),
Arg.create("prefix", true, "the prefix string"),
@@ -53,32 +57,14 @@ public class MetaRemovePrefix extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
final String prefix = args.get(1).replace("{SPACE}", " ");
int priority;
try {
priority = Integer.parseInt(args.get(0));
} catch (NumberFormatException e) {
Message.META_INVALID_PRIORITY.send(sender, args.get(0));
return CommandResult.INVALID_ARGS;
}
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
int priority = ArgumentUtils.handlePriority(0, args);
String prefix = ArgumentUtils.handleNodeWithoutCheck(1, args);
String server = ArgumentUtils.handleServer(2, args);
String world = ArgumentUtils.handleWorld(3, args);
// Handle bulk removal
if (prefix.equalsIgnoreCase("null")) {
String server = null;
String world = null;
if (args.size() >= 3) {
server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() != 3) {
world = args.get(3).toLowerCase();
}
}
List<Node> toRemove = new ArrayList<>();
for (Node node : holder.getNodes()) {
if (!node.isPrefix()) continue;
@@ -111,48 +97,36 @@ public class MetaRemovePrefix extends SecondarySubCommand {
Message.BULK_CHANGE_SUCCESS.send(sender, toRemove.size());
save(holder, sender, plugin);
return CommandResult.SUCCESS;
}
} else {
final String node = "prefix." + priority + "." + MetaUtils.escapeCharacters(prefix);
final String node = "prefix." + priority + "." + MetaUtils.escapeCharacters(prefix);
try {
if (args.size() >= 3) {
final String server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() == 3) {
holder.unsetPermission(node, server);
Message.REMOVEPREFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server);
LogEntry.build().actor(sender).acted(holder)
.action("meta removeprefix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
holder.unsetPermission(node, server, world);
Message.REMOVEPREFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server, world);
LogEntry.build().actor(sender).acted(holder)
.action("meta removeprefix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
try {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.unsetPermission(node);
Message.REMOVEPREFIX_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority);
LogEntry.build().actor(sender).acted(holder)
.action("meta removeprefix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
}
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_PREFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
break;
case SERVER:
holder.unsetPermission(node, server);
Message.REMOVEPREFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server);
break;
case SERVER_AND_WORLD:
holder.unsetPermission(node, server, world);
Message.REMOVEPREFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server, world);
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta removeprefix " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_PREFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
}
}
}
@@ -26,23 +26,27 @@ import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class MetaRemoveSuffix extends SecondarySubCommand {
public class MetaRemoveSuffix extends SharedSubCommand {
public MetaRemoveSuffix() {
super("removesuffix", "Removes a suffix", Permission.USER_META_REMOVESUFFIX, Permission.GROUP_META_REMOVESUFFIX, Predicate.notInRange(2, 4),
super("removesuffix", "Removes a suffix", Permission.USER_META_REMOVESUFFIX, Permission.GROUP_META_REMOVESUFFIX,
Predicates.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to add the suffix at"),
Arg.create("suffix", true, "the suffix string"),
@@ -53,32 +57,14 @@ public class MetaRemoveSuffix extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
final String suffix = args.get(1).replace("{SPACE}", " ");
int priority;
try {
priority = Integer.parseInt(args.get(0));
} catch (NumberFormatException e) {
Message.META_INVALID_PRIORITY.send(sender, args.get(0));
return CommandResult.INVALID_ARGS;
}
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
int priority = ArgumentUtils.handlePriority(0, args);
String suffix = ArgumentUtils.handleNodeWithoutCheck(1, args);
String server = ArgumentUtils.handleServer(2, args);
String world = ArgumentUtils.handleWorld(3, args);
// Handle bulk removal
if (suffix.equalsIgnoreCase("null")) {
String server = null;
String world = null;
if (args.size() >= 3) {
server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() != 3) {
world = args.get(3).toLowerCase();
}
}
List<Node> toRemove = new ArrayList<>();
for (Node node : holder.getNodes()) {
if (!node.isSuffix()) continue;
@@ -111,48 +97,36 @@ public class MetaRemoveSuffix extends SecondarySubCommand {
Message.BULK_CHANGE_SUCCESS.send(sender, toRemove.size());
save(holder, sender, plugin);
return CommandResult.SUCCESS;
}
} else {
final String node = "suffix." + priority + "." + MetaUtils.escapeCharacters(suffix);
final String node = "suffix." + priority + "." + MetaUtils.escapeCharacters(suffix);
try {
if (args.size() >= 3) {
final String server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() == 3) {
holder.unsetPermission(node, server);
Message.REMOVESUFFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server);
LogEntry.build().actor(sender).acted(holder)
.action("meta removesuffix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
holder.unsetPermission(node, server, world);
Message.REMOVESUFFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server, world);
LogEntry.build().actor(sender).acted(holder)
.action("meta removesuffix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
try {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.unsetPermission(node);
Message.REMOVESUFFIX_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority);
LogEntry.build().actor(sender).acted(holder)
.action("meta removesuffix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
}
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_SUFFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
break;
case SERVER:
holder.unsetPermission(node, server);
Message.REMOVESUFFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server);
break;
case SERVER_AND_WORLD:
holder.unsetPermission(node, server, world);
Message.REMOVESUFFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server, world);
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta removesuffix " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_SUFFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
}
}
}
@@ -26,23 +26,26 @@ import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class MetaRemoveTempPrefix extends SecondarySubCommand {
public class MetaRemoveTempPrefix extends SharedSubCommand {
public MetaRemoveTempPrefix() {
super("removetempprefix", "Removes a temporary prefix", Permission.USER_META_REMOVETEMP_PREFIX, Permission.GROUP_META_REMOVETEMP_PREFIX, Predicate.notInRange(2, 4),
super("removetempprefix", "Removes a temporary prefix", Permission.USER_META_REMOVETEMP_PREFIX, Permission.GROUP_META_REMOVETEMP_PREFIX, Predicates.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to add the prefix at"),
Arg.create("prefix", true, "the prefix string"),
@@ -53,32 +56,14 @@ public class MetaRemoveTempPrefix extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
final String prefix = args.get(1).replace("{SPACE}", " ");
int priority;
try {
priority = Integer.parseInt(args.get(0));
} catch (NumberFormatException e) {
Message.META_INVALID_PRIORITY.send(sender, args.get(0));
return CommandResult.INVALID_ARGS;
}
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
int priority = ArgumentUtils.handlePriority(0, args);
String prefix = ArgumentUtils.handleNodeWithoutCheck(1, args);
String server = ArgumentUtils.handleServer(2, args);
String world = ArgumentUtils.handleWorld(3, args);
// Handle bulk removal
if (prefix.equalsIgnoreCase("null")) {
String server = null;
String world = null;
if (args.size() >= 3) {
server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() != 3) {
world = args.get(3).toLowerCase();
}
}
List<Node> toRemove = new ArrayList<>();
for (Node node : holder.getNodes()) {
if (!node.isPrefix()) continue;
@@ -111,48 +96,36 @@ public class MetaRemoveTempPrefix extends SecondarySubCommand {
Message.BULK_CHANGE_SUCCESS.send(sender, toRemove.size());
save(holder, sender, plugin);
return CommandResult.SUCCESS;
}
} else {
final String node = "prefix." + priority + "." + MetaUtils.escapeCharacters(prefix);
final String node = "prefix." + priority + "." + MetaUtils.escapeCharacters(prefix);
try {
if (args.size() >= 3) {
final String server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() == 3) {
holder.unsetPermission(node, server, true);
Message.REMOVE_TEMP_PREFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server);
LogEntry.build().actor(sender).acted(holder)
.action("meta removetempprefix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
holder.unsetPermission(node, server, world, true);
Message.REMOVE_TEMP_PREFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server, world);
LogEntry.build().actor(sender).acted(holder)
.action("meta removetempprefix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
try {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.unsetPermission(node, true);
Message.REMOVE_TEMP_PREFIX_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority);
LogEntry.build().actor(sender).acted(holder)
.action("meta removetempprefix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
}
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_PREFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
break;
case SERVER:
holder.unsetPermission(node, server, true);
Message.REMOVE_TEMP_PREFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server);
break;
case SERVER_AND_WORLD:
holder.unsetPermission(node, server, world, true);
Message.REMOVE_TEMP_PREFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority, server, world);
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta removetempprefix " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_PREFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
}
}
}
@@ -26,23 +26,26 @@ import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class MetaRemoveTempSuffix extends SecondarySubCommand {
public class MetaRemoveTempSuffix extends SharedSubCommand {
public MetaRemoveTempSuffix() {
super("removetempsuffix", "Removes a temporary suffix", Permission.USER_META_REMOVETEMP_SUFFIX, Permission.GROUP_META_REMOVETEMP_SUFFIX, Predicate.notInRange(2, 4),
super("removetempsuffix", "Removes a temporary suffix", Permission.USER_META_REMOVETEMP_SUFFIX, Permission.GROUP_META_REMOVETEMP_SUFFIX, Predicates.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to add the suffix at"),
Arg.create("suffix", true, "the suffix string"),
@@ -53,32 +56,14 @@ public class MetaRemoveTempSuffix extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
final String suffix = args.get(1).replace("{SPACE}", " ");
int priority;
try {
priority = Integer.parseInt(args.get(0));
} catch (NumberFormatException e) {
Message.META_INVALID_PRIORITY.send(sender, args.get(0));
return CommandResult.INVALID_ARGS;
}
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
int priority = ArgumentUtils.handlePriority(0, args);
String suffix = ArgumentUtils.handleNodeWithoutCheck(1, args);
String server = ArgumentUtils.handleServer(2, args);
String world = ArgumentUtils.handleWorld(3, args);
// Handle bulk removal
if (suffix.equalsIgnoreCase("null")) {
String server = null;
String world = null;
if (args.size() >= 3) {
server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() != 3) {
world = args.get(3).toLowerCase();
}
}
List<Node> toRemove = new ArrayList<>();
for (Node node : holder.getNodes()) {
if (!node.isSuffix()) continue;
@@ -111,48 +96,36 @@ public class MetaRemoveTempSuffix extends SecondarySubCommand {
Message.BULK_CHANGE_SUCCESS.send(sender, toRemove.size());
save(holder, sender, plugin);
return CommandResult.SUCCESS;
}
} else {
final String node = "suffix." + priority + "." + MetaUtils.escapeCharacters(suffix);
final String node = "suffix." + priority + "." + MetaUtils.escapeCharacters(suffix);
try {
if (args.size() >= 3) {
final String server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() == 3) {
holder.unsetPermission(node, server, true);
Message.REMOVE_TEMP_SUFFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server);
LogEntry.build().actor(sender).acted(holder)
.action("meta removetempsuffix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
holder.unsetPermission(node, server, world, true);
Message.REMOVE_TEMP_SUFFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server, world);
LogEntry.build().actor(sender).acted(holder)
.action("meta removetempsuffix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
try {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.unsetPermission(node, true);
Message.REMOVE_TEMP_SUFFIX_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority);
LogEntry.build().actor(sender).acted(holder)
.action("meta removetempsuffix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
}
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_SUFFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
break;
case SERVER:
holder.unsetPermission(node, server, true);
Message.REMOVE_TEMP_SUFFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server);
break;
case SERVER_AND_WORLD:
holder.unsetPermission(node, server, world, true);
Message.REMOVE_TEMP_SUFFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority, server, world);
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta removetempsuffix " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_SUFFIX.send(sender, holder.getFriendlyName());
return CommandResult.STATE_ERROR;
}
}
}
@@ -22,26 +22,29 @@
package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.Node;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import java.util.List;
import java.util.stream.Collectors;
public class MetaSet extends SecondarySubCommand {
public class MetaSet extends SharedSubCommand {
public MetaSet() {
super("set", "Sets a meta value", Permission.USER_META_SET, Permission.GROUP_META_SET, Predicate.notInRange(2, 4),
super("set", "Sets a meta value", Permission.USER_META_SET, Permission.GROUP_META_SET, Predicates.notInRange(2, 4),
Arg.list(
Arg.create("key", true, "the key to set"),
Arg.create("value", true, "the value to set"),
@@ -52,27 +55,14 @@ public class MetaSet extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
String key = MetaUtils.escapeCharacters(args.get(0));
String value = MetaUtils.escapeCharacters(args.get(1));
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
String key = args.get(0);
String value = args.get(1);
String node = "meta." + key + "." + value;
String server = null;
String world = null;
String server = ArgumentUtils.handleServer(2, args);
String world = ArgumentUtils.handleWorld(3, args);
if (args.size() >= 3) {
server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() != 3) {
world = args.get(3).toLowerCase();
}
}
me.lucko.luckperms.api.Node n = new Node.Builder(node).setServer(server).setWorld(world).build();
Node n = NodeFactory.makeMetaNode(key, value).setServer(server).setWorld(world).build();
if (holder.hasPermission(n).asBoolean()) {
Message.ALREADY_HAS_META.send(sender, holder.getFriendlyName());
@@ -85,25 +75,22 @@ public class MetaSet extends SecondarySubCommand {
holder.setPermission(n);
} catch (ObjectAlreadyHasException ignored) {}
if (server == null) {
Message.SET_META_SUCCESS.send(sender, key, value, holder.getFriendlyName());
LogEntry.build().actor(sender).acted(holder)
.action("meta set " + key + " " + value)
.build().submit(plugin, sender);
} else {
if (world == null) {
switch (ContextHelper.determine(server, world)) {
case NONE:
Message.SET_META_SUCCESS.send(sender, key, value, holder.getFriendlyName());
break;
case SERVER:
Message.SET_META_SERVER_SUCCESS.send(sender, key, value, holder.getFriendlyName(), server);
LogEntry.build().actor(sender).acted(holder)
.action("meta set " + key + " " + value + " " + server)
.build().submit(plugin, sender);
} else {
break;
case SERVER_AND_WORLD:
Message.SET_META_SERVER_WORLD_SUCCESS.send(sender, key, value, holder.getFriendlyName(), server, world);
LogEntry.build().actor(sender).acted(holder)
.action("meta set " + key + " " + value + " " + server + " " + world)
.build().submit(plugin, sender);
}
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta set " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
}
@@ -22,27 +22,30 @@
package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.Node;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import java.util.List;
import java.util.stream.Collectors;
public class MetaSetTemp extends SecondarySubCommand {
public class MetaSetTemp extends SharedSubCommand {
public MetaSetTemp() {
super("settemp", "Sets a meta value temporarily", Permission.USER_META_SETTEMP, Permission.GROUP_META_SETTEMP, Predicate.notInRange(3, 5),
super("settemp", "Sets a meta value temporarily", Permission.USER_META_SETTEMP, Permission.GROUP_META_SETTEMP, Predicates.notInRange(3, 5),
Arg.list(
Arg.create("key", true, "the key to set"),
Arg.create("value", true, "the value to set"),
@@ -54,44 +57,14 @@ public class MetaSetTemp extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
long duration;
try {
duration = Long.parseLong(args.get(2));
} catch (NumberFormatException e) {
try {
duration = DateUtil.parseDateDiff(args.get(2), true);
} catch (DateUtil.IllegalDateException e1) {
Message.ILLEGAL_DATE_ERROR.send(sender, args.get(2));
return CommandResult.INVALID_ARGS;
}
}
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
String key = args.get(0);
String value = args.get(1);
long duration = ArgumentUtils.handleDuration(2, args);
String server = ArgumentUtils.handleServer(3, args);
String world = ArgumentUtils.handleWorld(4, args);
if (DateUtil.shouldExpire(duration)) {
Message.PAST_DATE_ERROR.send(sender);
return CommandResult.INVALID_ARGS;
}
String key = MetaUtils.escapeCharacters(args.get(0));
String value = MetaUtils.escapeCharacters(args.get(1));
String node = "meta." + key + "." + value;
String server = null;
String world = null;
if (args.size() >= 3) {
server = args.get(2).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() != 3) {
world = args.get(3).toLowerCase();
}
}
me.lucko.luckperms.api.Node n = new Node.Builder(node).setServer(server).setWorld(world).setExpiry(duration).build();
Node n = NodeFactory.makeMetaNode(key, value).setServer(server).setWorld(world).setExpiry(duration).build();
if (holder.hasPermission(n).asBoolean()) {
Message.ALREADY_HAS_META.send(sender, holder.getFriendlyName());
@@ -104,25 +77,22 @@ public class MetaSetTemp extends SecondarySubCommand {
holder.setPermission(n);
} catch (ObjectAlreadyHasException ignored) {}
if (server == null) {
Message.SET_META_TEMP_SUCCESS.send(sender, key, value, holder.getFriendlyName(), DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(holder)
.action("meta settemp " + key + " " + value + " " + duration)
.build().submit(plugin, sender);
} else {
if (world == null) {
switch (ContextHelper.determine(server, world)) {
case NONE:
Message.SET_META_TEMP_SUCCESS.send(sender, key, value, holder.getFriendlyName(), DateUtil.formatDateDiff(duration));
break;
case SERVER:
Message.SET_META_TEMP_SERVER_SUCCESS.send(sender, key, value, holder.getFriendlyName(), server, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(holder)
.action("meta settemp " + key + " " + value + " " + duration + " " + server)
.build().submit(plugin, sender);
} else {
break;
case SERVER_AND_WORLD:
Message.SET_META_TEMP_SERVER_WORLD_SUCCESS.send(sender, key, value, holder.getFriendlyName(), server, world, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(holder)
.action("meta settemp " + key + " " + value + " " + duration + " " + server + " " + world)
.build().submit(plugin, sender);
}
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta settemp " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
}
@@ -22,25 +22,27 @@
package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.List;
import java.util.stream.Collectors;
public class MetaUnset extends SecondarySubCommand {
public class MetaUnset extends SharedSubCommand {
public MetaUnset() {
super("unset", "Unsets a meta value", Permission.USER_META_UNSET, Permission.GROUP_META_UNSET, Predicate.notInRange(1, 3),
super("unset", "Unsets a meta value", Permission.USER_META_UNSET, Permission.GROUP_META_UNSET,
Predicates.notInRange(1, 3),
Arg.list(
Arg.create("key", true, "the key to unset"),
Arg.create("server", false, "the server to remove the meta pair on"),
@@ -50,38 +52,27 @@ public class MetaUnset extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
String key = MetaUtils.escapeCharacters(args.get(0));
String server = null;
String world = null;
if (args.size() >= 2) {
server = args.get(1).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() != 2) {
world = args.get(2).toLowerCase();
}
}
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
String key = args.get(0);
String server = ArgumentUtils.handleServer(1, args);
String world = ArgumentUtils.handleWorld(2, args);
holder.clearMetaKeys(key, server, world, false);
if (server == null) {
Message.UNSET_META_SUCCESS.send(sender, key, holder.getFriendlyName());
} else {
if (world == null) {
switch (ContextHelper.determine(server, world)) {
case NONE:
Message.UNSET_META_SUCCESS.send(sender, key, holder.getFriendlyName());
break;
case SERVER:
Message.UNSET_META_SERVER_SUCCESS.send(sender, key, holder.getFriendlyName(), server);
} else {
break;
case SERVER_AND_WORLD:
Message.UNSET_META_SERVER_WORLD_SUCCESS.send(sender, key, holder.getFriendlyName(), server, world);
}
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta unset " + args.stream().collect(Collectors.joining(" ")))
.action("meta unset " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
@@ -22,25 +22,27 @@
package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.List;
import java.util.stream.Collectors;
public class MetaUnsetTemp extends SecondarySubCommand {
public class MetaUnsetTemp extends SharedSubCommand {
public MetaUnsetTemp() {
super("unsettemp", "Unsets a temporary meta value", Permission.USER_META_UNSETTEMP, Permission.GROUP_META_UNSETTEMP, Predicate.notInRange(1, 3),
super("unsettemp", "Unsets a temporary meta value", Permission.USER_META_UNSETTEMP, Permission.GROUP_META_UNSETTEMP,
Predicates.notInRange(1, 3),
Arg.list(
Arg.create("key", true, "the key to unset"),
Arg.create("server", false, "the server to remove the meta pair on"),
@@ -50,38 +52,27 @@ public class MetaUnsetTemp extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
String key = MetaUtils.escapeCharacters(args.get(0));
String server = null;
String world = null;
if (args.size() >= 2) {
server = args.get(1).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() != 2) {
world = args.get(2).toLowerCase();
}
}
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
String key = args.get(0);
String server = ArgumentUtils.handleServer(1, args);
String world = ArgumentUtils.handleWorld(2, args);
holder.clearMetaKeys(key, server, world, true);
if (server == null) {
Message.UNSET_META_TEMP_SUCCESS.send(sender, key, holder.getFriendlyName());
} else {
if (world == null) {
switch (ContextHelper.determine(server, world)) {
case NONE:
Message.UNSET_META_TEMP_SUCCESS.send(sender, key, holder.getFriendlyName());
break;
case SERVER:
Message.UNSET_META_TEMP_SERVER_SUCCESS.send(sender, key, holder.getFriendlyName(), server);
} else {
break;
case SERVER_AND_WORLD:
Message.UNSET_META_TEMP_SERVER_WORLD_SUCCESS.send(sender, key, holder.getFriendlyName(), server, world);
}
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("meta unsettemp " + args.stream().collect(Collectors.joining(" ")))
.action("meta unsettemp " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
@@ -0,0 +1,84 @@
/*
* 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.commands.generic.other;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.LuckPermsPlugin;
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.commands.utils.Util;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class HolderShowTracks<T extends PermissionHolder> extends SubCommand<T> {
public HolderShowTracks(boolean user) {
super("showtracks", "Lists the tracks that the object is on",
user ? Permission.USER_SHOWTRACKS : Permission.GROUP_SHOWTRACKS, Predicates.alwaysFalse(), null);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, T holder, List<String> args, String label) throws CommandException {
if (!plugin.getStorage().loadAllTracks().join()) {
Message.TRACKS_LOAD_ERROR.send(sender);
return CommandResult.LOADING_ERROR;
}
Set<Node> nodes = holder.getNodes().stream()
.filter(Node::isGroupNode)
.filter(Node::isPermanent)
.collect(Collectors.toSet());
StringBuilder sb = new StringBuilder();
for (Node node : nodes) {
String name = node.getGroupName();
plugin.getTrackManager().getAll().values().stream()
.filter(t -> t.containsGroup(name))
.forEach(t -> sb.append("&a")
.append(t.getName())
.append(": ")
.append(Util.listToArrowSep(t.getGroups(), name))
.append(Util.getNodeContextDescription(node))
.append("\n")
);
}
if (sb.length() == 0) {
Message.LIST_TRACKS_EMPTY.send(sender, holder.getFriendlyName());
return CommandResult.SUCCESS;
} else {
sb.deleteCharAt(sb.length() - 1);
Message.LIST_TRACKS.send(sender, holder.getFriendlyName(), sb.toString());
return CommandResult.SUCCESS;
}
}
}
@@ -23,14 +23,15 @@
package me.lucko.luckperms.common.commands.generic.parent;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.common.commands.generic.SecondaryMainCommand;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedMainCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.core.PermissionHolder;
public class CommandParent<T extends PermissionHolder> extends SecondaryMainCommand<T> {
public class CommandParent<T extends PermissionHolder> extends SharedMainCommand<T> {
public CommandParent(boolean user) {
super("Parent", "Edit inheritances", user, ImmutableList.<SecondarySubCommand>builder()
super("Parent", "Edit inheritances", user, ImmutableList.<SharedSubCommand>builder()
.add(new ParentInfo())
.add(new ParentSet())
.add(new ParentAdd())
.add(new ParentRemove())
.add(new ParentAddTemp())
@@ -24,26 +24,29 @@ package me.lucko.luckperms.common.commands.generic.parent;
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.Predicate;
import me.lucko.luckperms.common.commands.Sender;
import me.lucko.luckperms.common.commands.generic.SecondarySubCommand;
import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import java.util.List;
import java.util.stream.Collectors;
import static me.lucko.luckperms.common.commands.SubCommand.getGroupTabComplete;
public class ParentAdd extends SecondarySubCommand {
public class ParentAdd extends SharedSubCommand {
public ParentAdd() {
super("add", "Sets another group for the object to inherit permissions from",
Permission.USER_PARENT_ADD, Permission.GROUP_PARENT_ADD, Predicate.notInRange(1, 3),
super("add", "Sets another group for the object to inherit permissions from", Permission.USER_PARENT_ADD,
Permission.GROUP_PARENT_ADD, Predicates.notInRange(1, 3),
Arg.list(
Arg.create("group", true, "the group to inherit from"),
Arg.create("server", false, "the server to inherit the group on"),
@@ -53,15 +56,12 @@ public class ParentAdd extends SecondarySubCommand {
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) {
String groupName = args.get(0).toLowerCase();
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
String groupName = ArgumentUtils.handleName(0, args);
String server = ArgumentUtils.handleServer(1, args);
String world = ArgumentUtils.handleWorld(2, args);
if (ArgumentChecker.checkNode(groupName)) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (!plugin.getDatastore().loadGroup(groupName).getUnchecked()) {
if (!plugin.getStorage().loadGroup(groupName).join()) {
Message.GROUP_DOES_NOT_EXIST.send(sender);
return CommandResult.INVALID_ARGS;
}
@@ -73,38 +73,28 @@ public class ParentAdd extends SecondarySubCommand {
}
try {
if (args.size() >= 2) {
final String server = args.get(1).toLowerCase();
if (ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() == 2) {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.setInheritGroup(group);
Message.SET_INHERIT_SUCCESS.send(sender, holder.getFriendlyName(), group.getDisplayName());
break;
case SERVER:
holder.setInheritGroup(group, server);
Message.SET_INHERIT_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), group.getDisplayName(), server);
LogEntry.build().actor(sender).acted(holder)
.action("parent add " + group.getName() + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(2).toLowerCase();
break;
case SERVER_AND_WORLD:
holder.setInheritGroup(group, server, world);
Message.SET_INHERIT_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), group.getDisplayName(), server, world);
LogEntry.build().actor(sender).acted(holder)
.action("parent add " + group.getName() + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
holder.setInheritGroup(group);
Message.SET_INHERIT_SUCCESS.send(sender, holder.getFriendlyName(), group.getDisplayName());
LogEntry.build().actor(sender).acted(holder)
.action("parent add " + group.getName())
.build().submit(plugin, sender);
break;
}
LogEntry.build().actor(sender).acted(holder)
.action("parent add " + args.stream().map(ArgumentUtils.WRAPPER).collect(Collectors.joining(" ")))
.build().submit(plugin, sender);
save(holder, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_INHERITS.send(sender, holder.getFriendlyName(), group.getDisplayName());
return CommandResult.STATE_ERROR;
Loaded 100 of 264 files, more files were not shown because too many files have changed in this diff. Show more