Compare commits

...
128 Commits
Author SHA1 Message Date
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
Luck 383276f47a Refactor contexts, expose cached data in the API & release 2.13 2016-10-23 16:46:53 +01:00
Luck 33c78e4a17 Use LoadingCache instead of a regular map + more datastore fixes 2016-10-22 20:39:26 +01:00
Luck 55a0de7899 Lower buffer time to 1 second. Should resolve any issues with changes being overridden. (related: #32) 2016-10-22 18:52:51 +01:00
Luck 6b3aab66bf Fix some #saveX methods being waited for, when they can just be ran async 2016-10-22 09:35:11 +01:00
Luck 77e70ef8d3 Fix deadlocks caused by waiting for async operations to complete before the scheduler has started 2016-10-22 09:21:30 +01:00
Luck 9b92143501 prevent logins until the plugin has started 2016-10-22 00:07:30 +01:00
Luck 87f94f6b8f add started value to bukkit plugin 2016-10-22 00:05:33 +01:00
Luck 5d955e77b6 Make the max pool size configurable 2016-10-21 22:22:06 +01:00
Luck 270a276b98 Refactor SQL storage to not hold onto connections for as long 2016-10-21 22:07:14 +01:00
Luck be7d914e39 Finish the buffering refactor - still WIP. Towards #32 2016-10-21 18:34:53 +01:00
Luck 37fc00cce8 Refactoring storage - WIP. Towards #32 2016-10-20 21:55:34 +01:00
Luck 0d515abadb Cleanup some bad code in SQLDatastore. Might help #32 2016-10-19 23:30:30 +01:00
Luck daef01194e Shade MySQL connector into Sponge jar. Resolves #31 2016-10-19 22:23:43 +01:00
Luck 258bf1cc41 small cleanup 2016-10-19 20:57:53 +01:00
Luck ce3d7829d7 Update internal permissions to match the new command layouts 2016-10-19 20:14:16 +01:00
Luck c66a01c1a6 Fix temporary permission expirations never persisting. Fixes #30 2016-10-19 17:37:26 +01:00
Luck d113a92ce5 Cleanup permission calculation 2016-10-18 20:48:59 +01:00
Luck 7b655d12df Add set-primary-group option to the default assignments 2016-10-17 18:23:41 +01:00
Luck a4c872f1e8 Fix per-world permissions not working until a user switches worlds 2016-10-17 17:10:02 +01:00
Luck 0e7d9bf9c1 Bump hikari version 2016-10-16 21:05:25 +01:00
Luck 6252a5bc75 Fix invalid property 2016-10-16 20:53:12 +01:00
Luck e4e80c9c31 Update to SpongeAPI 5.0.0 release 2016-10-16 18:13:55 +01:00
Luck 165c5610c3 Add extra Hikari flag 2016-10-16 17:24:02 +01:00
Luck 13fbc7dd39 Implement default assignment system (#25) 2016-10-16 13:58:57 +01:00
Luck 02a75fc32a Reimplement autoop on Bukkit & other misc fixes 2016-10-15 21:04:04 +01:00
Luck 699c4d107b Swap the javaassist maven plugin with a better method 2016-10-15 08:59:49 +01:00
Luck e4810302e1 Implement meta / Sponge option commands & fix meta caching system. Fully resolves #23 2016-10-14 22:49:32 +01:00
Luck 73f10cad66 Make the recent command changes backwards compatible 2016-10-14 20:42:00 +01:00
Luck f1d670dc46 refactor permission commands 2016-10-14 19:55:22 +01:00
Luck 045539c752 refactor inheritance commands 2016-10-14 19:19:57 +01:00
Luck 782c09b686 Refine bulk group edit primary group check 2016-10-13 21:29:30 +01:00
Luck 6109718c67 Cleanup some remaining TODOs 2016-10-13 21:16:34 +01:00
Luck cd758d7e48 Bump minor version 2016-10-13 20:40:09 +01:00
Luck fcb0fcadeb Fix StackOverflowException 2016-10-13 20:36:08 +01:00
Luck 26fb506560 Reorganize packages 2016-10-13 20:07:10 +01:00
Luck b6c4239322 Fix NPE 2016-10-13 19:43:48 +01:00
Luck 74f9283f18 Silence exception on #giveDefaultIfNeeded. Resolves #26 2016-10-13 19:25:31 +01:00
Luck 60e6ae6e23 Fix Sponge implementation, remove standalone module 2016-10-13 19:13:34 +01:00
Luck 83d9229295 Refactor caching system (WIP) - still working towards #23 2016-10-12 21:57:57 +01:00
Luck e079b0f3ed Fix meta command showing when a user doesn't have permission to use it 2016-10-11 21:17:04 +01:00
Luck d433a5461d Refactor meta commands, working towards #23 2016-10-11 21:12:10 +01:00
Luck 2c43f6bf21 Fix global permissions and groups sometimes not applying 2016-10-11 19:31:55 +01:00
Luck ac57509a29 Fix prefix/suffix priorities being ignored 2016-10-11 19:31:26 +01:00
Luck c5ce655cf6 Add Vault chat debug messages 2016-10-11 19:06:18 +01:00
Luck 9fe05efb4e Don't force the default group 2016-10-11 18:54:42 +01:00
Luck dcf207f5e5 Fix exception, resolves #20 and #22 2016-10-10 22:39:24 +01:00
Luck 11facab71c Fix NPE, resolves #19 2016-10-10 22:26:39 +01:00
Luck 5b4975f34c Implement persisting subjects (+ defaults) 2016-10-10 18:58:43 +01:00
Luck 069e535f1a Avoid odd behavior where Sponge prevents User subjects from being GCed 2016-10-09 21:34:05 +01:00
Luck 1eb053447e Make refresh calls in SpongeListener run async 2016-10-09 20:49:17 +01:00
Luck 93c7c06b2d Cleanup some Sponge subject classes 2016-10-09 13:14:58 +01:00
Luck b0085bc1e1 Update readme 2016-10-09 10:58:14 +01:00
Luck 9133951446 I'm dumb 2016-10-08 16:45:18 +01:00
Luck 7853d4686a Fix NPE with LPPermissibles & refreshing users 2016-10-08 16:43:57 +01:00
Luck ed5892eb56 add option to ignore vault world parameters 2016-10-08 15:01:54 +01:00
Luck 687804de2c small change to BukkitConfig 2016-10-08 09:05:48 +01:00
Luck 9d166041ab Account for inheritance and wildcards in SimpleSubject 2016-10-07 18:11:59 +01:00
Luck 924041bff4 Add server and world args to clear command, and add clearmeta command 2016-10-06 21:23:27 +01:00
Luck e9216d3e0f Allow the prefix to be modified by the lang file 2016-10-06 19:54:52 +01:00
Luck db8f1bca66 Fix API javadoc & fix Bukkit legacy build 2016-10-06 17:21:04 +01:00
355 changed files with 17588 additions and 13673 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*
+6 -3
View File
@@ -14,13 +14,16 @@ LuckPerms is an advanced permissions implementation aiming to be a flexible, per
* [Sponge Plugin Page](https://forums.spongepowered.org/t/luckperms-an-advanced-permissions-system/14274 "Sponge Plugin Page")
## LuckPerms vs Other Plugins
### Bukkit
![alt text](https://static.lucko.me/luckperms-compare-copy.png "Feature comparison")
_Features checked on 23rd Aug 2016. If you find any inaccuracies, please do let me know. I tried to be as fair as possible, and copy all major features from the respective plugin pages._
### 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
See LICENSE.md.
LuckPerms is licensed under the permissive MIT license. See LICENSE.md for more info.
## Thanks to:
[![JProfiler](https://www.ej-technologies.com/images/product_banners/jprofiler_large.png)](http://www.ej-technologies.com/products/jprofiler/overview.html)
Thanks to ej-technologies for granting LuckPerms an open source licence to their [java profiling software](http://www.ej-technologies.com/products/jprofiler/overview.html "Java Profiler").
Thanks to ej-technologies for granting LuckPerms an open source licence to their [Java Profiling Software](http://www.ej-technologies.com/products/jprofiler/overview.html "Java Profiler").
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.11-SNAPSHOT</version>
<version>2.14-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -22,9 +22,8 @@
package me.lucko.luckperms.api;
import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.api.context.ContextSet;
import java.util.Collections;
import java.util.Map;
/**
@@ -41,32 +40,61 @@ public class Contexts {
* @return a context that will not apply any filters
*/
public static Contexts allowAll() {
return new Contexts(Collections.emptyMap(), true, true, true, true, true);
return new Contexts(ContextSet.empty(), true, true, true, true, true, true);
}
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups);
public static Contexts of(ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
}
public Contexts(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
public Contexts(ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
if (context == null) {
throw new NullPointerException("context");
}
this.context = ImmutableMap.copyOf(context);
this.context = context.makeImmutable();
this.includeGlobal = includeGlobal;
this.includeGlobalWorld = includeGlobalWorld;
this.applyGroups = applyGroups;
this.applyGlobalGroups = applyGlobalGroups;
this.applyGlobalWorldGroups = applyGlobalWorldGroups;
this.op = op;
}
@SuppressWarnings("deprecation")
@Deprecated
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups);
}
@SuppressWarnings("deprecation")
@Deprecated
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
}
@Deprecated
public Contexts(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
this(context == null ? null : ContextSet.fromMap(context), includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
}
@SuppressWarnings("deprecation")
@Deprecated
public Contexts(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
this(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, false);
}
/**
* The contexts that apply for this lookup
*
* The keys for servers and worlds are defined as static values.
*/
private final Map<String, String> context;
private final ContextSet context;
/**
* The mode to parse defaults on Bukkit
* @since 2.12
*/
private final boolean op;
/**
* If global or non server specific nodes should be applied
@@ -95,12 +123,31 @@ public class Contexts {
/**
* Gets the contexts that apply for this lookup
* @return an immutable map of context key value pairs
* @return an immutable set of context key value pairs
* @since 2.13
*/
public Map<String, String> getContext() {
public ContextSet getContexts() {
return this.context;
}
/**
* Gets the contexts that apply for this lookup
* @return an immutable map of context key value pairs
* @deprecated in favour of {@link #getContexts()}
*/
@Deprecated
public Map<String, String> getContext() {
return this.context.toMap();
}
/**
* Gets if OP defaults should be included
* @return true if op defaults should be included
*/
public boolean isOp() {
return this.op;
}
/**
* Gets if global or non server specific nodes should be applied
* @return true if global or non server specific nodes should be applied
@@ -143,7 +190,8 @@ public class Contexts {
public String toString() {
return "Contexts(" +
"context=" + this.getContext() + ", " +
"context=" + this.getContexts() + ", " +
"op=" + this.isOp() + ", " +
"includeGlobal=" + this.isIncludeGlobal() + ", " +
"includeGlobalWorld=" + this.isIncludeGlobalWorld() + ", " +
"applyGroups=" + this.isApplyGroups() + ", " +
@@ -152,4 +200,49 @@ public class Contexts {
")";
}
/*
* Ugly auto-generated lombok code
*/
/**
* Check for equality
* @param o the other
* @return true if equal
* @since 2.12
*/
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Contexts)) return false;
final Contexts other = (Contexts) o;
final Object this$context = this.getContexts();
final Object other$context = other.getContexts();
if (this$context == null ? other$context != null : !this$context.equals(other$context)) return false;
if (this.isOp() != other.isOp()) return false;
if (this.isIncludeGlobal() != other.isIncludeGlobal()) return false;
if (this.isIncludeGlobalWorld() != other.isIncludeGlobalWorld()) return false;
if (this.isApplyGroups() != other.isApplyGroups()) return false;
if (this.isApplyGlobalGroups() != other.isApplyGlobalGroups()) return false;
if (this.isApplyGlobalWorldGroups() != other.isApplyGlobalWorldGroups()) return false;
return true;
}
/**
* Gets the hashcode
* @return the hashcode
* @since 2.12
*/
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $context = this.getContexts();
result = result * PRIME + ($context == null ? 43 : $context.hashCode());
result = result * PRIME + (this.isOp() ? 79 : 97);
result = result * PRIME + (this.isIncludeGlobal() ? 79 : 97);
result = result * PRIME + (this.isIncludeGlobalWorld() ? 79 : 97);
result = result * PRIME + (this.isApplyGroups() ? 79 : 97);
result = result * PRIME + (this.isApplyGlobalGroups() ? 79 : 97);
result = result * PRIME + (this.isApplyGlobalWorldGroups() ? 79 : 97);
return result;
}
}
@@ -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();
@@ -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();
}
@@ -258,7 +258,7 @@ public class MetaUtils {
int priority = Integer.MIN_VALUE;
String meta = null;
for (Node n : holder.getAllNodes()) {
for (Node n : holder.getAllNodes(Contexts.allowAll())) {
if (!n.getValue()) {
continue;
}
@@ -22,10 +22,9 @@
package me.lucko.luckperms.api;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import me.lucko.luckperms.api.context.ContextSet;
import java.util.*;
/**
* Represents an immutable node object
@@ -109,15 +108,40 @@ public interface Node extends Map.Entry<String, Boolean> {
* @param context the context key value pairs
* @param worldAndServer if world and server contexts should be checked
* @return true if the node should apply
* @since 2.13
*/
boolean shouldApplyWithContext(Map<String, String> context, boolean worldAndServer);
boolean shouldApplyWithContext(ContextSet context, boolean worldAndServer);
/**
* If this node should apply in the given context
* @param context the context key value pairs
* @return true if the node should apply
* @since 2.13
*/
boolean shouldApplyWithContext(Map<String, String> context);
boolean shouldApplyWithContext(ContextSet context);
/**
* If this node should apply in the given context
* @param context the context key value pairs
* @param worldAndServer if world and server contexts should be checked
* @return true if the node should apply
* @deprecated in favour of {@link #shouldApplyWithContext(ContextSet, boolean)}
*/
@Deprecated
default boolean shouldApplyWithContext(Map<String, String> context, boolean worldAndServer) {
return shouldApplyWithContext(ContextSet.fromMap(context), worldAndServer);
}
/**
* If this node should apply in the given context
* @param context the context key value pairs
* @return true if the node should apply
* @deprecated in favour of {@link #shouldApplyWithContext(ContextSet)}
*/
@Deprecated
default boolean shouldApplyWithContext(Map<String, String> context) {
return shouldApplyWithContext(ContextSet.fromMap(context));
}
/**
* Similar to {@link #shouldApplyOnServer(String, boolean, boolean)}, except this method accepts a List
@@ -186,8 +210,18 @@ public interface Node extends Map.Entry<String, Boolean> {
/**
* @return the extra contexts required for this node to apply
* @deprecated in favour of {@link #getContexts()}
*/
Map<String, String> getExtraContexts();
@Deprecated
default Map<String, String> getExtraContexts() {
return getContexts().toMap();
}
/**
* @return the extra contexts required for this node to apply
* @since 2.13
*/
ContextSet getContexts();
/**
* Converts this node into a serialized form
@@ -302,7 +336,9 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder setServer(String server) throws IllegalArgumentException;
Builder withExtraContext(String key, String value);
Builder withExtraContext(Map<String, String> map);
Builder withExtraContext(Set<Map.Entry<String, String>> context);
Builder withExtraContext(Map.Entry<String, String> entry);
Builder withExtraContext(ContextSet set);
Node build();
}
@@ -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 & 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);
}
@@ -22,10 +22,12 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
/**
@@ -64,6 +66,13 @@ public interface User extends PermissionHolder {
*/
void refreshPermissions();
/**
* Gets the user's {@link UserData} cache, if they have one setup.
* @return an optional, possibly containing the user's cached lookup data.
* @since 2.13
*/
Optional<UserData> getUserDataCache();
/**
* Check to see if the user is a member of a group
* @param group The group to check membership of
@@ -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.
*/
@@ -0,0 +1,64 @@
/*
* 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.caching;
import java.util.Map;
import java.util.SortedMap;
/**
* Holds cached Meta lookup data for a specific set of contexts
* @since 2.13
*/
public interface MetaData {
/**
* Gets an immutable copy of the meta this user has
* @return an immutable map of meta
*/
Map<String, String> getMeta();
/**
* Gets an immutable sorted map of all of the prefixes the user has, whereby the first value is the highest priority prefix.
* @return a sorted map of prefixes
*/
SortedMap<Integer, String> getPrefixes();
/**
* Gets an immutable sorted map of all of the suffixes the user has, whereby the first value is the highest priority suffix.
* @return a sorted map of suffixes
*/
SortedMap<Integer, String> getSuffixes();
/**
* Gets the user's highest priority prefix, or null if the user has no prefixes
* @return a prefix string, or null
*/
String getPrefix();
/**
* Gets the user's highest priority suffix, or null if the user has no suffixes
* @return a suffix string, or null
*/
String getSuffix();
}
@@ -20,33 +20,36 @@
* SOFTWARE.
*/
package me.lucko.luckperms.tracks;
package me.lucko.luckperms.api.caching;
import me.lucko.luckperms.utils.AbstractManager;
import me.lucko.luckperms.api.Tristate;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.Map;
public class TrackManager extends AbstractManager<String, Track> {
/**
* Holds cached Permission lookup data for a specific set of contexts
* @since 2.13
*/
public interface PermissionData {
/**
* Returns a set of tracks that contain at least one of the groups from the Set provided
* @param group the group to filter by
* @return a set of tracks that the groups could be a member of
* Gets a permission value for the given permission node
* @param permission the permission node
* @return a tristate result
* @throws NullPointerException if permission is null
*/
public Set<Track> getApplicableTracks(String group) {
return getAll().values().stream()
.filter(t -> t.containsGroup(group))
.collect(Collectors.toSet());
}
Tristate getPermissionValue(String permission);
/**
* Makes a new track object
* @param name The name of the track
* @return a new {@link Track} object
* Invalidates the underlying permission calculator cache.
* Can be called to allow for an update in defaults.
*/
@Override
public Track apply(String name) {
return new Track(name);
}
void invalidateCache();
/**
* Gets an immutable copy of the permission map backing the permission calculator
* @return an immutable set of permissions
*/
Map<String, Boolean> getImmutableBacking();
}
@@ -0,0 +1,119 @@
/*
* 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.caching;
import me.lucko.luckperms.api.Contexts;
import java.util.Set;
/**
* Holds cached permission and meta lookup data for a {@link me.lucko.luckperms.api.User}.
* Data is only likely to be available for online users. All calls will account for inheritance, as well as any
* default data provided by the platform. This calls are heavily cached and are therefore fast.
*
* @since 2.13
*/
public interface UserData {
/**
* Gets PermissionData from the cache, given a specified context.
* If the data is not cached, it is calculated. Therefore, this call could be costly.
* @param contexts the contexts to get the permission data in
* @return a permission data instance
* @throws NullPointerException if contexts is null
*/
PermissionData getPermissionData(Contexts contexts);
/**
* Gets MetaData from the cache, given a specified context.
* If the data is not cached, it is calculated. Therefore, this call could be costly.
* @param contexts the contexts to get the permission data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
*/
MetaData getMetaData(Contexts contexts);
/**
* Calculates permission data, bypassing the cache.
* @param contexts the contexts to get permission data in
* @return a permission data instance
* @throws NullPointerException if contexts is null
*/
PermissionData calculatePermissions(Contexts contexts);
/**
* Calculates meta data, bypassing the cache.
* @param contexts the contexts to get meta data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
*/
MetaData calculateMeta(Contexts contexts);
/**
* Calculates permission data and stores it in the cache. If there is already data cached for the given contexts,
* and if the resultant output is different, the cached value is updated.
* @param contexts the contexts to recalculate in.
* @throws NullPointerException if contexts is null
*/
void recalculatePermissions(Contexts contexts);
/**
* Calculates meta data and stores it in the cache. If there is already data cached for the given contexts,
* and if the resultant output is different, the cached value is updated.
* @param contexts the contexts to recalculate in.
* @throws NullPointerException if contexts is null
*/
void recalculateMeta(Contexts contexts);
/**
* Calls {@link #recalculatePermissions(Contexts)} for all current loaded contexts
*/
void recalculatePermissions();
/**
* Calls {@link #recalculateMeta(Contexts)} for all current loaded contexts
*/
void recalculateMeta();
/**
* Calls {@link #preCalculate(Contexts)} for the given contexts
* @param contexts a set of contexts
* @throws NullPointerException if contexts is null
*/
void preCalculate(Set<Contexts> contexts);
/**
* Ensures that PermissionData and MetaData is cached for a context. If the cache does not contain any data for the
* context, it will be calculated and saved.
* @param contexts the contexts to pre-calculate for
* @throws NullPointerException if contexts is null
*/
void preCalculate(Contexts contexts);
/**
* Invalidates all of the underlying Permission calculators.
* Can be called to allow for an update in defaults.
*/
void invalidatePermissionCalculators();
}
@@ -27,7 +27,7 @@ import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A simple implementation of the listener aspects of {@link IContextCalculator<T>}
* A simple implementation of the listener aspects of {@link IContextCalculator}
* @param <T> the subject type
*/
public abstract class ContextCalculator<T> implements IContextCalculator<T> {
@@ -0,0 +1,311 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.context;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Holds contexts.
* All contained contexts are immutable, and unlike {@link MutableContextSet}, contexts cannot be added or removed.
*
* @since 2.13
*/
public class ContextSet {
/**
* Make a singleton ContextSet from a context pair
* @param key the key
* @param value the value
* @return a new ContextSet containing one KV pair
* @throws NullPointerException if key or value is null
*/
public static ContextSet singleton(String key, String value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
throw new NullPointerException("value");
}
MutableContextSet set = new MutableContextSet();
set.add(key, value);
return set.immutableCopy();
}
/**
* Creates a ContextSet from an existing map
* @param map the map to copy from
* @return a new ContextSet representing the pairs from the map
* @throws NullPointerException if the map is null
*/
public static ContextSet fromMap(Map<String, String> map) {
if (map == null) {
throw new NullPointerException("map");
}
MutableContextSet set = new MutableContextSet();
set.addAll(map);
return set.immutableCopy();
}
/**
* Creates a ContextSet from an existing iterable of Map Entries
* @param iterable the iterable to copy from
* @return a new ContextSet representing the pairs in the iterable
* @throws NullPointerException if the iterable is null
*/
public static ContextSet fromEntries(Iterable<Map.Entry<String, String>> iterable) {
if (iterable == null) {
throw new NullPointerException("iterable");
}
MutableContextSet set = new MutableContextSet();
set.addAll(iterable);
return set.immutableCopy();
}
/**
* Creates a new ContextSet from an existing set.
* Only really useful for converting between mutable and immutable types.
* @param contextSet the context set to copy from
* @return a new ContextSet with the same content and the one provided
* @throws NullPointerException if contextSet is null
*/
public static ContextSet fromSet(ContextSet contextSet) {
if (contextSet == null) {
throw new NullPointerException("contextSet");
}
MutableContextSet set = new MutableContextSet();
set.addAll(contextSet.toSet());
return set.immutableCopy();
}
/**
* Creates a new empty ContextSet.
* @return a new ContextSet
*/
public static ContextSet empty() {
return new ContextSet();
}
final Set<Map.Entry<String, String>> contexts;
public ContextSet() {
this.contexts = new HashSet<>();
}
protected ContextSet(Set<Map.Entry<String, String>> contexts) {
this.contexts = contexts;
}
/**
* Check to see if this set is in an immutable form
* @return true if the set is immutable
*/
public boolean isImmutable() {
return true;
}
/**
* If the set is mutable, this method will return an immutable copy. Otherwise just returns itself.
* @return an immutable ContextSet
*/
public ContextSet makeImmutable() {
return this;
}
/**
* Converts this ContextSet to an immutable {@link Set} of {@link Map.Entry}s.
* @return an immutable set
*/
public Set<Map.Entry<String, String>> toSet() {
synchronized (contexts) {
return ImmutableSet.copyOf(contexts);
}
}
/**
* Converts this ContextSet to an immutable {@link Map}
*
* <b>NOTE: Use of this method may result in data being lost. ContextSets can contain lots of different values for
* one key.</b>
*
* @return an immutable map
*/
public Map<String, String> toMap() {
synchronized (contexts) {
return ImmutableMap.copyOf(contexts.stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
}
}
/**
* Check if the set contains at least one value for the given key.
* @param key the key to check for
* @return true if the set contains a value for the key
* @throws NullPointerException if the key is null
*/
public boolean containsKey(String key) {
if (key == null) {
throw new NullPointerException("key");
}
synchronized (contexts) {
for (Map.Entry<String, String> e : contexts) {
if (e.getKey().equalsIgnoreCase(key)) {
return true;
}
}
}
return false;
}
/**
* Gets a set of all of the values mapped to the given key
* @param key the key to find values for
* @return a set of values
* @throws NullPointerException if the key is null
*/
public Set<String> getValues(String key) {
if (key == null) {
throw new NullPointerException("key");
}
synchronized (contexts) {
return ImmutableSet.copyOf(contexts.stream()
.filter(e -> e.getKey().equalsIgnoreCase(key))
.map(Map.Entry::getValue)
.collect(Collectors.toSet())
);
}
}
/**
* Check if thr set contains a given key mapped to a given value
* @param key the key to look for
* @param value the value to look for (case sensitive)
* @return true if the set contains the KV pair
* @throws NullPointerException if the key or value is null
*/
public boolean has(String key, String value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
throw new NullPointerException("value");
}
synchronized (contexts) {
for (Map.Entry<String, String> e : contexts) {
if (!e.getKey().equalsIgnoreCase(key)) {
continue;
}
if (!e.getValue().equals(value)) {
continue;
}
return true;
}
}
return false;
}
/**
* Same as {@link #has(String, String)}, except ignores the case of the value.
* @param key the key to look for
* @param value the value to look for
* @return true if the set contains the KV pair
* @throws NullPointerException if the key or value is null
*/
public boolean hasIgnoreCase(String key, String value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
throw new NullPointerException("value");
}
synchronized (contexts) {
for (Map.Entry<String, String> e : contexts) {
if (!e.getKey().equalsIgnoreCase(key)) {
continue;
}
if (!e.getValue().equalsIgnoreCase(value)) {
continue;
}
return true;
}
}
return false;
}
/**
* Check if the set is empty
* @return true if the set is empty
*/
public boolean isEmpty() {
synchronized (contexts) {
return contexts.isEmpty();
}
}
/**
* Gets the number of key-value context pairs in the set
* @return the size of the set
*/
public int size() {
synchronized (contexts) {
return contexts.size();
}
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof ContextSet)) return false;
final ContextSet other = (ContextSet) o;
final Object thisContexts = this.contexts;
final Object otherContexts = other.contexts;
return thisContexts == null ? otherContexts == null : thisContexts.equals(otherContexts);
}
@Override
public int hashCode() {
return 59 + (this.contexts == null ? 43 : this.contexts.hashCode());
}
@Override
public String toString() {
return "ContextSet(contexts=" + this.contexts + ")";
}
}
@@ -22,6 +22,7 @@
package me.lucko.luckperms.api.context;
import java.util.HashMap;
import java.util.Map;
/**
@@ -34,11 +35,40 @@ public interface IContextCalculator<T> {
/**
* Gives the subject all of the applicable contexts they meet
* @param subject the subject to add contexts tp
* @param subject the subject to add contexts to
* @param accumulator a map of contexts to add to
* @return the map
* @deprecated in favour of {@link #giveApplicableContext(Object, MutableContextSet)}. Older implementations of this interface
* will still work, as the replacement method is given as a default, and falls back to using this method.
*/
Map<String, String> giveApplicableContext(T subject, Map<String, String> accumulator);
@Deprecated
default Map<String, String> giveApplicableContext(T subject, Map<String, String> accumulator) {
MutableContextSet acc = new MutableContextSet();
giveApplicableContext(subject, acc);
accumulator.putAll(acc.toMap());
return accumulator;
}
/**
* Gives the subject all of the applicable contexts they meet
*
* <p><b>You MUST implement this method. The default is only provided for backwards compatibility with
* {@link #giveApplicableContext(Object, Map)}.</b>
*
* @param subject the subject to add contexts to
* @param accumulator a map of contexts to add to
* @return the map
* @since 2.13
*/
@SuppressWarnings("deprecation")
default MutableContextSet giveApplicableContext(T subject, MutableContextSet accumulator) {
Map<String, String> acc = new HashMap<>();
giveApplicableContext(subject, acc);
accumulator.addAll(acc.entrySet());
return accumulator;
}
/**
* Checks to see if a context is applicable to a subject
@@ -0,0 +1,272 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.context;
import com.google.common.collect.Maps;
import java.util.HashSet;
import java.util.Map;
/**
* Holds contexts
* All contained contexts are immutable, but contexts can be added or removed from the set.
*
* @since 2.13
*/
public class MutableContextSet extends ContextSet {
/**
* Make a singleton MutableContextSet from a context pair
* @param key the key
* @param value the value
* @return a new MutableContextSet containing one KV pair
* @throws NullPointerException if key or value is null
*/
public static MutableContextSet singleton(String key, String value) {
MutableContextSet set = new MutableContextSet();
set.add(key, value);
return set;
}
/**
* Creates a MutableContextSet from an existing map
* @param map the map to copy from
* @return a new MutableContextSet representing the pairs from the map
* @throws NullPointerException if the map is null
*/
public static MutableContextSet fromMap(Map<String, String> map) {
MutableContextSet set = new MutableContextSet();
set.addAll(map);
return set;
}
/**
* Creates a MutableContextSet from an existing iterable of Map Entries
* @param iterable the iterable to copy from
* @return a new MutableContextSet representing the pairs in the iterable
* @throws NullPointerException if the iterable is null
*/
public static MutableContextSet fromEntries(Iterable<Map.Entry<String, String>> iterable) {
MutableContextSet set = new MutableContextSet();
set.addAll(iterable);
return set;
}
/**
* Creates a new MutableContextSet from an existing set.
* Only really useful for converting between mutable and immutable types.
* @param contextSet the context set to copy from
* @return a new MutableContextSet with the same content and the one provided
* @throws NullPointerException if contextSet is null
*/
public static MutableContextSet fromSet(ContextSet contextSet) {
MutableContextSet set = new MutableContextSet();
set.addAll(contextSet.toSet());
return set;
}
/**
* Creates a new empty MutableContextSet.
* @return a new MutableContextSet
*/
public static MutableContextSet empty() {
return new MutableContextSet();
}
@Override
public boolean isImmutable() {
return false;
}
@Override
public ContextSet makeImmutable() {
return immutableCopy();
}
/**
* Returns an immutable copy of this set.
* @return an immutable copy of this set
*/
public ContextSet immutableCopy() {
synchronized (contexts) {
return new ContextSet(new HashSet<>(contexts));
}
}
/**
* Adds a new key value pair to the set
* @param key the key to add
* @param value the value to add
* @throws NullPointerException if the key or value is null
*/
public void add(String key, String value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
throw new NullPointerException("value");
}
synchronized (contexts) {
contexts.add(Maps.immutableEntry(key, value));
}
}
/**
* Adds a new key value pair to the set
* @param entry the entry to add
* @throws NullPointerException if the entry is null
*/
public void add(Map.Entry<String, String> entry) {
if (entry == null) {
throw new NullPointerException("context");
}
synchronized (contexts) {
contexts.add(Maps.immutableEntry(entry.getKey(), entry.getValue()));
}
}
/**
* Adds an iterable containing contexts to the set
* @param iterable an iterable of key value context pairs
* @throws NullPointerException if iterable is null
*/
public void addAll(Iterable<Map.Entry<String, String>> iterable) {
if (iterable == null) {
throw new NullPointerException("contexts");
}
synchronized (this.contexts) {
for (Map.Entry<String, String> e : iterable) {
this.contexts.add(Maps.immutableEntry(e.getKey(), e.getValue()));
}
}
}
/**
* Adds the entry set of a map to the set
* @param map the map to add from
* @throws NullPointerException if the map is null
*/
public void addAll(Map<String, String> map) {
if (map == null) {
throw new NullPointerException("contexts");
}
addAll(map.entrySet());
}
/**
* Adds of of the values in another ContextSet to this set
* @param contextSet the set to add from
* @throws NullPointerException if the contextSet is null
*/
public void addAll(ContextSet contextSet) {
if (contextSet == null) {
throw new NullPointerException("contextSet");
}
synchronized (this.contexts) {
this.contexts.addAll(contextSet.toSet());
}
}
/**
* Remove a key value pair from this set
* @param key the key to remove
* @param value the value to remove (case sensitive)
* @throws NullPointerException if the key or value is null
*/
public void remove(String key, String value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
throw new NullPointerException("value");
}
synchronized (contexts) {
contexts.removeIf(e -> e.getKey().equalsIgnoreCase(key) && e.getValue().equals(value));
}
}
/**
* Same as {@link #remove(String, String)}, except ignores the case of the value
* @param key the key to remove
* @param value the value to remove
* @throws NullPointerException if the key or value is null
*/
public void removeIgnoreCase(String key, String value) {
if (key == null) {
throw new NullPointerException("key");
}
if (value == null) {
throw new NullPointerException("value");
}
synchronized (contexts) {
contexts.removeIf(e -> e.getKey().equalsIgnoreCase(key) && e.getValue().equalsIgnoreCase(value));
}
}
/**
* Removes all pairs with the given key
* @param key the key to remove
* @throws NullPointerException if the key is null
*/
public void removeAll(String key) {
if (key == null) {
throw new NullPointerException("key");
}
synchronized (contexts) {
contexts.removeIf(e -> e.getKey().equalsIgnoreCase(key));
}
}
/**
* Clears the set
*/
public void clear() {
synchronized (contexts) {
contexts.clear();
}
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof ContextSet)) return false;
final ContextSet other = (ContextSet) o;
final Object thisContexts = this.contexts;
final Object otherContexts = other.contexts;
return thisContexts == null ? otherContexts == null : thisContexts.equals(otherContexts);
}
@Override
public int hashCode() {
return 59 + (this.contexts == null ? 43 : this.contexts.hashCode());
}
}
@@ -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;
}
}
+21 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.11-SNAPSHOT</version>
<version>2.14-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -67,6 +67,26 @@
<pattern>org.h2</pattern>
<shadedPattern>me.lucko.luckperms.lib.h2</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>me.lucko.luckperms.lib.guava</shadedPattern>
</relocation>
<relocation>
<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.11-SNAPSHOT</version>
<version>2.14-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>2.13-SNAPSHOT</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.11-SNAPSHOT</version>
<version>2.14-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>
@@ -1,317 +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;
import lombok.Getter;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.implementation.ApiProvider;
import me.lucko.luckperms.api.vault.VaultHook;
import me.lucko.luckperms.calculators.DefaultsProvider;
import me.lucko.luckperms.commands.ConsecutiveExecutor;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.config.LPConfiguration;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.contexts.ContextManager;
import me.lucko.luckperms.contexts.ServerCalculator;
import me.lucko.luckperms.contexts.WorldCalculator;
import me.lucko.luckperms.core.UuidCache;
import me.lucko.luckperms.data.Importer;
import me.lucko.luckperms.groups.GroupManager;
import me.lucko.luckperms.runnables.ExpireTemporaryTask;
import me.lucko.luckperms.runnables.UpdateTask;
import me.lucko.luckperms.storage.Datastore;
import me.lucko.luckperms.storage.StorageFactory;
import me.lucko.luckperms.tracks.TrackManager;
import me.lucko.luckperms.users.BukkitUserManager;
import me.lucko.luckperms.utils.LocaleManager;
import me.lucko.luckperms.utils.LogFactory;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Getter
public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private VaultHook vaultHook = null;
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private LPConfiguration configuration;
private BukkitUserManager userManager;
private GroupManager groupManager;
private TrackManager trackManager;
private Datastore datastore;
private UuidCache uuidCache;
private ApiProvider apiProvider;
private Logger log;
private Importer importer;
private ConsecutiveExecutor consecutiveExecutor;
private DefaultsProvider defaultsProvider;
private LocaleManager localeManager;
private ContextManager<Player> contextManager;
private WorldCalculator worldCalculator;
@Override
public void onEnable() {
log = LogFactory.wrap(getLogger());
getLog().info("Loading configuration...");
configuration = new BukkitConfig(this);
localeManager = new LocaleManager();
File locale = new File(getDataFolder(), "lang.yml");
if (locale.exists()) {
getLog().info("Found locale file. Attempting to load from it.");
try {
localeManager.loadFromFile(locale);
} catch (Exception e) {
e.printStackTrace();
}
}
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);
PluginCommand main = getServer().getPluginCommand("luckperms");
main.setExecutor(commandManager);
main.setTabCompleter(commandManager);
main.setAliases(Arrays.asList("perms", "lp", "permissions", "p", "perm"));
datastore = StorageFactory.getDatastore(this, "h2");
getLog().info("Loading internal permission managers...");
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
userManager = new BukkitUserManager(this);
groupManager = new GroupManager(this);
trackManager = new TrackManager();
importer = new Importer(commandManager);
consecutiveExecutor = new ConsecutiveExecutor(commandManager);
contextManager = new ContextManager<>();
worldCalculator = new WorldCalculator(this);
pm.registerEvents(worldCalculator, this);
contextManager.registerCalculator(worldCalculator);
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
contextManager.registerListener(userManager);
int mins = getConfiguration().getSyncTime();
if (mins > 0) {
long ticks = mins * 60 * 20;
getServer().getScheduler().runTaskTimerAsynchronously(this, new UpdateTask(this), 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();
}
getLog().info("Registering API...");
apiProvider = new ApiProvider(this);
LuckPerms.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.");
try {
new UpdateTask(this).run();
} catch (Exception e) {
e.printStackTrace();
}
registerPermissions(getConfiguration().isCommandsAllowOp() ? PermissionDefault.OP : PermissionDefault.FALSE);
if (!getConfiguration().isOpsEnabled()) {
getServer().getOperators().forEach(o -> o.setOp(false));
}
getLog().info("Successfully loaded.");
}
@Override
public void onDisable() {
getLog().info("Closing datastore...");
datastore.shutdown();
getLog().info("Unregistering API...");
LuckPerms.unregisterProvider();
getServer().getServicesManager().unregisterAll(this);
if (vaultHook != null) {
vaultHook.unhook(this);
}
}
@Override
public void doAsync(Runnable r) {
getServer().getScheduler().runTaskAsynchronously(this, r);
}
@Override
public void doSync(Runnable r) {
getServer().getScheduler().runTask(this, r);
}
@Override
public String getVersion() {
return getDescription().getVersion();
}
@Override
public PlatformType getType() {
return PlatformType.BUKKIT;
}
@Override
public File getMainDir() {
return getDataFolder();
}
@Override
public Message getPlayerStatus(UUID uuid) {
return getServer().getPlayer(getUuidCache().getExternalUUID(uuid)) != null ? Message.PLAYER_ONLINE : Message.PLAYER_OFFLINE;
}
@Override
public int getPlayerCount() {
return getServer().getOnlinePlayers().size();
}
@Override
public List<String> getPlayerList() {
return getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
}
@Override
public List<Sender> getNotifyListeners() {
return getServer().getOnlinePlayers().stream()
.map(p -> BukkitSenderFactory.get(this).wrap(p, Collections.singleton(me.lucko.luckperms.constants.Permission.LOG_NOTIFY)))
.filter(me.lucko.luckperms.constants.Permission.LOG_NOTIFY::isAuthorized)
.collect(Collectors.toList());
}
@Override
public Sender getConsoleSender() {
return BukkitSenderFactory.get(this).wrap(getServer().getConsoleSender());
}
@Override
public List<String> getPossiblePermissions() {
final List<String> perms = new ArrayList<>();
getServer().getPluginManager().getPermissions().forEach(p -> {
perms.add(p.getName());
p.getChildren().keySet().forEach(perms::add);
});
return perms;
}
@Override
public Object getPlugin(String name) {
return getServer().getPluginManager().getPlugin(name);
}
@Override
public Object getService(Class clazz) {
return getServer().getServicesManager().load(clazz);
}
@SuppressWarnings("deprecation")
@Override
public UUID getUUID(String playerName) {
try {
return getServer().getOfflinePlayer(playerName).getUniqueId();
} catch (Exception e) {
return null;
}
}
@Override
public boolean isPluginLoaded(String name) {
return getServer().getPluginManager().isPluginEnabled(name);
}
@Override
public void runUpdateTask() {
getServer().getScheduler().runTaskAsynchronously(this, new UpdateTask(this));
}
private void registerPermissions(PermissionDefault def) {
PluginManager pm = getServer().getPluginManager();
Map<String, List<String>> wildcards = new HashMap<>();
List<String> all = new ArrayList<>();
for (me.lucko.luckperms.constants.Permission p : me.lucko.luckperms.constants.Permission.values()) {
pm.addPermission(new Permission(p.getNode(), def));
if (p.getGroup() != null) {
if (!wildcards.containsKey(p.getGroup())) {
wildcards.put(p.getGroup(), new ArrayList<>());
}
wildcards.get(p.getGroup()).add(p.getTag());
}
all.add(p.getNode());
}
for (Map.Entry<String, List<String>> e : wildcards.entrySet()) {
pm.addPermission(new Permission(
"luckperms." + e.getKey() + ".*", def,
e.getValue().stream()
.map(tag -> "luckperms." + e.getKey() + "." + tag)
.collect(Collectors.toMap(s -> s, s -> true))
)
);
}
pm.addPermission(new Permission("luckperms.*", def, all.stream().collect(Collectors.toMap(s -> s, s -> true))));
}
}
@@ -1,313 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.vault;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import me.lucko.luckperms.LPBukkitPlugin;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.vault.cache.VaultUser;
import me.lucko.luckperms.api.vault.cache.VaultUserManager;
import me.lucko.luckperms.core.PermissionHolder;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.users.User;
import net.milkbowl.vault.permission.Permission;
import java.util.*;
/**
* The LuckPerms Vault Permission implementation
* Most lookups are cached.
*/
public class VaultPermissionHook extends Permission implements Runnable {
private final List<Runnable> tasks = new ArrayList<>();
@Getter
@Setter
private LPBukkitPlugin plugin;
@Getter
private VaultUserManager vaultUserManager;
@Getter
@Setter
private String server = "global";
@Getter
@Setter
private boolean includeGlobal = true;
public void setup() {
vaultUserManager = new VaultUserManager(plugin, this);
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this, 1L, 1L);
}
public void log(String s) {
if (plugin.getConfiguration().isDebugPermissionChecks()) {
plugin.getLog().info("[VAULT] " + s);
}
}
void scheduleTask(Runnable r) {
synchronized (tasks) {
tasks.add(r);
}
}
@Override
public void run() {
List<Runnable> toRun = new ArrayList<>();
synchronized (tasks) {
toRun.addAll(tasks);
tasks.clear();
}
toRun.forEach(Runnable::run);
}
@Override
public String getName() {
return "LuckPerms";
}
@Override
public boolean isEnabled() {
return plugin.getDatastore().isAcceptingLogins();
}
@Override
public boolean hasSuperPermsCompat() {
return true;
}
private boolean objectHas(String world, Group group, String permission) {
if (group == null) return false;
Map<String, String> context = new HashMap<>();
if (world != null && !world.equals("")) {
context.put("world", world);
}
context.put("server", server);
Map<String, Boolean> toApply = group.exportNodes(
new Contexts(context, includeGlobal, includeGlobal, true, true, true),
Collections.emptyList(), true
);
return toApply.containsKey(permission) && toApply.get(permission);
}
private boolean add(String world, PermissionHolder object, String permission) {
if (object == null) return false;
try {
if (world != null && !world.equals("")) {
object.setPermission(permission, true, server, world);
} else {
object.setPermission(permission, true, server);
}
} catch (ObjectAlreadyHasException ignored) {}
save(object);
return true;
}
private boolean remove(String world, PermissionHolder object, String permission) {
if (object == null) return false;
try {
if (world != null && !world.equals("")) {
object.unsetPermission(permission, server, world);
} else {
object.unsetPermission(permission, server);
}
} catch (ObjectLacksException ignored) {}
save(object);
return true;
}
void save(PermissionHolder t) {
if (t instanceof User) {
((User) t).refreshPermissions();
plugin.getDatastore().saveUser(((User) t));
}
if (t instanceof Group) {
plugin.getDatastore().saveGroup(((Group) t));
plugin.runUpdateTask();
}
}
@Override
public boolean playerHas(String world, @NonNull String player, @NonNull String permission) {
log("Checking if player " + player + " has permission: " + permission + " on world " + world + ", server " + server);
User user = plugin.getUserManager().get(player);
if (user == null) return false;
if (!vaultUserManager.containsUser(user.getUuid())) {
return false;
}
VaultUser vaultUser = vaultUserManager.getUser(user.getUuid());
Map<String, String> context = new HashMap<>();
context.put("server", server);
if (world != null) {
context.put("world", world);
}
return vaultUser.hasPermission(context, permission);
}
@Override
public boolean playerAdd(String world, @NonNull String player, @NonNull String permission) {
log("Adding permission to player " + player + ": '" + permission + "' on world " + world + ", server " + server);
final User user = plugin.getUserManager().get(player);
scheduleTask(() -> add(world, user, permission));
return true;
}
@Override
public boolean playerRemove(String world, @NonNull String player, @NonNull String permission) {
log("Removing permission from player " + player + ": '" + permission + "' on world " + world + ", server " + server);
final User user = plugin.getUserManager().get(player);
scheduleTask(() -> remove(world, user, permission));
return true;
}
@Override
public boolean groupHas(String world, @NonNull String groupName, @NonNull String permission) {
log("Checking if group " + groupName + " has permission: " + permission + " on world " + world + ", server " + server);
final Group group = plugin.getGroupManager().get(groupName);
return objectHas(world, group, permission);
}
@Override
public boolean groupAdd(String world, @NonNull String groupName, @NonNull String permission) {
log("Adding permission to group " + groupName + ": '" + permission + "' on world " + world + ", server " + server);
final Group group = plugin.getGroupManager().get(groupName);
scheduleTask(() -> add(world, group, permission));
return true;
}
@Override
public boolean groupRemove(String world, @NonNull String groupName, @NonNull String permission) {
log("Removing permission from group " + groupName + ": '" + permission + "' on world " + world + ", server " + server);
final Group group = plugin.getGroupManager().get(groupName);
scheduleTask(() -> remove(world, group, permission));
return true;
}
@Override
public boolean playerInGroup(String world, @NonNull String player, @NonNull String group) {
log("Checking if player " + player + " is in group: " + group + " on world " + world + ", server " + server);
final User user = plugin.getUserManager().get(player);
if (user == null) return false;
return user.getNodes().stream()
.filter(Node::isGroupNode)
.filter(n -> n.shouldApplyOnServer(server, isIncludeGlobal(), false))
.filter(n -> n.shouldApplyOnWorld(world, true, false))
.map(Node::getGroupName)
.filter(s -> s.equalsIgnoreCase(group))
.findAny().isPresent();
}
@Override
public boolean playerAddGroup(String world, @NonNull String player, @NonNull String groupName) {
log("Adding player " + player + " to group: '" + groupName + "' on world " + world + ", server " + server);
final User user = plugin.getUserManager().get(player);
if (user == null) return false;
final Group group = plugin.getGroupManager().get(groupName);
if (group == null) return false;
scheduleTask(() -> {
try {
if (world != null && !world.equals("")) {
user.addGroup(group, server, world);
} else {
user.addGroup(group, server);
}
} catch (ObjectAlreadyHasException ignored) {}
save(user);
});
return true;
}
@Override
public boolean playerRemoveGroup(String world, @NonNull String player, @NonNull String groupName) {
log("Removing player " + player + " from group: '" + groupName + "' on world " + world + ", server " + server);
final User user = plugin.getUserManager().get(player);
if (user == null) return false;
final Group group = plugin.getGroupManager().get(groupName);
if (group == null) return false;
scheduleTask(() -> {
try {
if (world != null && !world.equals("")) {
user.removeGroup(group, server, world);
} else {
user.removeGroup(group, server);
}
} catch (ObjectLacksException ignored) {}
save(user);
});
return true;
}
@Override
public String[] getPlayerGroups(String world, @NonNull String player) {
log("Getting groups of player: " + player + ", on world " + world + ", server " + server);
User user = plugin.getUserManager().get(player);
if (user == null) return new String[0];
return user.getNodes().stream()
.filter(Node::isGroupNode)
.filter(n -> n.shouldApplyOnServer(server, isIncludeGlobal(), false))
.filter(n -> n.shouldApplyOnWorld(world, true, false))
.map(Node::getGroupName)
.toArray(String[]::new);
}
@Override
public String getPrimaryGroup(String world, @NonNull String player) {
log("Getting primary group of player: " + player);
final User user = plugin.getUserManager().get(player);
return (user == null) ? null : user.getPrimaryGroup();
}
@Override
public String[] getGroups() {
return plugin.getGroupManager().getAll().keySet().toArray(new String[0]);
}
@Override
public boolean hasGroupSupport() {
return true;
}
}
@@ -1,72 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.vault.cache;
import lombok.Getter;
import lombok.NonNull;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.calculators.*;
import me.lucko.luckperms.users.BukkitUser;
import me.lucko.luckperms.users.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ContextCache {
@Getter
private final Map<String, String> context;
@Getter
private final Map<String, Boolean> permissionCache = new ConcurrentHashMap<>();
private final PermissionCalculator calculator;
public ContextCache(User user, Map<String, String> context, LuckPermsPlugin plugin, DefaultsProvider defaultsProvider) {
this.context = context;
List<PermissionProcessor> processors = new ArrayList<>(5);
processors.add(new MapProcessor(permissionCache));
if (plugin.getConfiguration().isApplyingWildcards()) {
processors.add(new WildcardProcessor(permissionCache));
}
if (plugin.getConfiguration().isApplyingRegex()) {
processors.add(new RegexProcessor(permissionCache));
}
processors.add(new DefaultsProcessor(((BukkitUser) user)::isOp, defaultsProvider));
calculator = new PermissionCalculator(plugin, user.getName(), plugin.getConfiguration().isDebugPermissionChecks(), processors);
}
public void invalidateCache() {
calculator.invalidateCache();
}
public Tristate getPermissionValue(@NonNull String permission) {
return calculator.getPermissionValue(permission);
}
}
@@ -1,181 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.vault.cache;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.LPBukkitPlugin;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.vault.VaultPermissionHook;
import me.lucko.luckperms.users.User;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@RequiredArgsConstructor
public class VaultUser {
private final LPBukkitPlugin plugin;
private final VaultPermissionHook vault;
@Getter
private final User user;
@Getter
private final Map<Map<String, String>, ContextCache> contextData = new ConcurrentHashMap<>();
@Getter
private final Map<Map<String, String>, ChatCache> chatData = new ConcurrentHashMap<>();
public boolean hasPermission(Map<String, String> context, String permission) {
ContextCache cd = contextData.computeIfAbsent(context, map -> calculatePermissions(map, false));
return cd.getPermissionValue(permission).asBoolean();
}
public ChatCache processChatData(Map<String, String> context) {
return chatData.computeIfAbsent(context, map -> calculateChat(map, false));
}
public ContextCache calculatePermissions(Map<String, String> context, boolean apply) {
Map<String, Boolean> toApply = user.exportNodes(
new Contexts(context, vault.isIncludeGlobal(), true, true, true, true),
Collections.emptyList(),
true
);
ContextCache existing = contextData.get(context);
if (existing == null) {
existing = new ContextCache(user, context, plugin, plugin.getDefaultsProvider());
if (apply) {
contextData.put(context, existing);
}
}
boolean different = false;
if (toApply.size() != existing.getPermissionCache().size()) {
different = true;
} else {
for (Map.Entry<String, Boolean> e : existing.getPermissionCache().entrySet()) {
if (toApply.containsKey(e.getKey()) && toApply.get(e.getKey()) == e.getValue()) {
continue;
}
different = true;
break;
}
}
if (!different) return existing;
existing.getPermissionCache().clear();
existing.invalidateCache();
existing.getPermissionCache().putAll(toApply);
return existing;
}
public ChatCache calculateChat(Map<String, String> context, boolean apply) {
ChatCache existing = chatData.get(context);
if (existing == null) {
existing = new ChatCache(context);
if (apply) {
chatData.put(context, existing);
}
}
Map<String, String> contexts = new HashMap<>(context);
String server = contexts.get("server");
String world = contexts.get("world");
contexts.remove("server");
contexts.remove("world");
existing.invalidateCache();
// Load meta
for (Node n : user.getPermissions(true)) {
if (!n.getValue()) {
continue;
}
if (!n.isMeta()) {
continue;
}
if (!n.shouldApplyOnServer(server, vault.isIncludeGlobal(), false)) {
continue;
}
if (!n.shouldApplyOnWorld(world, true, false)) {
continue;
}
if (!n.shouldApplyWithContext(contexts, false)) {
continue;
}
Map.Entry<String, String> meta = n.getMeta();
existing.getMeta().put(meta.getKey(), meta.getValue());
}
// Load prefixes & suffixes
int prefixPriority = Integer.MIN_VALUE;
int suffixPriority = Integer.MIN_VALUE;
for (Node n : user.getAllNodes(null, new Contexts(context, vault.isIncludeGlobal(), true, true, true, true))) {
if (!n.getValue()) {
continue;
}
if (!n.isPrefix() && !n.isSuffix()) {
continue;
}
if (!n.shouldApplyOnServer(server, vault.isIncludeGlobal(), false)) {
continue;
}
if (!n.shouldApplyOnWorld(world, true, false)) {
continue;
}
if (!n.shouldApplyWithContext(contexts, false)) {
continue;
}
if (n.isPrefix()) {
Map.Entry<Integer, String> value = n.getPrefix();
if (value.getKey() > prefixPriority) {
existing.setPrefix(value.getValue());
}
} else {
Map.Entry<Integer, String> value = n.getSuffix();
if (value.getKey() > suffixPriority) {
existing.setSuffix(value.getValue());
}
}
}
return existing;
}
}
@@ -1,68 +0,0 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.vault.cache;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.LPBukkitPlugin;
import me.lucko.luckperms.api.vault.VaultPermissionHook;
import me.lucko.luckperms.users.User;
import org.bukkit.World;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@RequiredArgsConstructor
public class VaultUserManager {
private final LPBukkitPlugin plugin;
private final VaultPermissionHook vault;
private final Map<UUID, VaultUser> userCache = new ConcurrentHashMap<>();
public void setupUser(User user) {
VaultUser vaultUser = userCache.computeIfAbsent(user.getUuid(), uuid -> new VaultUser(plugin, vault, user));
vaultUser.calculatePermissions(Collections.singletonMap("server", vault.getServer()), true);
vaultUser.calculateChat(Collections.singletonMap("server", vault.getServer()), true);
for (World world : plugin.getServer().getWorlds()) {
Map<String, String> context = new HashMap<>();
context.put("server", vault.getServer());
context.put("world", world.getName());
vaultUser.calculatePermissions(context, true);
vaultUser.calculateChat(context, true);
}
}
public void clearUser(UUID uuid) {
userCache.remove(uuid);
}
public boolean containsUser(UUID uuid) {
return userCache.containsKey(uuid);
}
public VaultUser getUser(UUID uuid) {
return userCache.get(uuid);
}
}
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit;
import 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.common.users.User;
import java.util.UUID;
@AllArgsConstructor
public class BukkitCalculatorFactory implements CalculatorFactory {
private final LPBukkitPlugin plugin;
@Override
public PermissionCalculator build(Contexts contexts, User user) {
UUID uuid = plugin.getUuidCache().getExternalUUID(user.getUuid());
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());
}
if (plugin.getConfiguration().isApplyingRegex()) {
processors.add(new RegexProcessor());
}
processors.add(new DefaultsProcessor(contexts.isOp(), plugin.getDefaultsProvider()));
return new PermissionCalculator(plugin, user.getName(), processors.build());
}
}
@@ -20,14 +20,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms;
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.commands.CommandManager;
import me.lucko.luckperms.commands.Util;
import me.lucko.luckperms.constants.Patterns;
import me.lucko.luckperms.common.commands.CommandManager;
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;
import org.bukkit.command.CommandSender;
@@ -37,14 +37,17 @@ 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()
@@ -52,9 +55,8 @@ class BukkitCommand extends CommandManager implements CommandExecutor, TabExecut
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));
}
}
@@ -20,17 +20,18 @@
* SOFTWARE.
*/
package me.lucko.luckperms;
package me.lucko.luckperms.bukkit;
import me.lucko.luckperms.config.AbstractConfiguration;
import me.lucko.luckperms.common.config.AbstractConfiguration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
class BukkitConfig extends AbstractConfiguration<LPBukkitPlugin> {
private YamlConfiguration configuration;
@@ -49,13 +50,7 @@ class BukkitConfig extends AbstractConfiguration<LPBukkitPlugin> {
getPlugin().saveResource("config.yml", false);
}
configuration = new YamlConfiguration();
try {
configuration.load(configFile);
} catch (InvalidConfigurationException | IOException e) {
e.printStackTrace();
}
configuration = YamlConfiguration.loadConfiguration(configFile);
}
@Override
@@ -73,6 +68,21 @@ class BukkitConfig extends AbstractConfiguration<LPBukkitPlugin> {
return configuration.getBoolean(path, def);
}
@Override
protected List<String> getList(String path, List<String> def) {
return Optional.ofNullable(configuration.getStringList(path)).orElse(def);
}
@Override
protected List<String> getObjectList(String path, List<String> def) {
ConfigurationSection section = configuration.getConfigurationSection(path);
if (section == null) {
return def;
}
return Optional.ofNullable(section.getKeys(false).stream().collect(Collectors.toList())).orElse(def);
}
@SuppressWarnings("unchecked")
@Override
protected Map<String, String> getMap(String path, Map<String, String> def) {
@@ -20,23 +20,22 @@
* SOFTWARE.
*/
package me.lucko.luckperms;
package me.lucko.luckperms.bukkit;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.inject.Injector;
import me.lucko.luckperms.inject.LPPermissible;
import me.lucko.luckperms.users.BukkitUser;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.AbstractListener;
import me.lucko.luckperms.bukkit.inject.Injector;
import me.lucko.luckperms.bukkit.inject.LPPermissible;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.AbstractListener;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.*;
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 java.util.Collections;
import java.util.Map;
import java.util.UUID;
class BukkitListener extends AbstractListener implements Listener {
@@ -49,7 +48,8 @@ class BukkitListener extends AbstractListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerPreLogin(AsyncPlayerPreLoginEvent e) {
if (!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());
return;
@@ -57,38 +57,14 @@ class BukkitListener extends AbstractListener implements Listener {
// Process login
onAsyncLogin(e.getUniqueId(), e.getName());
// Pre-process the user's permissions, so they're ready for PLE.
BukkitUser user = (BukkitUser) plugin.getUserManager().get(plugin.getUuidCache().getUUID(e.getUniqueId()));
Map<String, Boolean> toApply = user.exportNodes(
new Contexts(
Collections.singletonMap("server", plugin.getConfiguration().getServer()),
plugin.getConfiguration().isIncludingGlobalPerms(),
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
true,
plugin.getConfiguration().isApplyingGlobalGroups(),
plugin.getConfiguration().isApplyingGlobalWorldGroups()
),
Collections.emptyList(),
true
);
user.setLoginPreProcess(toApply);
// Hook with Vault early
if (plugin.getVaultHook() != null && plugin.getVaultHook().isHooked()) {
plugin.getVaultHook().getPermissionHook().getVaultUserManager().setupUser(user);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerPreLoginMonitor(AsyncPlayerPreLoginEvent e) {
if (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
final UUID internal = plugin.getUuidCache().getUUID(e.getUniqueId());
onLeave(e.getUniqueId());
if (plugin.getVaultHook() != null && plugin.getVaultHook().isHooked()) {
plugin.getVaultHook().getPermissionHook().getVaultUserManager().clearUser(internal);
}
}
}
@@ -98,61 +74,56 @@ class BukkitListener extends AbstractListener implements Listener {
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
if (user == null) {
// User wasn't loaded for whatever reason.
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
return;
}
BukkitUser u = (BukkitUser) user;
try {
// Make a new permissible for the user
LPPermissible lpPermissible = new LPPermissible(player, plugin, plugin.getDefaultsProvider());
// Insert the pre-processed permissions into the permissible
lpPermissible.getLuckPermsPermissions().putAll(u.getLoginPreProcess());
u.setLoginPreProcess(null);
LPPermissible lpPermissible = new LPPermissible(player, user, plugin);
// Inject into the player
Injector.inject(player, lpPermissible);
u.setLpPermissible(lpPermissible);
} catch (Throwable t) {
t.printStackTrace();
}
if (player.isOp()) {
// We assume all users are not op, but those who are need extra calculation.
plugin.doAsync(() -> user.getUserData().preCalculate(plugin.getPreProcessContexts(true)));
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerLoginMonitor(PlayerLoginEvent e) {
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
// The player got denied on sync login.
final UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
onLeave(e.getPlayer().getUniqueId());
if (plugin.getVaultHook() != null && plugin.getVaultHook().isHooked()) {
plugin.getVaultHook().getPermissionHook().getVaultUserManager().clearUser(internal);
}
} else {
User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
// Call another update to calculate full context. (incl. per world permissions)
plugin.doAsync(user::refreshPermissions);
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoin(PlayerJoinEvent e) {
// Refresh permissions again
UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
plugin.getWorldCalculator().getWorldCache().put(internal, e.getPlayer().getWorld().getName());
plugin.doAsync(() -> refreshPlayer(internal));
}
@EventHandler(priority = EventPriority.LOWEST)
@EventHandler(priority = EventPriority.MONITOR) // Allow other plugins to see data when this event gets called.
public void onPlayerQuit(PlayerQuitEvent e) {
final UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
final Player player = e.getPlayer();
final UUID internal = plugin.getUuidCache().getUUID(player.getUniqueId());
// Remove from World cache
plugin.getWorldCalculator().getWorldCache().remove(internal);
onLeave(e.getPlayer().getUniqueId());
if (plugin.getVaultHook() != null && plugin.getVaultHook().isHooked()) {
plugin.getVaultHook().getPermissionHook().getVaultUserManager().clearUser(internal);
// Remove the custom permissible
Injector.unInject(player);
// Handle auto op
if (plugin.getConfiguration().isAutoOp()) {
player.setOp(false);
}
// Call internal leave handling
onLeave(player.getUniqueId());
}
@EventHandler
@@ -20,29 +20,21 @@
* SOFTWARE.
*/
package me.lucko.luckperms;
package me.lucko.luckperms.bukkit;
import me.lucko.luckperms.commands.SenderFactory;
import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.common.LuckPermsPlugin;
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;
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) {
@@ -0,0 +1,432 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit;
import lombok.Getter;
import me.lucko.luckperms.ApiHandler;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.bukkit.calculators.AutoOPListener;
import me.lucko.luckperms.bukkit.calculators.ChildPermissionProvider;
import me.lucko.luckperms.bukkit.calculators.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.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.messaging.RedisMessaging;
import me.lucko.luckperms.common.runnables.ExpireTemporaryTask;
import me.lucko.luckperms.common.runnables.UpdateTask;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.storage.StorageFactory;
import me.lucko.luckperms.common.tracks.TrackManager;
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;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.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();
private LPConfiguration configuration;
private UserManager userManager;
private GroupManager groupManager;
private TrackManager trackManager;
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()) {
getLog().info("Found locale file. Attempting to load from it.");
try {
localeManager.loadFromFile(locale);
} catch (Exception e) {
e.printStackTrace();
}
}
// register commands
getLog().info("Registering commands...");
BukkitCommand commandManager = new BukkitCommand(this);
PluginCommand main = getServer().getPluginCommand("luckperms");
main.setExecutor(commandManager);
main.setTabCompleter(commandManager);
main.setAliases(Arrays.asList("perms", "lp", "permissions", "p", "perm"));
// load internal managers
getLog().info("Loading internal permission managers...");
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
userManager = new UserManager(this);
groupManager = new GroupManager(this);
trackManager = new TrackManager();
importer = new Importer(commandManager);
consecutiveExecutor = new ConsecutiveExecutor(commandManager);
calculatorFactory = new BukkitCalculatorFactory(this);
contextManager = new ContextManager<>();
worldCalculator = new WorldCalculator(this);
pm.registerEvents(worldCalculator, this);
contextManager.registerCalculator(worldCalculator);
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
// handle server operators
if (getConfiguration().isAutoOp()) {
contextManager.registerListener(new AutoOPListener());
}
// 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();
}
// 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);
// 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.");
}
@Override
public void onDisable() {
started = false;
getLog().info("Closing datastore...");
storage.shutdown();
if (redisMessaging != null) {
getLog().info("Closing redis...");
redisMessaging.shutdown();
}
getLog().info("Unregistering API...");
ApiHandler.unregisterProvider();
getServer().getServicesManager().unregisterAll(this);
if (vaultHook != null) {
vaultHook.unhook(this);
}
}
@Override
public void doAsync(Runnable r) {
asyncExecutor.execute(r);
}
@Override
public void doSync(Runnable r) {
syncExecutor.execute(r);
}
@Override
public void doAsyncRepeating(Runnable r, long interval) {
getServer().getScheduler().runTaskTimerAsynchronously(this, r, interval, interval);
}
@Override
public String getVersion() {
return getDescription().getVersion();
}
@Override
public PlatformType getType() {
return PlatformType.BUKKIT;
}
@Override
public File getMainDir() {
return getDataFolder();
}
@Override
public int getPlayerCount() {
return getServer().getOnlinePlayers().size();
}
@Override
public List<String> getPlayerList() {
return getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
}
@Override
public Set<UUID> getOnlinePlayers() {
return getServer().getOnlinePlayers().stream().map(Player::getUniqueId).collect(Collectors.toSet());
}
@Override
public boolean isOnline(UUID external) {
return getServer().getPlayer(external) != null;
}
@Override
public List<Sender> getSenders() {
return getServer().getOnlinePlayers().stream()
.map(p -> getSenderFactory().wrap(p))
.collect(Collectors.toList());
}
@Override
public Sender getConsoleSender() {
return getSenderFactory().wrap(getServer().getConsoleSender());
}
@Override
public Set<Contexts> getPreProcessContexts(boolean op) {
Set<ContextSet> c = new HashSet<>();
c.add(ContextSet.empty());
c.add(ContextSet.singleton("server", getConfiguration().getServer()));
// Pre process all worlds
c.addAll(getServer().getWorlds().stream()
.map(World::getName)
.map(s -> {
MutableContextSet set = new MutableContextSet();
set.add("server", getConfiguration().getServer());
set.add("world", s);
return set.makeImmutable();
})
.collect(Collectors.toList())
);
// Pre process the separate Vault server, if any
if (!getConfiguration().getServer().equals(getConfiguration().getVaultServer())) {
c.add(ContextSet.singleton("server", getConfiguration().getVaultServer()));
c.addAll(getServer().getWorlds().stream()
.map(World::getName)
.map(s -> {
MutableContextSet set = new MutableContextSet();
set.add("server", getConfiguration().getVaultServer());
set.add("world", s);
return set.makeImmutable();
})
.collect(Collectors.toList())
);
}
Set<Contexts> contexts = new HashSet<>();
// Convert to full Contexts
contexts.addAll(c.stream()
.map(set -> new Contexts(
set,
getConfiguration().isIncludingGlobalPerms(),
getConfiguration().isIncludingGlobalWorldPerms(),
true,
getConfiguration().isApplyingGlobalGroups(),
getConfiguration().isApplyingGlobalWorldGroups(),
op
))
.collect(Collectors.toSet())
);
// Check for and include varying Vault config options
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())
);
}
return contexts;
}
@Override
public Object getPlugin(String name) {
return getServer().getPluginManager().getPlugin(name);
}
@Override
public Object getService(Class clazz) {
return getServer().getServicesManager().load(clazz);
}
@SuppressWarnings("deprecation")
@Override
public UUID getUUID(String playerName) {
try {
return getServer().getOfflinePlayer(playerName).getUniqueId();
} catch (Exception e) {
return null;
}
}
@Override
public boolean isPluginLoaded(String name) {
return getServer().getPluginManager().isPluginEnabled(name);
}
private void registerPermissions(PermissionDefault def) {
PluginManager pm = getServer().getPluginManager();
for (Permission p : Permission.values()) {
for (String node : p.getNodes()) {
pm.addPermission(new org.bukkit.permissions.Permission(node, def));
}
}
}
}
@@ -20,18 +20,20 @@
* SOFTWARE.
*/
package me.lucko.luckperms.contexts;
package me.lucko.luckperms.bukkit;
import com.google.common.collect.Maps;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import java.util.Map;
import java.util.UUID;
@@ -47,11 +49,11 @@ public class WorldCalculator extends ContextCalculator<Player> implements Listen
private final Map<UUID, String> worldCache = new ConcurrentHashMap<>();
@Override
public Map<String, String> giveApplicableContext(Player subject, Map<String, String> accumulator) {
public MutableContextSet giveApplicableContext(Player subject, MutableContextSet accumulator) {
String world = getWorld(subject);
if (world != null) {
accumulator.put(WORLD_KEY, world);
accumulator.add(Maps.immutableEntry(WORLD_KEY, world));
}
return accumulator;
@@ -69,14 +71,25 @@ 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);
}
@EventHandler(priority = EventPriority.LOW)
public void onPlayerJoin(PlayerLoginEvent e) {
UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
worldCache.put(internal, e.getPlayer().getWorld().getName());
pushUpdate(
e.getPlayer(),
Maps.immutableEntry(WORLD_KEY, null),
Maps.immutableEntry(WORLD_KEY, e.getPlayer().getWorld().getName())
);
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerChangedWorld(PlayerChangedWorldEvent e) {
UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
@@ -20,28 +20,37 @@
* SOFTWARE.
*/
package me.lucko.luckperms.calculators;
package me.lucko.luckperms.bukkit.calculators;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import org.bukkit.permissions.PermissionAttachmentInfo;
import java.util.Map;
import java.util.function.Supplier;
@AllArgsConstructor
public class AttachmentProcessor implements PermissionProcessor {
@Getter
private final Map<String, PermissionAttachmentInfo> map;
private final Supplier<Map<String, PermissionAttachmentInfo>> map;
@Override
public Tristate hasPermission(String permission) {
if (map.containsKey(permission)) {
return Tristate.fromBoolean(map.get(permission).getValue());
Map<String, PermissionAttachmentInfo> m = map.get();
if (m == null) {
return Tristate.UNDEFINED;
}
return Tristate.UNDEFINED;
PermissionAttachmentInfo pai = m.get(permission);
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
}
}
@@ -20,27 +20,28 @@
* SOFTWARE.
*/
package me.lucko.luckperms.contexts;
package me.lucko.luckperms.bukkit.calculators;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.context.ContextCalculator;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.service.context.Context;
import me.lucko.luckperms.api.context.ContextListener;
import me.lucko.luckperms.bukkit.inject.Injector;
import me.lucko.luckperms.bukkit.inject.LPPermissible;
import org.bukkit.entity.Player;
import java.util.Map;
import java.util.Optional;
@RequiredArgsConstructor
public class WorldCalculator extends ContextCalculator<Player> {
public class AutoOPListener implements ContextListener<Player> {
@Override
public Map<String, String> giveApplicableContext(Player subject, Map<String, String> accumulator) {
accumulator.put(Context.WORLD_KEY, subject.getWorld().getName());
return accumulator;
}
public void onContextChange(Player subject, Map.Entry<String, String> before, Map.Entry<String, String> current) throws Exception {
LPPermissible permissible = Injector.getPermissible(subject.getUniqueId());
if (permissible == null) {
return;
}
@Override
public boolean isContextApplicable(Player subject, Map.Entry<String, String> context) {
return context.getKey().equals(Context.WORLD_KEY) && subject.getWorld().getName().equals(context.getValue());
Map<String, Boolean> backing = permissible.getUser().getUserData().getPermissionData(permissible.calculateContexts()).getImmutableBacking();
boolean op = Optional.ofNullable(backing.get("luckperms.autoop")).orElse(false);
subject.setOp(op);
}
}
@@ -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.calculators;
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);
}
}
}
}
@@ -0,0 +1,53 @@
/*
* 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.calculators;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@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 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);
}
}
}
}
@@ -20,32 +20,34 @@
* SOFTWARE.
*/
package me.lucko.luckperms.calculators;
package me.lucko.luckperms.bukkit.calculators;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import org.bukkit.Bukkit;
import org.bukkit.permissions.Permission;
import java.util.function.Supplier;
import java.util.Map;
@AllArgsConstructor
public class DefaultsProcessor implements PermissionProcessor {
private final Supplier<Boolean> isOp;
private final boolean isOp;
private final DefaultsProvider defaultsProvider;
@Override
public Tristate hasPermission(String permission) {
Tristate t = defaultsProvider.hasDefault(permission, isOp.get());
Tristate t = defaultsProvider.hasDefault(permission, isOp);
if (t != Tristate.UNDEFINED) {
return t;
}
Permission defPerm = Bukkit.getServer().getPluginManager().getPermission(permission);
if (defPerm != null) {
return Tristate.fromBoolean(defPerm.getDefault().getValue(isOp.get()));
} else {
return Tristate.UNDEFINED;
}
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
}
}
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.calculators;
package me.lucko.luckperms.bukkit.calculators;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.Tristate;
@@ -97,11 +97,9 @@ public class DefaultsProvider {
public Tristate hasDefault(String permission, boolean isOp) {
Map<String, Boolean> map = isOp ? op : nonOp;
if (!map.containsKey(permission)) {
return Tristate.UNDEFINED;
}
return Tristate.fromBoolean(map.get(permission));
Boolean b = map.get(permission);
return b == null ? Tristate.UNDEFINED : Tristate.fromBoolean(b);
}
@AllArgsConstructor
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.inject;
package me.lucko.luckperms.bukkit.inject;
import org.bukkit.permissions.PermissibleBase;
import org.bukkit.permissions.Permission;
@@ -20,37 +20,39 @@
* SOFTWARE.
*/
package me.lucko.luckperms.inject;
package me.lucko.luckperms.bukkit.inject;
import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permissible;
import org.bukkit.permissions.PermissibleBase;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* Injects a {@link LPPermissible} into a {@link Player}
*/
@UtilityClass
public class Injector {
private static final Map<UUID, LPPermissible> INJECTED_PERMISSIBLES = new ConcurrentHashMap<>();
private static Field HUMAN_ENTITY_FIELD;
static {
try {
HUMAN_ENTITY_FIELD = Class.forName(getInternalClassName("entity.CraftHumanEntity")).getDeclaredField("perm");
HUMAN_ENTITY_FIELD = Class.forName(getVersionedClassName("entity.CraftHumanEntity")).getDeclaredField("perm");
HUMAN_ENTITY_FIELD.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public static boolean inject(CommandSender sender, PermissibleBase permissible) {
public static boolean inject(Player player, LPPermissible permissible) {
try {
Field f = getPermField(sender);
f.set(sender, permissible);
HUMAN_ENTITY_FIELD.set(player, permissible);
INJECTED_PERMISSIBLES.put(player.getUniqueId(), permissible);
return true;
} catch (Exception e) {
e.printStackTrace();
@@ -58,15 +60,16 @@ public class Injector {
}
}
public static boolean unInject(CommandSender sender) {
public static boolean unInject(Player player) {
try {
Permissible permissible = getPermissible(sender);
Permissible permissible = (Permissible) HUMAN_ENTITY_FIELD.get(player);
if (permissible instanceof LPPermissible) {
/* The player is most likely leaving. Bukkit will attempt to call #clearPermissions, so we cannot set to null.
However, there's no need to re-inject a real PermissibleBase, so we just inject a dummy instead.
This saves tick time, pointlessly recalculating defaults when the instance will never be used. */
getPermField(sender).set(sender, new DummyPermissibleBase());
HUMAN_ENTITY_FIELD.set(player, new DummyPermissibleBase());
}
INJECTED_PERMISSIBLES.remove(player.getUniqueId());
return true;
} catch (Exception e) {
e.printStackTrace();
@@ -74,23 +77,11 @@ public class Injector {
}
}
private static Permissible getPermissible(CommandSender sender) {
try {
Field f = getPermField(sender);
return (Permissible) f.get(sender);
} catch (Exception e) {
throw new RuntimeException(e);
}
public static LPPermissible getPermissible(UUID uuid) {
return INJECTED_PERMISSIBLES.get(uuid);
}
private static Field getPermField(CommandSender sender) {
if (sender instanceof Player) {
return HUMAN_ENTITY_FIELD;
}
throw new RuntimeException("Couldn't get perm field for sender " + sender.getClass().getName());
}
private static String getInternalClassName(String className) {
private static String getVersionedClassName(String className) {
Class server = Bukkit.getServer().getClass();
if (!server.getSimpleName().equals("CraftServer")) {
throw new RuntimeException("Couldn't inject into server " + server);
@@ -20,20 +20,20 @@
* SOFTWARE.
*/
package me.lucko.luckperms.inject;
package me.lucko.luckperms.bukkit.inject;
import lombok.Getter;
import lombok.NonNull;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.calculators.*;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.users.User;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.permissions.*;
import org.bukkit.plugin.Plugin;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.stream.Collectors;
@@ -43,42 +43,41 @@ import java.util.stream.Collectors;
public class LPPermissible extends PermissibleBase {
@Getter
private final CommandSender parent;
private final PermissionCalculator calculator;
private final User user;
@Getter
private final Map<String, Boolean> luckPermsPermissions = new ConcurrentHashMap<>();
private final List<PermissionAttachment> attachments = new LinkedList<>();
private final Player parent;
private final LPBukkitPlugin plugin;
// Attachment stuff.
@Getter
private final Map<String, PermissionAttachmentInfo> attachmentPermissions = new HashMap<>();
private final List<PermissionAttachment> attachments = new LinkedList<>();
public LPPermissible(@NonNull CommandSender sender, LuckPermsPlugin plugin, DefaultsProvider defaultsProvider) {
super(sender);
this.parent = sender;
List<PermissionProcessor> processors = new ArrayList<>(5);
processors.add(new MapProcessor(luckPermsPermissions));
processors.add(new AttachmentProcessor(attachmentPermissions));
if (plugin.getConfiguration().isApplyingWildcards()) {
processors.add(new WildcardProcessor(luckPermsPermissions));
}
if (plugin.getConfiguration().isApplyingRegex()) {
processors.add(new RegexProcessor(luckPermsPermissions));
}
processors.add(new DefaultsProcessor(parent::isOp, defaultsProvider));
calculator = new PermissionCalculator(plugin, parent.getName(), plugin.getConfiguration().isDebugPermissionChecks(), processors);
public LPPermissible(@NonNull Player parent, User user, LPBukkitPlugin plugin) {
super(parent);
this.user = user;
this.parent = parent;
this.plugin = plugin;
recalculatePermissions();
}
public void invalidateCache() {
calculator.invalidateCache();
public Contexts calculateContexts() {
return new Contexts(
plugin.getContextManager().getApplicableContext(parent),
plugin.getConfiguration().isIncludingGlobalPerms(),
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
true,
plugin.getConfiguration().isApplyingGlobalGroups(),
plugin.getConfiguration().isApplyingGlobalWorldGroups(),
parent.isOp()
);
}
@Override
public boolean isOp() {
return parent.isOp();
private boolean hasData() {
return user.getUserData() != null;
}
@Override
@@ -88,7 +87,7 @@ public class LPPermissible extends PermissibleBase {
@Override
public boolean isPermissionSet(@NonNull String name) {
return calculator.getPermissionValue(name) != Tristate.UNDEFINED;
return hasData() && user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(name) != Tristate.UNDEFINED;
}
@Override
@@ -98,9 +97,11 @@ public class LPPermissible extends PermissibleBase {
@Override
public boolean hasPermission(@NonNull String name) {
Tristate ts = calculator.getPermissionValue(name);
if (ts != Tristate.UNDEFINED) {
return ts.asBoolean();
if (hasData()) {
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(name);
if (ts != Tristate.UNDEFINED) {
return ts.asBoolean();
}
}
return Permission.DEFAULT_PERMISSION.getValue(isOp());
@@ -108,14 +109,32 @@ public class LPPermissible extends PermissibleBase {
@Override
public boolean hasPermission(@NonNull Permission perm) {
Tristate ts = calculator.getPermissionValue(perm.getName());
if (ts != Tristate.UNDEFINED) {
return ts.asBoolean();
if (hasData()) {
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(perm.getName());
if (ts != Tristate.UNDEFINED) {
return ts.asBoolean();
}
}
return perm.getDefault().getValue(isOp());
}
@Override
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
Set<PermissionAttachmentInfo> perms = new HashSet<>();
perms.addAll(attachmentPermissions.values());
if (hasData()) {
perms.addAll(
user.getUserData().getPermissionData(calculateContexts()).getImmutableBacking().entrySet().stream()
.map(e -> new PermissionAttachmentInfo(parent, e.getKey(), null, e.getValue()))
.collect(Collectors.toList())
);
}
return perms;
}
@Override
public PermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String name, boolean value) {
if (!plugin.isEnabled()) {
@@ -165,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;
@@ -202,7 +221,9 @@ public class LPPermissible extends PermissibleBase {
calculateChildPermissions(attachment.getPermissions(), false, attachment);
}
invalidateCache();
if (hasData()) {
user.getUserData().invalidatePermissionCalculators();
}
}
@Override
@@ -233,28 +254,4 @@ public class LPPermissible extends PermissibleBase {
}
}
}
@Override
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
Set<PermissionAttachmentInfo> perms = new HashSet<>();
perms.addAll(attachmentPermissions.values());
perms.addAll(luckPermsPermissions.entrySet().stream()
.map(e -> new PermissionAttachmentInfo(parent, e.getKey(), null, e.getValue()))
.collect(Collectors.toList()));
return perms;
}
private class RemoveAttachmentRunnable implements Runnable {
private PermissionAttachment attachment;
private RemoveAttachmentRunnable(PermissionAttachment attachment) {
this.attachment = attachment;
}
public void run() {
attachment.remove();
}
}
}
@@ -20,26 +20,27 @@
* SOFTWARE.
*/
package me.lucko.luckperms.commands.migration.subcommands;
package me.lucko.luckperms.bukkit.migration;
import de.bananaco.bpermissions.api.*;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.commands.CommandResult;
import me.lucko.luckperms.commands.Predicate;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.commands.SubCommand;
import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.core.PermissionHolder;
import me.lucko.luckperms.data.LogEntry;
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.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 me.lucko.luckperms.utils.ArgumentChecker;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import static me.lucko.luckperms.constants.Permission.MIGRATION;
import static me.lucko.luckperms.common.constants.Permission.MIGRATION;
public class MigrationBPermissions extends SubCommand<Object> {
private static Field uConfigField;
@@ -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,8 +122,8 @@ public class MigrationBPermissions extends SubCommand<Object> {
}
// Make a LuckPerms group for the one being migrated.
plugin.getDatastore().createAndLoadGroup(groupName);
me.lucko.luckperms.groups.Group lpGroup = plugin.getGroupManager().get(groupName);
plugin.getStorage().createAndLoadGroup(groupName).join();
me.lucko.luckperms.common.groups.Group lpGroup = plugin.getGroupManager().get(groupName);
try {
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
@@ -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");
me.lucko.luckperms.users.User lpUser = plugin.getUserManager().get(uuid);
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);
}
@@ -222,7 +223,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
// Migrate existing meta
for (Map.Entry<String, String> meta : c.getMeta().entrySet()) {
if (meta.getKey().equalsIgnoreCase("prefix") || meta.getKey().equalsIgnoreCase("suffix")) {
String chatMeta = ArgumentChecker.escapeCharacters(meta.getValue());
String chatMeta = MetaUtils.escapeCharacters(meta.getValue());
try {
holder.setPermission(meta.getKey().toLowerCase() + "." + c.getPriority() + "." + chatMeta, true);
LogEntry.build()
@@ -20,15 +20,22 @@
* SOFTWARE.
*/
package me.lucko.luckperms.commands.migration.subcommands;
package me.lucko.luckperms.bukkit.migration;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.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,18 +69,11 @@ 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());
me.lucko.luckperms.groups.Group group = plugin.getGroupManager().get(g.getName().toLowerCase());
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase()).join();
me.lucko.luckperms.common.groups.Group group = plugin.getGroupManager().get(g.getName().toLowerCase());
try {
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
@@ -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,8 +195,8 @@ 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());
me.lucko.luckperms.groups.Group group = plugin.getGroupManager().get(e.getKey());
plugin.getStorage().createAndLoadGroup(e.getKey()).join();
me.lucko.luckperms.common.groups.Group group = plugin.getGroupManager().get(e.getKey());
try {
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
@@ -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,19 +234,19 @@ 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");
me.lucko.luckperms.users.User user = plugin.getUserManager().get(e.getKey());
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()) {
// n.key.key = world
// 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,19 +20,24 @@
* SOFTWARE.
*/
package me.lucko.luckperms.commands.migration.subcommands;
package me.lucko.luckperms.bukkit.migration;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.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 me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import ru.tehkode.permissions.NativeInterface;
import ru.tehkode.permissions.PermissionGroup;
import ru.tehkode.permissions.PermissionManager;
@@ -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);
plugin.getStorage().createAndLoadGroup(name).join();
Group lpGroup = plugin.getGroupManager().get(name);
try {
LogEntry.build()
@@ -197,7 +195,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
String suffix = group.getOwnSuffix();
if (prefix != null && !prefix.equals("")) {
prefix = ArgumentChecker.escapeCharacters(prefix);
prefix = MetaUtils.escapeCharacters(prefix);
try {
lpGroup.setPermission("prefix." + groupWeight + "." + prefix, true);
LogEntry.build()
@@ -212,7 +210,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
}
if (suffix != null && !suffix.equals("")) {
suffix = ArgumentChecker.escapeCharacters(suffix);
suffix = MetaUtils.escapeCharacters(suffix);
try {
lpGroup.setPermission("suffix." + groupWeight + "." + suffix, true);
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");
plugin.getStorage().loadUser(u, "null").join();
User lpUser = plugin.getUserManager().get(u);
try {
@@ -341,7 +339,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
String suffix = user.getOwnSuffix();
if (prefix != null && !prefix.equals("")) {
prefix = ArgumentChecker.escapeCharacters(prefix);
prefix = MetaUtils.escapeCharacters(prefix);
try {
lpUser.setPermission("prefix." + maxGroupWeight + "." + prefix, true);
LogEntry.build()
@@ -356,7 +354,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
}
if (suffix != null && !suffix.equals("")) {
suffix = ArgumentChecker.escapeCharacters(suffix);
suffix = MetaUtils.escapeCharacters(suffix);
try {
lpUser.setPermission("suffix." + maxGroupWeight + "." + suffix, true);
LogEntry.build()
@@ -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,22 +20,27 @@
* SOFTWARE.
*/
package me.lucko.luckperms.commands.migration.subcommands;
package me.lucko.luckperms.bukkit.migration;
import com.github.cheesesoftware.PowerfulPermsAPI.*;
import com.google.common.util.concurrent.ListenableFuture;
import com.zaxxer.hikari.HikariDataSource;
import lombok.Cleanup;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.commands.migration.subcommands.utils.LPResultRunnable;
import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.core.PermissionHolder;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.bukkit.migration.utils.LPResultRunnable;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.core.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 me.lucko.luckperms.users.User;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -47,7 +52,7 @@ import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import static me.lucko.luckperms.constants.Permission.MIGRATION;
import static me.lucko.luckperms.common.constants.Permission.MIGRATION;
@SuppressWarnings("unchecked")
public class MigrationPowerfulPerms extends SubCommand<Object> {
@@ -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,8 +251,8 @@ 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());
final me.lucko.luckperms.groups.Group group = plugin.getGroupManager().get(g.getName().toLowerCase());
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase()).join();
final me.lucko.luckperms.common.groups.Group group = plugin.getGroupManager().get(g.getName().toLowerCase());
try {
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
@@ -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");
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);
}
}
@@ -20,19 +20,24 @@
* SOFTWARE.
*/
package me.lucko.luckperms.commands.migration.subcommands;
package me.lucko.luckperms.bukkit.migration;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
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.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.tracks.Track;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
import java.util.List;
@@ -40,19 +45,15 @@ import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* <3 <3 zPermissions <3 <3
* Finally a permissions plugin with a decent API. *sigh*
*/
public class MigrationZPermissions extends SubCommand<Object> {
public MigrationZPermissions() {
super("zpermissions", "Migration from zPermissions", Permission.MIGRATION, Predicate.alwaysFalse(),
super("zpermissions", "Migration from zPermissions", Permission.MIGRATION, Predicates.alwaysFalse(),
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("zPermissions")) {
log.severe("zPermissions Migration: Error -> zPermissions is not loaded.");
@@ -72,7 +73,7 @@ public class MigrationZPermissions extends SubCommand<Object> {
// Migrate all groups
log.info("zPermissions Migration: Starting group migration.");
for (String g : service.getAllGroups()) {
plugin.getDatastore().createAndLoadGroup(g.toLowerCase());
plugin.getStorage().createAndLoadGroup(g.toLowerCase()).join();
Group group = plugin.getGroupManager().get(g.toLowerCase());
try {
LogEntry.build()
@@ -115,13 +116,13 @@ public class MigrationZPermissions extends SubCommand<Object> {
}
}
plugin.getDatastore().saveGroup(group);
plugin.getStorage().saveGroup(group);
}
// Migrate all tracks
log.info("zPermissions Migration: Starting track migration.");
for (String t : service.getAllTracks()) {
plugin.getDatastore().createAndLoadTrack(t.toLowerCase());
plugin.getStorage().createAndLoadTrack(t.toLowerCase()).join();
Track track = plugin.getTrackManager().get(t.toLowerCase());
try {
LogEntry.build()
@@ -144,13 +145,13 @@ public class MigrationZPermissions extends SubCommand<Object> {
}
}
plugin.getDatastore().saveTrack(track);
plugin.getStorage().saveTrack(track);
}
// Migrate all users.
log.info("zPermissions Migration: Starting user migration.");
for (UUID u : service.getAllPlayersUUID()) {
plugin.getDatastore().loadUser(u, "null");
plugin.getStorage().loadUser(u, "null").join();
User user = plugin.getUserManager().get(u);
for (Map.Entry<String, Boolean> e : service.getPlayerPermissions(null, null, u).entrySet()) {
@@ -213,7 +214,7 @@ public class MigrationZPermissions extends SubCommand<Object> {
String suffix = service.getPlayerSuffix(u);
if (prefix != null && !prefix.equals("")) {
prefix = ArgumentChecker.escapeCharacters(prefix);
prefix = MetaUtils.escapeCharacters(prefix);
try {
user.setPermission("prefix.100." + prefix, true);
LogEntry.build()
@@ -228,7 +229,7 @@ public class MigrationZPermissions extends SubCommand<Object> {
}
if (suffix != null && !suffix.equals("")) {
suffix = ArgumentChecker.escapeCharacters(suffix);
suffix = MetaUtils.escapeCharacters(suffix);
try {
user.setPermission("suffix.100." + suffix, true);
LogEntry.build()
@@ -243,7 +244,7 @@ public class MigrationZPermissions extends SubCommand<Object> {
}
plugin.getUserManager().cleanup(user);
plugin.getDatastore().saveUser(user);
plugin.getStorage().saveUser(user);
}
log.info("zPermissions Migration: Success! Completed without any errors.");
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.commands.migration.subcommands.utils;
package me.lucko.luckperms.bukkit.migration.utils;
import com.github.cheesesoftware.PowerfulPermsAPI.ResultRunnable;
@@ -20,18 +20,19 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.vault;
package me.lucko.luckperms.bukkit.vault;
import lombok.NonNull;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.vault.cache.ChatCache;
import me.lucko.luckperms.api.vault.cache.VaultUser;
import me.lucko.luckperms.core.PermissionHolder;
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.PermissionHolder;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.users.User;
import net.milkbowl.vault.chat.Chat;
import java.util.HashMap;
@@ -39,8 +40,8 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static me.lucko.luckperms.utils.ArgumentChecker.escapeCharacters;
import static me.lucko.luckperms.utils.ArgumentChecker.unescapeCharacters;
import static me.lucko.luckperms.api.MetaUtils.escapeCharacters;
import static me.lucko.luckperms.api.MetaUtils.unescapeCharacters;
/**
* Provides the Vault Chat service through the use of normal permission nodes.
@@ -56,7 +57,7 @@ import static me.lucko.luckperms.utils.ArgumentChecker.unescapeCharacters;
* Permission Nodes = meta.node.value
*
* Node that special characters used within LuckPerms are escaped:
* See {@link me.lucko.luckperms.utils.ArgumentChecker#escapeCharacters(String)}
* See {@link me.lucko.luckperms.api.MetaUtils#unescapeCharacters(String)}
*/
public class VaultChatHook extends Chat {
private final VaultPermissionHook perms;
@@ -74,11 +75,14 @@ public class VaultChatHook extends Chat {
return perms.isEnabled();
}
private void saveMeta(PermissionHolder holder, String world, String node, String value) {
private void setMeta(PermissionHolder holder, String world, String node, String value) {
String finalWorld = perms.isIgnoreWorld() ? null : world;
if (holder == null) return;
if (node.equals("")) return;
perms.scheduleTask(() -> {
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);
@@ -92,12 +96,12 @@ public class VaultChatHook extends Chat {
} catch (ObjectLacksException ignored) {}
});
Node.Builder metaNode = new me.lucko.luckperms.core.Node.Builder("meta." + k + "." + v).setValue(true);
Node.Builder metaNode = new NodeBuilder("meta." + k + "." + v).setValue(true);
if (!perms.getServer().equalsIgnoreCase("global")) {
metaNode.setServer(perms.getServer());
}
if (world != null && !world.equals("")) {
metaNode.setServer(perms.getServer()).setWorld(world);
if (finalWorld != null && !finalWorld.equals("")) {
metaNode.setServer(perms.getServer()).setWorld(finalWorld);
}
try {
@@ -109,18 +113,21 @@ public class VaultChatHook extends Chat {
}
private void setChatMeta(boolean prefix, PermissionHolder holder, String value, String world) {
String finalWorld = perms.isIgnoreWorld() ? null : world;
if (holder == null) return;
if (value.equals("")) return;
perms.scheduleTask(() -> {
Node.Builder node = new me.lucko.luckperms.core.Node.Builder(prefix ? "prefix" : "suffix" + ".1000." + escapeCharacters(value));
perms.log("Setting " + (prefix ? "prefix" : "suffix") + " for " + holder.getObjectName() + " on world " + world + ", server " + perms.getServer());
perms.getScheduler().scheduleTask(() -> {
Node.Builder node = new NodeBuilder(prefix ? "prefix" : "suffix" + ".1000." + escapeCharacters(value));
node.setValue(true);
if (!perms.getServer().equalsIgnoreCase("global")) {
node.setServer(perms.getServer());
}
if (world != null && !world.equals("")) {
node.setServer(perms.getServer()).setWorld(world);
if (finalWorld != null && !finalWorld.equals("")) {
node.setServer(perms.getServer()).setWorld(finalWorld);
}
try {
@@ -133,46 +140,41 @@ public class VaultChatHook extends Chat {
private String getUserMeta(User user, String world, String node, String defaultValue) {
if (user == null) return defaultValue;
world = perms.isIgnoreWorld() ? null : world;
node = escapeCharacters(node);
if (!perms.getVaultUserManager().containsUser(user.getUuid())) {
perms.log("Getting meta: '" + node + "' for user " + user.getName() + " on world " + world + ", server " + perms.getServer());
if (user.getUserData() == null) {
return defaultValue;
}
VaultUser vaultUser = perms.getVaultUserManager().getUser(user.getUuid());
Map<String, String> context = new HashMap<>();
context.put("server", perms.getServer());
if (world != null) {
context.put("world", world);
}
ChatCache cd = vaultUser.processChatData(context);
return unescapeCharacters(cd.getMeta().getOrDefault(node, defaultValue));
return unescapeCharacters(user.getUserData().getMetaData(perms.createContext(perms.getServer(), world)).getMeta().getOrDefault(node, defaultValue));
}
private String getUserChatMeta(boolean prefix, User user, String world) {
if (user == null) return "";
world = perms.isIgnoreWorld() ? null : world;
if (!perms.getVaultUserManager().containsUser(user.getUuid())) {
perms.log("Getting " + (prefix ? "prefix" : "suffix") + " for user " + user.getName() + " on world " + world + ", server " + perms.getServer());
if (user.getUserData() == null) {
return "";
}
VaultUser vaultUser = perms.getVaultUserManager().getUser(user.getUuid());
Map<String, String> context = new HashMap<>();
context.put("server", perms.getServer());
if (world != null) {
context.put("world", world);
}
ChatCache cd = vaultUser.processChatData(context);
return unescapeCharacters(prefix ? (cd.getPrefix() == null ? "" : cd.getPrefix()) : (cd.getSuffix() == null ? "" : cd.getSuffix()));
MetaData data = user.getUserData().getMetaData(perms.createContext(perms.getServer(), world));
String v = prefix ? data.getPrefix() : data.getSuffix();
return v == null ? "" : unescapeCharacters(v);
}
private String getGroupMeta(Group group, String world, String node, String defaultValue) {
world = perms.isIgnoreWorld() ? null : world;
if (group == null) return defaultValue;
if (node.equals("")) return defaultValue;
node = escapeCharacters(node);
perms.log("Getting meta: '" + node + "' for group " + group.getName() + " on world " + world + ", server " + perms.getServer());
for (Node n : group.getPermissions(true)) {
if (!n.getValue()) {
continue;
@@ -200,8 +202,11 @@ public class VaultChatHook extends Chat {
}
private String getGroupChatMeta(boolean prefix, Group group, String world) {
world = perms.isIgnoreWorld() ? null : world;
if (group == null) return "";
perms.log("Getting " + (prefix ? "prefix" : "suffix") + " for group " + group + " on world " + world + ", server " + perms.getServer());
int priority = Integer.MIN_VALUE;
String meta = null;
@@ -211,7 +216,7 @@ public class VaultChatHook extends Chat {
context.put("world", world);
}
for (Node n : group.getAllNodes(null, new Contexts(context, perms.isIncludeGlobal(), true, true, true, true))) {
for (Node n : group.getAllNodes(null, new Contexts(ContextSet.fromMap(context), perms.isIncludeGlobal(), true, true, true, true, false))) {
if (!n.getValue()) {
continue;
}
@@ -289,7 +294,7 @@ public class VaultChatHook extends Chat {
public void setPlayerInfoInteger(String world, @NonNull String player, @NonNull String node, int value) {
final User user = perms.getPlugin().getUserManager().get(player);
saveMeta(user, world, node, String.valueOf(value));
setMeta(user, world, node, String.valueOf(value));
}
public int getGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int defaultValue) {
@@ -303,7 +308,7 @@ public class VaultChatHook extends Chat {
public void setGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int value) {
final Group g = perms.getPlugin().getGroupManager().get(group);
saveMeta(g, world, node, String.valueOf(value));
setMeta(g, world, node, String.valueOf(value));
}
public double getPlayerInfoDouble(String world, @NonNull String player, @NonNull String node, double defaultValue) {
@@ -317,7 +322,7 @@ public class VaultChatHook extends Chat {
public void setPlayerInfoDouble(String world, @NonNull String player, @NonNull String node, double value) {
final User user = perms.getPlugin().getUserManager().get(player);
saveMeta(user, world, node, String.valueOf(value));
setMeta(user, world, node, String.valueOf(value));
}
public double getGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double defaultValue) {
@@ -331,7 +336,7 @@ public class VaultChatHook extends Chat {
public void setGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double value) {
final Group g = perms.getPlugin().getGroupManager().get(group);
saveMeta(g, world, node, String.valueOf(value));
setMeta(g, world, node, String.valueOf(value));
}
public boolean getPlayerInfoBoolean(String world, @NonNull String player, @NonNull String node, boolean defaultValue) {
@@ -345,7 +350,7 @@ public class VaultChatHook extends Chat {
public void setPlayerInfoBoolean(String world, @NonNull String player, @NonNull String node, boolean value) {
final User user = perms.getPlugin().getUserManager().get(player);
saveMeta(user, world, node, String.valueOf(value));
setMeta(user, world, node, String.valueOf(value));
}
public boolean getGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean defaultValue) {
@@ -359,7 +364,7 @@ public class VaultChatHook extends Chat {
public void setGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean value) {
final Group g = perms.getPlugin().getGroupManager().get(group);
saveMeta(g, world, node, String.valueOf(value));
setMeta(g, world, node, String.valueOf(value));
}
public String getPlayerInfoString(String world, @NonNull String player, @NonNull String node, String defaultValue) {
@@ -369,7 +374,7 @@ public class VaultChatHook extends Chat {
public void setPlayerInfoString(String world, @NonNull String player, @NonNull String node, String value) {
final User user = perms.getPlugin().getUserManager().get(player);
saveMeta(user, world, node, value);
setMeta(user, world, node, value);
}
public String getGroupInfoString(String world, @NonNull String group, @NonNull String node, String defaultValue) {
@@ -379,7 +384,7 @@ public class VaultChatHook extends Chat {
public void setGroupInfoString(String world, @NonNull String group, @NonNull String node, String value) {
final Group g = perms.getPlugin().getGroupManager().get(group);
saveMeta(g, world, node, value);
setMeta(g, world, node, value);
}
}
@@ -20,10 +20,10 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.vault;
package me.lucko.luckperms.bukkit.vault;
import lombok.Getter;
import me.lucko.luckperms.LPBukkitPlugin;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import net.milkbowl.vault.chat.Chat;
import net.milkbowl.vault.permission.Permission;
import org.bukkit.plugin.ServicePriority;
@@ -42,6 +42,11 @@ public class VaultHook {
permissionHook.setPlugin(plugin);
permissionHook.setServer(plugin.getConfiguration().getVaultServer());
permissionHook.setIncludeGlobal(plugin.getConfiguration().isVaultIncludingGlobal());
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) {
@@ -0,0 +1,400 @@
/*
* 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.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;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import net.milkbowl.vault.permission.Permission;
import java.util.HashMap;
import java.util.Map;
/**
* The LuckPerms Vault Permission implementation
* Most lookups are cached.
*/
@Getter
@Setter
public class VaultPermissionHook extends Permission {
private LPBukkitPlugin plugin;
@Setter(value = AccessLevel.NONE)
private VaultScheduler scheduler;
private String server = "global";
private boolean includeGlobal = true;
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().isVaultDebug()) {
plugin.getLog().info("[VAULT] " + s);
}
}
@Override
public String getName() {
return "LuckPerms";
}
@Override
public boolean isEnabled() {
return plugin.getStorage().isAcceptingLogins();
}
@Override
public boolean hasSuperPermsCompat() {
return true;
}
/**
* Generic method to add a permission to a holder
* @param world the world to add in
* @param holder the holder to add the permission to
* @param permission the permission to add
*/
private void add(String world, PermissionHolder holder, String permission) {
try {
if (world != null && !world.equals("")) {
holder.setPermission(permission, true, server, world);
} else {
holder.setPermission(permission, true, server);
}
} catch (ObjectAlreadyHasException ignored) {}
save(holder);
}
/**
* Generic method to remove a permission from a holder
* @param world the world to remove in
* @param holder the holder to remove the permission from
* @param permission the permission to remove
*/
private void remove(String world, PermissionHolder holder, String permission) {
try {
if (world != null && !world.equals("")) {
holder.unsetPermission(permission, server, world);
} else {
holder.unsetPermission(permission, server);
}
} catch (ObjectLacksException ignored) {}
save(holder);
}
/**
* Utility method for saving a user or group
* @param holder the holder instance
*/
void save(PermissionHolder holder) {
if (holder instanceof User) {
plugin.getStorage().saveUser(((User) holder))
.thenRunAsync(() -> ((User) holder).getRefreshBuffer().request(), plugin.getAsyncExecutor());
}
if (holder instanceof Group) {
plugin.getStorage().saveGroup(((Group) holder))
.thenRunAsync(() -> plugin.getUpdateTaskBuffer().request(), plugin.getAsyncExecutor());
}
}
Contexts createContext(String server, String world) {
Map<String, String> context = new HashMap<>();
if (world != null && !world.equals("")) {
context.put("world", world);
}
context.put("server", server);
return new Contexts(ContextSet.fromMap(context), isIncludeGlobal(), true, true, true, true, false);
}
@Override
public boolean playerHas(String world, @NonNull String player, @NonNull String permission) {
world = ignoreWorld ? null : world; // Correct world value
log("Checking if player " + player + " has permission: " + permission + " on world " + world + ", server " + server);
User user = plugin.getUserManager().get(player);
if (user == null) return false;
if (user.getUserData() == null) {
return false;
}
// Effectively fallback to the standard Bukkit #hasPermission check.
return user.getUserData().getPermissionData(createContext(server, world)).getPermissionValue(permission).asBoolean();
}
@Override
public boolean playerAdd(String world, @NonNull String player, @NonNull String permission) {
String finalWorld = ignoreWorld ? null : world; // Correct world value
log("Adding permission to player " + player + ": '" + permission + "' on world " + finalWorld + ", server " + server);
final User user = plugin.getUserManager().get(player);
if (user == null) return false;
scheduler.scheduleTask(() -> add(finalWorld, user, permission));
return true;
}
@Override
public boolean playerRemove(String world, @NonNull String player, @NonNull String permission) {
String finalWorld = ignoreWorld ? null : world; // Correct world value
log("Removing permission from player " + player + ": '" + permission + "' on world " + finalWorld + ", server " + server);
final User user = plugin.getUserManager().get(player);
if (user == null) return false;
scheduler.scheduleTask(() -> remove(finalWorld, user, permission));
return true;
}
@Override
public boolean groupHas(String world, @NonNull String groupName, @NonNull String permission) {
world = ignoreWorld ? null : world; // Correct world value
log("Checking if group " + groupName + " has permission: " + permission + " on world " + world + ", server " + server);
final Group group = plugin.getGroupManager().get(groupName);
if (group == null) return false;
// This is a nasty call. Groups aren't cached. :(
Map<String, Boolean> permissions = group.exportNodes(createContext(server, world), true);
return permissions.containsKey(permission) && permissions.get(permission);
}
@Override
public boolean groupAdd(String world, @NonNull String groupName, @NonNull String permission) {
String finalWorld = ignoreWorld ? null : world; // Correct world value
log("Adding permission to group " + groupName + ": '" + permission + "' on world " + finalWorld + ", server " + server);
final Group group = plugin.getGroupManager().get(groupName);
if (group == null) return false;
scheduler.scheduleTask(() -> add(finalWorld, group, permission));
return true;
}
@Override
public boolean groupRemove(String world, @NonNull String groupName, @NonNull String permission) {
String finalWorld = ignoreWorld ? null : world; // Correct world value
log("Removing permission from group " + groupName + ": '" + permission + "' on world " + finalWorld + ", server " + server);
final Group group = plugin.getGroupManager().get(groupName);
if (group == null) return false;
scheduler.scheduleTask(() -> remove(finalWorld, group, permission));
return true;
}
@Override
public boolean playerInGroup(String world, @NonNull String player, @NonNull String group) {
String finalWorld = ignoreWorld ? null : world; // Correct world value
log("Checking if player " + player + " is in group: " + group + " on world " + finalWorld + ", server " + server);
final User user = plugin.getUserManager().get(player);
if (user == null) return false;
return user.getNodes().stream()
.filter(Node::isGroupNode)
.filter(n -> n.shouldApplyOnServer(server, isIncludeGlobal(), false))
.filter(n -> n.shouldApplyOnWorld(finalWorld, true, false))
.map(Node::getGroupName)
.filter(s -> s.equalsIgnoreCase(group))
.findAny().isPresent();
}
@Override
public boolean playerAddGroup(String world, @NonNull String player, @NonNull String groupName) {
String finalWorld = ignoreWorld ? null : world; // Correct world value
log("Adding player " + player + " to group: '" + groupName + "' on world " + finalWorld + ", server " + server);
final User user = plugin.getUserManager().get(player);
if (user == null) return false;
final Group group = plugin.getGroupManager().get(groupName);
if (group == null) return false;
scheduler.scheduleTask(() -> {
try {
if (finalWorld != null && !finalWorld.equals("")) {
user.setInheritGroup(group, server, finalWorld);
} else {
user.setInheritGroup(group, server);
}
} catch (ObjectAlreadyHasException ignored) {}
save(user);
});
return true;
}
@Override
public boolean playerRemoveGroup(String world, @NonNull String player, @NonNull String groupName) {
String finalWorld = ignoreWorld ? null : world; // Correct world value
log("Removing player " + player + " from group: '" + groupName + "' on world " + finalWorld + ", server " + server);
final User user = plugin.getUserManager().get(player);
if (user == null) return false;
final Group group = plugin.getGroupManager().get(groupName);
if (group == null) return false;
scheduler.scheduleTask(() -> {
try {
if (finalWorld != null && !finalWorld.equals("")) {
user.unsetInheritGroup(group, server, finalWorld);
} else {
user.unsetInheritGroup(group, server);
}
} catch (ObjectLacksException ignored) {}
save(user);
});
return true;
}
@Override
public String[] getPlayerGroups(String world, @NonNull String player) {
String finalWorld = ignoreWorld ? null : world; // Correct world value
log("Getting groups of player: " + player + ", on world " + finalWorld + ", server " + server);
User user = plugin.getUserManager().get(player);
if (user == null) return new String[0];
return user.getNodes().stream()
.filter(Node::isGroupNode)
.filter(n -> n.shouldApplyOnServer(server, isIncludeGlobal(), false))
.filter(n -> n.shouldApplyOnWorld(finalWorld, true, false))
.map(Node::getGroupName)
.toArray(String[]::new);
}
@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);
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
public String[] getGroups() {
return plugin.getGroupManager().getAll().keySet().toArray(new String[0]);
}
@Override
public boolean hasGroupSupport() {
return true;
}
}
@@ -20,26 +20,34 @@
* SOFTWARE.
*/
package me.lucko.luckperms.contexts;
package me.lucko.luckperms.bukkit.vault;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.sponge.LuckPermsUserSubject;
import me.lucko.luckperms.api.sponge.collections.UserCollection;
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
@AllArgsConstructor
public class ContextUpdateTask implements Runnable {
private final UserCollection userCollection;
public class VaultScheduler implements Runnable {
private final List<Runnable> tasks = new ArrayList<>();
@Override
public void run() {
for (LuckPermsUserSubject subject : userCollection.getUsers().values()) {
Set<Map<String, String>> contexts = new HashSet<>(subject.getContextData().keySet());
contexts.forEach(map -> subject.calculatePermissions(map, true));
public VaultScheduler(LPBukkitPlugin plugin) {
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this, 1L, 1L);
}
public void scheduleTask(Runnable r) {
synchronized (tasks) {
tasks.add(r);
}
}
@Override
public void run() {
List<Runnable> toRun = new ArrayList<>();
synchronized (tasks) {
toRun.addAll(tasks);
tasks.clear();
}
toRun.forEach(Runnable::run);
}
}
@@ -1,135 +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.users;
import lombok.Getter;
import lombok.Setter;
import me.lucko.luckperms.LPBukkitPlugin;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.event.events.UserPermissionRefreshEvent;
import me.lucko.luckperms.api.implementation.internal.UserLink;
import me.lucko.luckperms.inject.LPPermissible;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permissible;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class BukkitUser extends User {
private final LPBukkitPlugin plugin;
@Getter
@Setter
private LPPermissible lpPermissible = null;
@Getter
@Setter
private Map<String, Boolean> loginPreProcess = null;
BukkitUser(UUID uuid, LPBukkitPlugin plugin) {
super(uuid, plugin);
this.plugin = plugin;
}
BukkitUser(UUID uuid, String username, LPBukkitPlugin plugin) {
super(uuid, username, plugin);
this.plugin = plugin;
}
public boolean isOp() {
return lpPermissible != null && lpPermissible.isOp();
}
@SuppressWarnings("unchecked")
@Override
public synchronized void refreshPermissions() {
if (lpPermissible == null) {
return;
}
// Calculate the permissions that should be applied. This is done async, who cares about how long it takes or how often it's done.
Map<String, Boolean> toApply = exportNodes(
new Contexts(
plugin.getContextManager().giveApplicableContext((Player) lpPermissible.getParent(), new HashMap<>()),
plugin.getConfiguration().isIncludingGlobalPerms(),
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
true,
plugin.getConfiguration().isApplyingGlobalGroups(),
plugin.getConfiguration().isApplyingGlobalWorldGroups()
),
Collections.emptyList(),
true
);
try {
Map<String, Boolean> existing = lpPermissible.getLuckPermsPermissions();
boolean different = false;
if (toApply.size() != existing.size()) {
different = true;
} else {
for (Map.Entry<String, Boolean> e : existing.entrySet()) {
if (toApply.containsKey(e.getKey()) && toApply.get(e.getKey()) == e.getValue()) {
continue;
}
different = true;
break;
}
}
if (!different) return;
existing.clear();
lpPermissible.invalidateCache();
existing.putAll(toApply);
if (plugin.getConfiguration().isAutoOp()) {
boolean op = false;
for (Map.Entry<String, Boolean> e : toApply.entrySet()) {
if (e.getKey().equalsIgnoreCase("luckperms.autoop") && e.getValue()) {
op = true;
break;
}
}
final boolean finalOp = op;
if (lpPermissible.isOp() != op) {
final Permissible parent = lpPermissible.getParent();
plugin.doSync(() -> parent.setOp(finalOp));
}
}
plugin.getApiProvider().fireEventAsync(new UserPermissionRefreshEvent(new UserLink(this)));
} catch (Exception e) {
e.printStackTrace();
}
if (plugin.getVaultHook() != null && plugin.getVaultHook().isHooked()) {
plugin.getVaultHook().getPermissionHook().getVaultUserManager().setupUser(this);
}
}
}
@@ -1,97 +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.users;
import me.lucko.luckperms.LPBukkitPlugin;
import me.lucko.luckperms.api.context.ContextListener;
import me.lucko.luckperms.inject.Injector;
import org.bukkit.entity.Player;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
public class BukkitUserManager extends UserManager implements ContextListener<Player> {
private final LPBukkitPlugin plugin;
public BukkitUserManager(LPBukkitPlugin plugin) {
super(plugin);
this.plugin = plugin;
}
@Override
public void preUnload(User user) {
if (user instanceof BukkitUser) {
BukkitUser u = (BukkitUser) user;
Player player = plugin.getServer().getPlayer(plugin.getUuidCache().getExternalUUID(u.getUuid()));
if (player != null) {
if (u.getLpPermissible() != null) {
Injector.unInject(player); // TODO is this needed?
u.setLpPermissible(null);
}
if (plugin.getConfiguration().isAutoOp()) {
player.setOp(false);
}
}
}
}
@Override
public void cleanup(User user) {
if (plugin.getServer().getPlayer(plugin.getUuidCache().getExternalUUID(user.getUuid())) == null) {
unload(user);
}
}
@Override
public User apply(UserIdentifier id) {
BukkitUser user = id.getUsername() == null ?
new BukkitUser(id.getUuid(), plugin) :
new BukkitUser(id.getUuid(), id.getUsername(), plugin);
giveDefaultIfNeeded(user, false);
return user;
}
@Override
public void updateAllUsers() {
// Sometimes called async, as we need to get the players on the Bukkit thread.
plugin.doSync(() -> {
Set<UUID> players = plugin.getServer().getOnlinePlayers().stream()
.map(p -> plugin.getUuidCache().getUUID(p.getUniqueId()))
.collect(Collectors.toSet());
plugin.doAsync(() -> players.forEach(u -> plugin.getDatastore().loadUser(u, "null")));
});
}
@Override
public void onContextChange(Player subject, Map.Entry<String, String> before, Map.Entry<String, String> current) throws Exception {
UUID internal = plugin.getUuidCache().getUUID(subject.getUniqueId());
User user = get(internal);
if (user != null) {
plugin.doAsync(user::refreshPermissions);
}
}
}
+159 -11
View File
@@ -5,6 +5,10 @@
# +------------------------------------------------------------------------+ #
##############################################################################
# +------------------------------------------------------------------------+ #
# | General | #
# +------------------------------------------------------------------------+ #
# The name of the server, used for server specific permissions. Set to 'global' to disable.
server: global
@@ -24,21 +28,31 @@ apply-global-world-groups: true
# If this server is in offline or online mode.
# This setting allows a player to have the same UUID across a network of offline mode/mixed servers.
#
# You should generally reflect the setting in server.properties here. Except when...
#
# 1. You have Spigot servers connected to a BungeeCord proxy, with online-mode set to false, but 'bungeecord' set to true in the spigot.yml
# AND 'ip-forward' set to true in the BungeeCord config.yml
# In this case, set online-mode in LuckPerms to true, despite the server being in offline mode.
#
# 2. You are only running one server instance using LuckPerms, (not a network)
# In this case, set online-mode to true no matter what is set in server.properties. (we can just fallback to the servers uuid cache)
#
# 3. If your proxy is running in offline mode, and you are using PaperSpigot (https://ci.destroystokyo.com/job/PaperSpigot/),
# you should set "bungee-online-mode" to false in the paper.yml, and set "online-mode" to true in all LuckPerms configs.
# This approach is thoroughly recommended for offline mode networks.
online-mode: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# +------------------------------------------------------------------------+ #
# | Permission Calculation | #
# +------------------------------------------------------------------------+ #
# If the plugin should apply wildcard permissions.
# If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered permissions matching
# the wildcard.
@@ -53,11 +67,17 @@ apply-regex: true
# If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# Define special group weights for this server.
# Default is just 0.
group-weight:
# admin: 10
# If LuckPerms should print to console every time a plugin checks if a player has a permission
debug-permission-checks: false
# +------------------------------------------------------------------------+ #
# | OP (Server Operator) Settings | #
# +------------------------------------------------------------------------+ #
# If the vanilla OP system is enabled. If set to false, all users will be de-opped, and the op/deop commands will be disabled.
enable-ops: true
@@ -67,12 +87,23 @@ enable-ops: true
# Additionally, setting this to true will force the "enable-ops" option above to false. All users will be de-opped unless
# they have the permission node, and the op/deop commands will be disabled.
#
# It is important to note that this setting is only checked when a player first joins the server, and when they switch
# worlds. Therefore, simply removing this permission from a user will not automatically de-op them. A player needs to
# relog to have the change take effect.
#
# It is recommended that you use this option instead of assigning a single '*' permission.
auto-op: false
# If opped players should be allowed to use LuckPerms commands. Set to false to only allow users who have the permissions access to the commands
commands-allow-op: true
# +------------------------------------------------------------------------+ #
# | Vault | #
# +------------------------------------------------------------------------+ #
# The name of the server used within Vault operations. If you don't want Vault operations to be server specific, set this
# to "global".
vault-server: global
@@ -80,15 +111,41 @@ vault-server: global
# If global permissions should be considered when retrieving meta or player groups
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:
#world_nether: world
#world_the_end: world
# world_nether: world
# world_the_end: world
# Rewrites group names. The underlying name of the group does not change, just the output in commands / placeholders / Vault.
group-name-rewrite:
#default: Member
# default: Member
# +------------------------------------------------------------------------+ #
# | Storage | #
# +------------------------------------------------------------------------+ #
# Which storage method the plugin should use.
# Currently supported: mysql, sqlite, h2, json, yaml, mongodb
@@ -110,7 +167,98 @@ data:
database: minecraft
username: root
password: ''
pool-size: 10 # The size of the MySQL connection pool.
# Set to -1 to disable. If this is the only instance accessing the datastore, you can disable syncing.
# 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: ''
# +------------------------------------------------------------------------+ #
# | Default Assignments | #
# +------------------------------------------------------------------------+ #
# This section allows you to define defaults to give users whenever they connect to the server.
# The default assignments are highly configurable and conditional.
#
# There is one default assignment built into LuckPerms, which will add all users to the "default" group if they
# are not a member of any other group. This setting cannot be disabled. However, you can use this section to add more of
# your own.
#
# IMPORTANT:
# In order to save storage space, LuckPerms does not store users who have no permissions defined, and are only a member
# of the default group. Adding default assignments to this section will negate this effect. It is HIGHLY RECCOMENDED
# that instead of assigning defaults here, you add permissions to the "default" group, or set the "default" group to inherit
# other groups, and then use the group-name-rewrite rule above.
#
# It is also important to note that these rules are considered every time a player logs into the server, and are applied
# directly to the user's data. Simply removing a rule here will not reserse the effect of that rule on any users who have
# already had it applied to them.
#
# The "has" and "lacks" conditions below support standard boolean logic, using the 'and' & 'or' characters used in Java.
# e.g. "(some.other.permission | some.permission.other) & some.thing.else" == a user has 'some.other.permission', or
# 'some.permission.other', and they also have 'some.thing.else'
#
# Groups are represented by the permission node: group.<group name>
# Per server and per world nodes are represented by: "server-world/permission" or "server/permission"
#
# Within conditions, permission nodes MUST be escaped using "<" and ">". See the example below.
#
# Explaination of the examples below: (they're just to demonstrate the features & use cases)
#
# rule1:
# If a user is either in the vip or vip+ group, and they have the "titles.titlecollector" permission set to true, and the
# "some.random.permission" set to false... if they're not in the group "prison_titlepack" on the "prison" server, then
# give add them to the "prison_titlepack" group on the "prison" server, and remove "some.random.permission".
#
# rule2:
# If the user isn't in any of the following groups on the skyblock server: sb_level1, sb_level2, sb_level3, then add
# them to sb_level1 on the skyblock server.
#
# rule3:
# If the user is a member of the default group, remove them from default, add them to member, and set their primary group
# to member.
#
# WARNING: Unlike internal commands, this system does not ensure that a group exists before adding a user to it.
# It also does not unsure that a user is a member of a group before making that group their primary group.
#
# Before you use "give: group.<name>" or "set-primary-group", make sure that the group exists, and that the user is
# a member of the group.
default-assignments:
# rule1:
# if:
# has-true: (<group.vip> | <group.vip+>) & <titles.tilecollector>
# has-false: <some.random.permission>
# lacks: <prison/group.prison_titlepack>
# give:
# - prison/group.prison_titlepack
# take:
# - some.random.permission
# rule2:
# if:
# lacks: <skyblock/group.sb_level1> & <skyblock/group.sb_level2> & <skyblock/group.sb_level3>
# give:
# - skyblock/group.sb_level1
# rule3:
# if:
# has-true: <group.default>
# take:
# - group.default
# give:
# - group.member
# set-primary-group: member
+1 -1
View File
@@ -4,7 +4,7 @@ description: A permissions plugin
author: Luck
website: https://github.com/lucko/LuckPerms
main: me.lucko.luckperms.LPBukkitPlugin
main: me.lucko.luckperms.bukkit.LPBukkitPlugin
softdepend: [Vault, PermissionsEx, GroupManager, PowerfulPerms, zPermissions, bPermissions] # For migration
commands:
+20 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.11-SNAPSHOT</version>
<version>2.14-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>
@@ -20,10 +20,11 @@
* SOFTWARE.
*/
package me.lucko.luckperms.contexts;
package me.lucko.luckperms.bungee;
import com.google.common.collect.Maps;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.MutableContextSet;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerSwitchEvent;
import net.md_5.bungee.api.plugin.Listener;
@@ -35,11 +36,11 @@ public class BackendServerCalculator extends ContextCalculator<ProxiedPlayer> im
private static final String WORLD_KEY = "world";
@Override
public Map<String, String> giveApplicableContext(ProxiedPlayer subject, Map<String, String> accumulator) {
public MutableContextSet giveApplicableContext(ProxiedPlayer subject, MutableContextSet accumulator) {
String server = getServer(subject);
if (server != null) {
accumulator.put(WORLD_KEY, server);
accumulator.add(Maps.immutableEntry(WORLD_KEY, server));
}
return accumulator;
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.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.users.User;
@AllArgsConstructor
public class BungeeCalculatorFactory implements CalculatorFactory {
private final LPBungeePlugin plugin;
@Override
public PermissionCalculator build(Contexts contexts, User user) {
ImmutableList.Builder<PermissionProcessor> processors = ImmutableList.builder();
processors.add(new MapProcessor());
if (plugin.getConfiguration().isApplyingWildcards()) {
processors.add(new WildcardProcessor());
}
if (plugin.getConfiguration().isApplyingRegex()) {
processors.add(new RegexProcessor());
}
return new PermissionCalculator(plugin, user.getName(), processors.build());
}
}
@@ -20,14 +20,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms;
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.commands.CommandManager;
import me.lucko.luckperms.commands.Util;
import me.lucko.luckperms.constants.Patterns;
import me.lucko.luckperms.common.commands.CommandManager;
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;
import net.md_5.bungee.api.plugin.TabExecutor;
@@ -35,17 +35,19 @@ 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()
@@ -54,6 +56,6 @@ class BungeeCommand extends Command implements TabExecutor {
@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));
}
}
@@ -20,9 +20,9 @@
* SOFTWARE.
*/
package me.lucko.luckperms;
package me.lucko.luckperms.bungee;
import me.lucko.luckperms.config.AbstractConfiguration;
import me.lucko.luckperms.common.config.AbstractConfiguration;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
@@ -32,7 +32,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
class BungeeConfig extends AbstractConfiguration<LPBungeePlugin> {
private Configuration configuration;
@@ -79,6 +82,21 @@ class BungeeConfig extends AbstractConfiguration<LPBungeePlugin> {
return configuration.getBoolean(path, def);
}
@Override
protected List<String> getList(String path, List<String> def) {
return Optional.ofNullable(configuration.getStringList(path)).orElse(def);
}
@Override
protected List<String> getObjectList(String path, List<String> def) {
Configuration section = configuration.getSection(path);
if (section == null) {
return def;
}
return Optional.ofNullable(section.getKeys().stream().collect(Collectors.toList())).orElse(def);
}
@Override
protected Map<String, String> getMap(String path, Map<String, String> def) {
Map<String, String> map = new HashMap<>();
@@ -20,12 +20,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms;
package me.lucko.luckperms.bungee;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.core.UuidCache;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.AbstractListener;
import me.lucko.luckperms.api.Contexts;
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.users.User;
import me.lucko.luckperms.common.utils.AbstractListener;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
@@ -35,6 +37,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;
@@ -58,15 +61,30 @@ public class BungeeListener extends AbstractListener implements Listener {
final ProxiedPlayer player = ((ProxiedPlayer) e.getSender());
BungeePlayerCache playerCache = plugin.getPlayerCache().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
if (playerCache == null) {
User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
if (user == null) {
return;
}
e.setHasPermission(playerCache.getPermissionValue(e.getPermission()));
if (user.getUserData() == null) {
plugin.getLog().warn("Player " + player.getName() + " does not have any user data setup.");
return;
}
Contexts contexts = new Contexts(
plugin.getContextManager().getApplicableContext(player),
plugin.getConfiguration().isIncludingGlobalPerms(),
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
true,
plugin.getConfiguration().isApplyingGlobalGroups(),
plugin.getConfiguration().isApplyingGlobalWorldGroups(),
false
);
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
@@ -78,22 +96,35 @@ public class BungeeListener extends AbstractListener implements Listener {
final PendingConnection c = e.getConnection();
if (!cache.isOnlineMode()) {
UUID uuid = plugin.getDatastore().getUUID(c.getName());
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().saveUUIDData(c.getName(), c.getUniqueId());
plugin.getStorage().force().saveUUIDData(c.getName(), c.getUniqueId()).join();
}
} else {
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().saveUUIDData(c.getName(), c.getUniqueId());
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().loadUser(cache.getUUID(c.getUniqueId()), c.getName());
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 {
user.setupData(false); // Pretty nasty calculation call. Sets up the caching system so data is ready when the user joins.
}
final long time = System.currentTimeMillis() - startTime;
if (time >= 1000) {
plugin.getLog().warn("Processing login for " + c.getName() + " took " + time + "ms.");
@@ -105,20 +136,15 @@ public class BungeeListener extends AbstractListener implements Listener {
@EventHandler
public void onPlayerPostLogin(PostLoginEvent e) {
final ProxiedPlayer player = e.getPlayer();
final UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
final User user = plugin.getUserManager().get(internal);
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
if (user == null) {
plugin.getProxy().getScheduler().schedule(plugin, () -> player.sendMessage(WARN_MESSAGE), 3, TimeUnit.SECONDS);
} else {
plugin.getPlayerCache().put(internal, new BungeePlayerCache(plugin, e.getPlayer().getName()));
user.refreshPermissions();
}
}
@EventHandler
public void onPlayerQuit(PlayerDisconnectEvent e) {
plugin.getPlayerCache().remove(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
onLeave(e.getPlayer().getUniqueId());
}
}
@@ -20,10 +20,11 @@
* SOFTWARE.
*/
package me.lucko.luckperms;
package me.lucko.luckperms.bungee;
import me.lucko.luckperms.commands.SenderFactory;
import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.common.LuckPermsPlugin;
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;
import net.md_5.bungee.api.connection.ProxiedPlayer;
@@ -31,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) {
@@ -20,50 +20,63 @@
* SOFTWARE.
*/
package me.lucko.luckperms;
package me.lucko.luckperms.bungee;
import lombok.Getter;
import me.lucko.luckperms.ApiHandler;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.implementation.ApiProvider;
import me.lucko.luckperms.commands.CommandManager;
import me.lucko.luckperms.commands.ConsecutiveExecutor;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.config.LPConfiguration;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.contexts.BackendServerCalculator;
import me.lucko.luckperms.contexts.ContextManager;
import me.lucko.luckperms.contexts.ServerCalculator;
import me.lucko.luckperms.core.UuidCache;
import me.lucko.luckperms.data.Importer;
import me.lucko.luckperms.groups.GroupManager;
import me.lucko.luckperms.runnables.ExpireTemporaryTask;
import me.lucko.luckperms.runnables.UpdateTask;
import me.lucko.luckperms.storage.Datastore;
import me.lucko.luckperms.storage.StorageFactory;
import me.lucko.luckperms.tracks.TrackManager;
import me.lucko.luckperms.users.BungeeUserManager;
import me.lucko.luckperms.utils.LocaleManager;
import me.lucko.luckperms.utils.LogFactory;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
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.CommandManager;
import me.lucko.luckperms.common.commands.ConsecutiveExecutor;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.config.LPConfiguration;
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.messaging.RedisMessaging;
import me.lucko.luckperms.common.runnables.ExpireTemporaryTask;
import me.lucko.luckperms.common.runnables.UpdateTask;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.storage.StorageFactory;
import me.lucko.luckperms.common.tracks.TrackManager;
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;
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 final Map<UUID, BungeePlayerCache> playerCache = new ConcurrentHashMap<>();
private Executor executor;
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private LPConfiguration configuration;
private BungeeUserManager userManager;
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;
@@ -71,14 +84,50 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
private ConsecutiveExecutor consecutiveExecutor;
private LocaleManager localeManager;
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()) {
@@ -90,66 +139,63 @@ 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 BungeeUserManager(this);
userManager = new UserManager(this);
groupManager = new GroupManager(this);
trackManager = new TrackManager();
importer = new Importer(commandManager);
consecutiveExecutor = new ConsecutiveExecutor(commandManager);
calculatorFactory = new BungeeCalculatorFactory(this);
contextManager = new ContextManager<>();
BackendServerCalculator serverCalculator = new BackendServerCalculator();
getProxy().getPluginManager().registerListener(this, serverCalculator);
contextManager.registerCalculator(serverCalculator);
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
contextManager.registerListener(userManager);
// 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);
LuckPerms.registerProvider(apiProvider);
// Run update task to refresh any online users
getLog().info("Scheduling Update Task to refresh any online users.");
try {
new UpdateTask(this).run();
} catch (Exception e) {
e.printStackTrace();
}
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...");
LuckPerms.unregisterProvider();
ApiHandler.unregisterProvider();
}
@Override
@@ -167,11 +213,6 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
return getDataFolder();
}
@Override
public Message getPlayerStatus(UUID uuid) {
return getProxy().getPlayer(getUuidCache().getExternalUUID(uuid)) != null ? Message.PLAYER_ONLINE : Message.PLAYER_OFFLINE;
}
@Override
public int getPlayerCount() {
return getProxy().getOnlineCount();
@@ -183,22 +224,54 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
}
@Override
public List<Sender> getNotifyListeners() {
public Set<UUID> getOnlinePlayers() {
return getProxy().getPlayers().stream().map(ProxiedPlayer::getUniqueId).collect(Collectors.toSet());
}
@Override
public boolean isOnline(UUID external) {
return getProxy().getPlayer(external) != null;
}
@Override
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
public List<String> getPossiblePermissions() {
// No such thing on Bungee. Wildcards are processed in the listener instead.
return Collections.emptyList();
public Set<Contexts> getPreProcessContexts(boolean op) {
Set<ContextSet> c = new HashSet<>();
c.add(ContextSet.empty());
c.add(ContextSet.singleton("server", getConfiguration().getServer()));
c.addAll(getProxy().getServers().values().stream()
.map(ServerInfo::getName)
.map(s -> {
MutableContextSet set = new MutableContextSet();
set.add("server", getConfiguration().getServer());
set.add("world", s);
return set.makeImmutable();
})
.collect(Collectors.toList())
);
return c.stream()
.map(set -> new Contexts(
set,
getConfiguration().isIncludingGlobalPerms(),
getConfiguration().isIncludingGlobalWorldPerms(),
true,
getConfiguration().isApplyingGlobalGroups(),
getConfiguration().isApplyingGlobalWorldGroups(),
false
))
.collect(Collectors.toSet());
}
@Override
@@ -224,11 +297,6 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
.isPresent();
}
@Override
public void runUpdateTask() {
doAsync(new UpdateTask(this));
}
@Override
public void doAsync(Runnable r) {
getProxy().getScheduler().runAsync(this, r);
@@ -236,6 +304,22 @@ 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
public void doAsyncRepeating(Runnable r, long interval) {
long millis = interval * 50L; // convert from ticks to milliseconds
getProxy().getScheduler().schedule(this, r, millis, millis, TimeUnit.MILLISECONDS);
}
}
@@ -20,19 +20,20 @@
* SOFTWARE.
*/
package me.lucko.luckperms.commands.migration.subcommands;
package me.lucko.luckperms.bungee.migration;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.commands.CommandResult;
import me.lucko.luckperms.commands.Predicate;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.commands.SubCommand;
import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
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.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 me.lucko.luckperms.utils.ArgumentChecker;
import net.alpenblock.bungeeperms.*;
import java.util.List;
@@ -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,11 +61,11 @@ 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());
me.lucko.luckperms.groups.Group group = plugin.getGroupManager().get(g.getName().toLowerCase());
plugin.getStorage().createAndLoadGroup(g.getName().toLowerCase()).join();
me.lucko.luckperms.common.groups.Group group = plugin.getGroupManager().get(g.getName().toLowerCase());
try {
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
@@ -144,7 +145,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
String suffix = g.getSuffix();
if (prefix != null && !prefix.equals("")) {
prefix = ArgumentChecker.escapeCharacters(prefix);
prefix = MetaUtils.escapeCharacters(prefix);
try {
group.setPermission("prefix.50." + prefix, true);
LogEntry.build()
@@ -159,7 +160,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
}
if (suffix != null && !suffix.equals("")) {
suffix = ArgumentChecker.escapeCharacters(suffix);
suffix = MetaUtils.escapeCharacters(suffix);
try {
group.setPermission("suffix.50." + suffix, true);
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,8 +188,8 @@ public class MigrationBungeePerms extends SubCommand<Object> {
userCount++;
// Make a LuckPerms user for the one being migrated.
plugin.getDatastore().loadUser(u.getUUID(), "null");
me.lucko.luckperms.users.User user = plugin.getUserManager().get(u.getUUID());
plugin.getStorage().loadUser(u.getUUID(), "null").join();
me.lucko.luckperms.common.users.User user = plugin.getUserManager().get(u.getUUID());
// Migrate global perms
for (String perm : u.getPerms()) {
@@ -259,7 +260,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
String suffix = u.getSuffix();
if (prefix != null && !prefix.equals("")) {
prefix = ArgumentChecker.escapeCharacters(prefix);
prefix = MetaUtils.escapeCharacters(prefix);
try {
user.setPermission("prefix.100." + prefix, true);
LogEntry.build()
@@ -274,7 +275,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
}
if (suffix != null && !suffix.equals("")) {
suffix = ArgumentChecker.escapeCharacters(suffix);
suffix = MetaUtils.escapeCharacters(suffix);
try {
user.setPermission("suffix.100." + suffix, true);
LogEntry.build()
@@ -288,7 +289,7 @@ public class MigrationBungeePerms extends SubCommand<Object> {
}
}
plugin.getDatastore().saveUser(user);
plugin.getStorage().saveUser(user);
plugin.getUserManager().cleanup(user);
}
@@ -1,99 +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.users;
import me.lucko.luckperms.BungeePlayerCache;
import me.lucko.luckperms.LPBungeePlugin;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.event.events.UserPermissionRefreshEvent;
import me.lucko.luckperms.api.implementation.internal.UserLink;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class BungeeUser extends User {
private final LPBungeePlugin plugin;
BungeeUser(UUID uuid, LPBungeePlugin plugin) {
super(uuid, plugin);
this.plugin = plugin;
}
BungeeUser(UUID uuid, String username, LPBungeePlugin plugin) {
super(uuid, username, plugin);
this.plugin = plugin;
}
@Override
public synchronized void refreshPermissions() {
ProxiedPlayer player = plugin.getProxy().getPlayer(plugin.getUuidCache().getExternalUUID(getUuid()));
if (player == null) {
return;
}
BungeePlayerCache playerCache = plugin.getPlayerCache().get(getUuid());
if (playerCache == null) {
return;
}
// Calculate the permissions that should be applied. This is done async.
Map<String, Boolean> toApply = exportNodes(
new Contexts(
plugin.getContextManager().giveApplicableContext(player, new HashMap<>()),
plugin.getConfiguration().isIncludingGlobalPerms(),
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
true,
plugin.getConfiguration().isApplyingGlobalGroups(),
plugin.getConfiguration().isApplyingGlobalWorldGroups()
),
Collections.emptyList(),
true
);
Map<String, Boolean> existing = playerCache.getPermissions();
boolean different = false;
if (toApply.size() != existing.size()) {
different = true;
} else {
for (Map.Entry<String, Boolean> e : existing.entrySet()) {
if (toApply.containsKey(e.getKey()) && toApply.get(e.getKey()) == e.getValue()) {
continue;
}
different = true;
break;
}
}
if (!different) return;
existing.clear();
playerCache.invalidateCache();
existing.putAll(toApply);
plugin.getApiProvider().fireEventAsync(new UserPermissionRefreshEvent(new UserLink(this)));
}
}
@@ -1,72 +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.users;
import me.lucko.luckperms.LPBungeePlugin;
import me.lucko.luckperms.api.context.ContextListener;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.Map;
import java.util.UUID;
public class BungeeUserManager extends UserManager implements ContextListener<ProxiedPlayer> {
private final LPBungeePlugin plugin;
public BungeeUserManager(LPBungeePlugin plugin) {
super(plugin);
this.plugin = plugin;
}
@Override
public void cleanup(User user) {
if (plugin.getProxy().getPlayer(plugin.getUuidCache().getExternalUUID(user.getUuid())) == null) {
unload(user);
}
}
@Override
public User apply(UserIdentifier id) {
BungeeUser user = id.getUsername() == null ?
new BungeeUser(id.getUuid(), plugin) :
new BungeeUser(id.getUuid(), id.getUsername(), plugin);
giveDefaultIfNeeded(user, false);
return user;
}
@Override
public void updateAllUsers() {
plugin.getProxy().getPlayers().stream()
.map(p -> plugin.getUuidCache().getUUID(p.getUniqueId()))
.forEach(u -> plugin.getDatastore().loadUser(u, "null"));
}
@Override
public void onContextChange(ProxiedPlayer subject, Map.Entry<String, String> before, Map.Entry<String, String> current) throws Exception {
UUID internal = plugin.getUuidCache().getUUID(subject.getUniqueId());
User user = get(internal);
if (user != null) {
plugin.doAsync(user::refreshPermissions);
}
}
}
+128 -19
View File
@@ -5,6 +5,10 @@
# +------------------------------------------------------------------------+ #
##############################################################################
# +------------------------------------------------------------------------+ #
# | General | #
# +------------------------------------------------------------------------+ #
# The name of the server, used for server specific permissions. Set to 'global' to disable.
server: bungee
@@ -24,21 +28,41 @@ apply-global-world-groups: true
# If this server is in offline or online mode.
# This setting allows a player to have the same UUID across a network of offline mode/mixed servers.
#
# You should generally reflect the setting in server.properties here. Except when...
#
# 1. You have Spigot servers connected to a BungeeCord proxy, with online-mode set to false, but 'bungeecord' set to true in the spigot.yml
# AND 'ip-forward' set to true in the BungeeCord config.yml
# In this case, set online-mode in LuckPerms to true, despite the server being in offline mode.
#
# 2. You are only running one server instance using LuckPerms, (not a network)
# In this case, set online-mode to true no matter what is set in server.properties. (we can just fallback to the servers uuid cache)
#
# 3. If your proxy is running in offline mode, and you are using PaperSpigot (https://ci.destroystokyo.com/job/PaperSpigot/),
# you should set "bungee-online-mode" to false in the paper.yml, and set "online-mode" to true in all LuckPerms configs.
# This approach is thoroughly recommended for offline mode networks.
online-mode: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in this list, the value assigned
# will be sent forward for permission calculation instead.
world-rewrite:
# world_nether: world
# world_the_end: world
# Rewrites group names. The underlying name of the group does not change, just the output in commands / placeholders / Vault.
group-name-rewrite:
# default: Member
# +------------------------------------------------------------------------+ #
# | Permission Calculation | #
# +------------------------------------------------------------------------+ #
# If the plugin should apply wildcard permissions.
# If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered permissions matching
# the wildcard.
@@ -53,23 +77,17 @@ apply-regex: true
# If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# Define special group weights for this server.
# Default is just 0.
group-weight:
# admin: 10
# 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.
# Remember world names on BungeeCord relate to the backend server name a user is connected to.
world-rewrite:
#hub2: hub
#hub3: hub
#opfactions: factions
# Rewrites group names. The underlying name of the group does not change, just the output in commands / placeholders / Vault.
group-name-rewrite:
#default: Member
# +------------------------------------------------------------------------+ #
# | Storage | #
# +------------------------------------------------------------------------+ #
# Which storage method the plugin should use.
# Currently supported: mysql, sqlite, h2, json, yaml, mongodb
@@ -91,7 +109,98 @@ data:
database: minecraft
username: root
password: ''
pool-size: 10 # The size of the MySQL connection pool.
# Set to -1 to disable. If this is the only instance accessing the datastore, you can disable syncing.
# e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources.
sync-minutes: 3
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: ''
# +------------------------------------------------------------------------+ #
# | Default Assignments | #
# +------------------------------------------------------------------------+ #
# This section allows you to define defaults to give users whenever they connect to the server.
# The default assignments are highly configurable and conditional.
#
# There is one default assignment built into LuckPerms, which will add all users to the "default" group if they
# are not a member of any other group. This setting cannot be disabled. However, you can use this section to add more of
# your own.
#
# IMPORTANT:
# In order to save storage space, LuckPerms does not store users who have no permissions defined, and are only a member
# of the default group. Adding default assignments to this section will negate this effect. It is HIGHLY RECCOMENDED
# that instead of assigning defaults here, you add permissions to the "default" group, or set the "default" group to inherit
# other groups, and then use the group-name-rewrite rule above.
#
# It is also important to note that these rules are considered every time a player logs into the server, and are applied
# directly to the user's data. Simply removing a rule here will not reserse the effect of that rule on any users who have
# already had it applied to them.
#
# The "has" and "lacks" conditions below support standard boolean logic, using the 'and' & 'or' characters used in Java.
# e.g. "(some.other.permission | some.permission.other) & some.thing.else" == a user has 'some.other.permission', or
# 'some.permission.other', and they also have 'some.thing.else'
#
# Groups are represented by the permission node: group.<group name>
# Per server and per world nodes are represented by: "server-world/permission" or "server/permission"
#
# Within conditions, permission nodes MUST be escaped using "<" and ">". See the example below.
#
# Explaination of the examples below: (they're just to demonstrate the features & use cases)
#
# rule1:
# If a user is either in the vip or vip+ group, and they have the "titles.titlecollector" permission set to true, and the
# "some.random.permission" set to false... if they're not in the group "prison_titlepack" on the "prison" server, then
# give add them to the "prison_titlepack" group on the "prison" server, and remove "some.random.permission".
#
# rule2:
# If the user isn't in any of the following groups on the skyblock server: sb_level1, sb_level2, sb_level3, then add
# them to sb_level1 on the skyblock server.
#
# rule3:
# If the user is a member of the default group, remove them from default, add them to member, and set their primary group
# to member.
#
# WARNING: Unlike internal commands, this system does not ensure that a group exists before adding a user to it.
# It also does not unsure that a user is a member of a group before making that group their primary group.
#
# Before you use "give: group.<name>" or "set-primary-group", make sure that the group exists, and that the user is
# a member of the group.
default-assignments:
# rule1:
# if:
# has-true: (<group.vip> | <group.vip+>) & <titles.tilecollector>
# has-false: <some.random.permission>
# lacks: <prison/group.prison_titlepack>
# give:
# - prison/group.prison_titlepack
# take:
# - some.random.permission
# rule2:
# if:
# lacks: <skyblock/group.sb_level1> & <skyblock/group.sb_level2> & <skyblock/group.sb_level3>
# give:
# - skyblock/group.sb_level1
# rule3:
# if:
# has-true: <group.default>
# take:
# - group.default
# give:
# - group.member
# set-primary-group: member
+1 -1
View File
@@ -2,5 +2,5 @@ name: LuckPerms
version: ${release.version}.${git.closest.tag.commit.count}
description: A permissions plugin
author: Luck
main: me.lucko.luckperms.LPBungeePlugin
main: me.lucko.luckperms.bungee.LPBungeePlugin
softdepends: [PowerfulPerms] # For migration
+9 -49
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.11-SNAPSHOT</version>
<version>2.14-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -36,7 +36,14 @@
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>2.4.7</version>
<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 -->
@@ -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>
@@ -20,25 +20,18 @@
* SOFTWARE.
*/
package me.lucko.luckperms.utils;
package me.lucko.luckperms;
import java.util.function.Supplier;
import me.lucko.luckperms.api.LuckPermsApi;
public class Cache<T> {
private T t = null;
public class ApiHandler {
public T get(Supplier<T> supplier) {
synchronized (this) {
if (t == null) {
t = supplier.get();
}
return t;
}
public static void registerProvider(LuckPermsApi luckPermsApi) {
LuckPerms.registerProvider(luckPermsApi);
}
public void invalidate() {
synchronized (this) {
t = null;
}
public static void unregisterProvider() {
LuckPerms.unregisterProvider();
}
}
@@ -1,174 +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;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.implementation.ApiProvider;
import me.lucko.luckperms.commands.ConsecutiveExecutor;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.config.LPConfiguration;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.contexts.ContextManager;
import me.lucko.luckperms.core.UuidCache;
import me.lucko.luckperms.data.Importer;
import me.lucko.luckperms.groups.GroupManager;
import me.lucko.luckperms.storage.Datastore;
import me.lucko.luckperms.tracks.TrackManager;
import me.lucko.luckperms.users.UserManager;
import me.lucko.luckperms.utils.LocaleManager;
import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/**
* Main internal interface for LuckPerms plugins, allowing the luckperms-common module to bind with the plugin instance.
* All plugin platforms implement this interface.
*/
public interface LuckPermsPlugin {
/*
* Access to all of the main internal manager classes
*/
UserManager getUserManager();
GroupManager getGroupManager();
TrackManager getTrackManager();
LPConfiguration getConfiguration();
Datastore getDatastore();
Logger getLog();
UuidCache getUuidCache();
ApiProvider getApiProvider();
Importer getImporter();
ConsecutiveExecutor getConsecutiveExecutor();
LocaleManager getLocaleManager();
ContextManager getContextManager();
/**
* @return the version of the plugin
*/
String getVersion();
/**
* @return the platform type
*/
PlatformType getType();
/**
* @return the main plugin directory
*/
File getMainDir();
/**
* @return the platforms data folder
*/
File getDataFolder();
/**
* Returns a colored string indicating the status of a player
* @param uuid The player's uuid
* @return a formatted status string
*/
Message getPlayerStatus(UUID uuid);
/**
* Gets the number of users online on the platform
* @return the number of users
*/
int getPlayerCount();
/**
* Gets the usernames of the users online on the platform
* @return a {@link List} of usernames
*/
List<String> getPlayerList();
/**
* @return a {@link List} of senders online on the platform
*/
List<Sender> getNotifyListeners();
/**
* @return the console sender of the instance
*/
Sender getConsoleSender();
/**
* Gets all possible permission nodes, used for resolving wildcards
* @return a {@link List} of permission nodes
*/
List<String> getPossiblePermissions();
/**
* Gets a set of players ignoring logging output
* @return a {@link Set} of uuids
*/
Set<UUID> getIgnoringLogs();
/**
* Gets a loaded plugins instance from the platform
* @param name the name of the plugin
* @return a plugin instance
*/
Object getPlugin(String name);
/**
* Gets a provided service from the platform.
* @param clazz the class of the service
* @return the service instance, if it is provided for
*/
Object getService(Class clazz);
/**
* Used as a backup for migration
* @param playerName the players name
* @return a uuid if found, or null if not
*/
UUID getUUID(String playerName);
/**
* Checks if a plugin is loaded on the platform
* @param name the name of the plugin
* @return true if the plugin is loaded
*/
boolean isPluginLoaded(String name);
/**
* Runs an update task
*/
void runUpdateTask();
/**
* 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);
}
@@ -1,187 +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.commands;
import com.google.common.collect.ImmutableList;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.commands.group.CreateGroup;
import me.lucko.luckperms.commands.group.DeleteGroup;
import me.lucko.luckperms.commands.group.GroupMainCommand;
import me.lucko.luckperms.commands.group.ListGroups;
import me.lucko.luckperms.commands.log.LogMainCommand;
import me.lucko.luckperms.commands.migration.MigrationMainCommand;
import me.lucko.luckperms.commands.misc.*;
import me.lucko.luckperms.commands.track.CreateTrack;
import me.lucko.luckperms.commands.track.DeleteTrack;
import me.lucko.luckperms.commands.track.ListTracks;
import me.lucko.luckperms.commands.track.TrackMainCommand;
import me.lucko.luckperms.commands.user.UserMainCommand;
import me.lucko.luckperms.commands.usersbulkedit.UsersBulkEditMainCommand;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
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();
/**
* Generic on command method to be called from the command executor object of the platform
* Unlike {@link #onCommand(Sender, String, List)}, this method is called in a new thread
* @param sender who sent the command
* @param label the command label used
* @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) {
plugin.doAsync(() -> {
CommandResult r = onCommand(sender, label, args);
plugin.doSync(() -> result.onComplete(r));
});
}
/**
* Generic on command method to be called from the command executor object of the platform
* @param sender who sent the command
* @param label the command label used
* @param args the arguments provided
* @return if the command was successful
*/
public CommandResult onCommand(Sender sender, String label, List<String> args) {
if (args.size() == 0) {
sendCommandUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
Optional<MainCommand> o = mainCommands.stream()
.filter(m -> m.getName().equalsIgnoreCase(args.get(0)))
.limit(1)
.findAny();
if (!o.isPresent()) {
sendCommandUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
final MainCommand 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;
}
}
if (args.size() == 1) {
main.sendUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
try {
return main.execute(plugin, sender, new ArrayList<>(args.subList(1, args.size())), label);
} catch (Exception e) {
e.printStackTrace();
return CommandResult.FAILURE;
}
}
/**
* Generic tab complete method to be called from the command executor object of the platform
* @param sender who is tab completing
* @param args the arguments provided so far
* @return a list of suggestions
*/
@SuppressWarnings("unchecked")
public List<String> onTabComplete(Sender sender, List<String> args) {
final List<MainCommand> mains = mainCommands.stream()
.filter(m -> m.isAuthorized(sender))
.collect(Collectors.toList());
if (args.size() <= 1) {
if (args.isEmpty() || args.get(0).equalsIgnoreCase("")) {
return mains.stream()
.map(m -> m.getName().toLowerCase())
.collect(Collectors.toList());
}
return mains.stream()
.map(m -> m.getName().toLowerCase())
.filter(s -> s.startsWith(args.get(0).toLowerCase()))
.collect(Collectors.toList());
}
Optional<MainCommand> o = mains.stream()
.filter(m -> m.getName().equalsIgnoreCase(args.get(0)))
.limit(1)
.findAny();
if (!o.isPresent()) {
return Collections.emptyList();
}
return o.get().onTabComplete(sender, args.subList(1, args.size()), plugin);
}
private void sendCommandUsage(Sender sender, String label) {
Util.sendPluginMessage(sender, "&2Running &bLuckPerms v" + plugin.getVersion() + "&2.");
mainCommands.stream()
.filter(c -> c.isAuthorized(sender))
.forEach(c -> Util.sendPluginMessage(sender, "&3> &a" + String.format(c.getUsage(), label)));
}
}
@@ -1,132 +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.commands;
import com.google.common.collect.ImmutableMap;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.constants.Permission;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
* 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) {
if (toCheck == null || toCheck.isEmpty()) {
this.perms = ImmutableMap.copyOf(Arrays.stream(Permission.values())
.collect(Collectors.toMap(p -> p, p -> factory.hasPermission(t, p.getNode()))));
} else {
this.perms = ImmutableMap.copyOf(toCheck.stream().collect(Collectors.toMap(p -> p, p -> factory.hasPermission(t, p.getNode()))));
}
}
}
@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);
}
}
}
@@ -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.commands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.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);
}
}
@@ -1,99 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class GroupAddPrefix extends SubCommand<Group> {
public GroupAddPrefix() {
super("addprefix", "Adds a prefix to the group", Permission.GROUP_ADDPREFIX, Predicate.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to add the prefix at"),
Arg.create("prefix", true, "the prefix string"),
Arg.create("server", false, "the server to add the prefix on"),
Arg.create("world", false, "the world to add the prefix on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
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;
}
final String node = "prefix." + priority + "." + ArgumentChecker.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) {
group.setPermission(node, true, server);
Message.ADDPREFIX_SERVER_SUCCESS.send(sender, group.getDisplayName(), prefix, priority, server);
LogEntry.build().actor(sender).acted(group)
.action("addprefix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
group.setPermission(node, true, server, world);
Message.ADDPREFIX_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), prefix, priority, server, world);
LogEntry.build().actor(sender).acted(group)
.action("addprefix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.setPermission(node, true);
Message.ADDPREFIX_SUCCESS.send(sender, group.getDisplayName(), prefix, priority);
LogEntry.build().actor(sender).acted(group)
.action("addprefix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_PREFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
}
@@ -1,99 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class GroupAddSuffix extends SubCommand<Group> {
public GroupAddSuffix() {
super("addsuffix", "Adds a suffix to the group", Permission.GROUP_ADDSUFFIX, Predicate.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to add the suffix at"),
Arg.create("suffix", true, "the suffix string"),
Arg.create("server", false, "the server to add the suffix on"),
Arg.create("world", false, "the world to add the suffix on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
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;
}
final String node = "suffix." + priority + "." + ArgumentChecker.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) {
group.setPermission(node, true, server);
Message.ADDSUFFIX_SERVER_SUCCESS.send(sender, group.getDisplayName(), suffix, priority, server);
LogEntry.build().actor(sender).acted(group)
.action("addsuffix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
group.setPermission(node, true, server, world);
Message.ADDSUFFIX_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), suffix, priority, server, world);
LogEntry.build().actor(sender).acted(group)
.action("addsuffix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.setPermission(node, true);
Message.ADDSUFFIX_SUCCESS.send(sender, group.getDisplayName(), suffix, priority);
LogEntry.build().actor(sender).acted(group)
.action("addsuffix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_SUFFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
}
@@ -1,118 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.DateUtil;
import java.util.List;
public class GroupAddTempPrefix extends SubCommand<Group> {
public GroupAddTempPrefix() {
super("addtempprefix", "Adds a prefix to the group temporarily", Permission.GROUP_ADD_TEMP_PREFIX, Predicate.notInRange(3, 5),
Arg.list(
Arg.create("priority", true, "the priority to add the prefix at"),
Arg.create("prefix", true, "the prefix string"),
Arg.create("duration", true, "the duration until the prefix expires"),
Arg.create("server", false, "the server to add the prefix on"),
Arg.create("world", false, "the world to add the prefix on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
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;
}
final String node = "prefix." + priority + "." + ArgumentChecker.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) {
group.setPermission(node, true, server, duration);
Message.ADD_TEMP_PREFIX_SERVER_SUCCESS.send(sender, group.getDisplayName(), prefix, priority, server, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("addtempprefix " + priority + " " + args.get(1) + " " + duration + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(4).toLowerCase();
group.setPermission(node, true, server, world, duration);
Message.ADD_TEMP_PREFIX_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), prefix, priority, server, world, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("addtempprefix " + priority + " " + args.get(1) + " " + duration + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.setPermission(node, true, duration);
Message.ADD_TEMP_PREFIX_SUCCESS.send(sender, group.getDisplayName(), prefix, priority, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("addtempprefix " + priority + " " + args.get(1) + " " + duration)
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_PREFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
}
@@ -1,118 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.DateUtil;
import java.util.List;
public class GroupAddTempSuffix extends SubCommand<Group> {
public GroupAddTempSuffix() {
super("addtempsuffix", "Adds a suffix to the group temporarily", Permission.GROUP_ADD_TEMP_SUFFIX, Predicate.notInRange(3, 5),
Arg.list(
Arg.create("priority", true, "the priority to add the suffix at"),
Arg.create("suffix", true, "the suffix string"),
Arg.create("duration", true, "the duration until the suffix expires"),
Arg.create("server", false, "the server to add the suffix on"),
Arg.create("world", false, "the world to add the suffix on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
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;
}
final String node = "suffix." + priority + "." + ArgumentChecker.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) {
group.setPermission(node, true, server, duration);
Message.ADD_TEMP_SUFFIX_SERVER_SUCCESS.send(sender, group.getDisplayName(), suffix, priority, server, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("addtempsuffix " + priority + " " + args.get(1) + " " + duration + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(4).toLowerCase();
group.setPermission(node, true, server, world, duration);
Message.ADD_TEMP_SUFFIX_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), suffix, priority, server, world, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("addtempsuffix " + priority + " " + args.get(1) + " " + duration + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.setPermission(node, true, duration);
Message.ADD_TEMP_SUFFIX_SUCCESS.send(sender, group.getDisplayName(), suffix, priority, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("addtempsuffix " + priority + " " + args.get(1) + " " + duration)
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_SUFFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
}
@@ -1,89 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.groups.Group;
import java.util.*;
public class GroupChatMeta extends SubCommand<Group> {
public GroupChatMeta() {
super("chatmeta", "Lists the group's chat meta", Permission.GROUP_CHATMETA, Predicate.alwaysFalse(), null);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
SortedSet<Map.Entry<Integer, String>> prefixes = new TreeSet<>(Util.getMetaComparator().reversed());
SortedSet<Map.Entry<Integer, String>> suffixes = new TreeSet<>(Util.getMetaComparator().reversed());
for (Node node : group.getAllNodes(null, Contexts.allowAll())) {
if (!node.isSuffix() && !node.isPrefix()) {
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()));
}
}
if (prefixes.isEmpty()) {
Message.CHAT_META_PREFIX_NONE.send(sender, group.getDisplayName());
} else {
Message.CHAT_META_PREFIX_HEADER.send(sender, group.getDisplayName());
for (Map.Entry<Integer, String> e : prefixes) {
Message.CHAT_META_ENTRY.send(sender, e.getKey(), e.getValue());
}
}
if (suffixes.isEmpty()) {
Message.CHAT_META_SUFFIX_NONE.send(sender, group.getDisplayName());
} else {
Message.CHAT_META_SUFFIX_HEADER.send(sender, group.getDisplayName());
for (Map.Entry<Integer, String> e : suffixes) {
Message.CHAT_META_ENTRY.send(sender, e.getKey(), e.getValue());
}
}
return CommandResult.SUCCESS;
}
}
@@ -1,66 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.core.Node;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class GroupHasPerm extends SubCommand<Group> {
public GroupHasPerm() {
super("haspermission", "Checks to see if the group has a certain permission node", Permission.GROUP_HASPERMISSION,
Predicate.notInRange(1, 3),
Arg.list(
Arg.create("node", true, "the permission node to check for"),
Arg.create("server", false, "the server to check on"),
Arg.create("world", false, "the world to check on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
if (args.size() >= 2) {
if (ArgumentChecker.checkServer(args.get(1))) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() == 2) {
Util.sendTristate(sender, args.get(0), group.hasPermission(new Node.Builder(args.get(0)).setServer(args.get(1)).build()));
} else {
Util.sendTristate(sender, args.get(0), group.hasPermission(new Node.Builder(args.get(0)).setServer(args.get(1)).setWorld(args.get(2)).build()));
}
} else {
Util.sendTristate(sender, args.get(0), group.hasPermission(new Node.Builder(args.get(0)).build()));
}
return CommandResult.SUCCESS;
}
}
@@ -1,80 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.core.InheritanceInfo;
import me.lucko.luckperms.core.Node;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class GroupInheritsPerm extends SubCommand<Group> {
public GroupInheritsPerm() {
super("inheritspermission", "Checks to see if the group inherits a certain permission node",
Permission.GROUP_INHERITSPERMISSION, Predicate.notInRange(1, 3),
Arg.list(
Arg.create("node", true, "the permission node to check for"),
Arg.create("server", false, "the server to check on"),
Arg.create("world", false, "the world to check on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
InheritanceInfo result;
if (args.size() >= 2) {
if (ArgumentChecker.checkServer(args.get(1))) {
Message.SERVER_INVALID_ENTRY.send(sender);
return CommandResult.INVALID_ARGS;
}
if (args.size() == 2) {
result = group.inheritsPermissionInfo(new Node.Builder(args.get(0)).setServer(args.get(1)).build());
} else {
result = group.inheritsPermissionInfo(new Node.Builder(args.get(0)).setServer(args.get(1)).setWorld(args.get(2)).build());
}
} else {
result = group.inheritsPermissionInfo(new Node.Builder(args.get(0)).build());
}
String location = null;
if (result.getLocation().isPresent()) {
if (result.getLocation().get().equals(group.getObjectName())) {
location = "self";
} else {
location = result.getLocation().get();
}
}
Util.sendPluginMessage(sender, "&b" + args.get(0) + ": " + Util.formatTristate(result.getResult()) +
(result.getLocation().isPresent() ? " &7(inherited from &a" + location + "&7)" : ""));
return CommandResult.SUCCESS;
}
}
@@ -1,153 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.ArrayList;
import java.util.List;
public class GroupRemovePrefix extends SubCommand<Group> {
public GroupRemovePrefix() {
super("removeprefix", "Removes a prefix from the group", Permission.GROUP_REMOVEPREFIX, Predicate.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to remove the prefix at"),
Arg.create("prefix", true, "the prefix string to remove"),
Arg.create("server", false, "the server to remove the prefix on"),
Arg.create("world", false, "the world to remove the prefix on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
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;
}
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 : group.getNodes()) {
if (!node.isPrefix()) continue;
if (node.getPrefix().getKey() != priority) continue;
if (node.isTemporary()) continue;
if (node.getServer().isPresent()) {
if (server == null) continue;
if (!node.getServer().get().equalsIgnoreCase(server)) continue;
} else {
if (server != null) continue;
}
if (node.getWorld().isPresent()) {
if (world == null) continue;
if (!node.getWorld().get().equalsIgnoreCase(world)) continue;
} else {
if (world != null) continue;
}
toRemove.add(node);
}
toRemove.forEach(n -> {
try {
group.unsetPermission(n);
} catch (ObjectLacksException ignored) {}
});
Message.BULK_CHANGE_SUCCESS.send(sender, toRemove.size());
save(group, sender, plugin);
return CommandResult.SUCCESS;
} else {
final String node = "prefix." + priority + "." + ArgumentChecker.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) {
group.unsetPermission(node, server);
Message.REMOVEPREFIX_SERVER_SUCCESS.send(sender, group.getDisplayName(), prefix, priority, server);
LogEntry.build().actor(sender).acted(group)
.action("removeprefix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
group.unsetPermission(node, server, world);
Message.REMOVEPREFIX_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), prefix, priority, server, world);
LogEntry.build().actor(sender).acted(group)
.action("removeprefix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.unsetPermission(node);
Message.REMOVEPREFIX_SUCCESS.send(sender, group.getDisplayName(), prefix, priority);
LogEntry.build().actor(sender).acted(group)
.action("removeprefix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_PREFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
}
}
@@ -1,153 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.ArrayList;
import java.util.List;
public class GroupRemoveSuffix extends SubCommand<Group> {
public GroupRemoveSuffix() {
super("removesuffix", "Removes a suffix from the group", Permission.GROUP_REMOVESUFFIX, Predicate.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to remove the suffix at"),
Arg.create("suffix", true, "the suffix string to remove"),
Arg.create("server", false, "the server to remove the suffix on"),
Arg.create("world", false, "the world to remove the suffix on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
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;
}
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 : group.getNodes()) {
if (!node.isSuffix()) continue;
if (node.getSuffix().getKey() != priority) continue;
if (node.isTemporary()) continue;
if (node.getServer().isPresent()) {
if (server == null) continue;
if (!node.getServer().get().equalsIgnoreCase(server)) continue;
} else {
if (server != null) continue;
}
if (node.getWorld().isPresent()) {
if (world == null) continue;
if (!node.getWorld().get().equalsIgnoreCase(world)) continue;
} else {
if (world != null) continue;
}
toRemove.add(node);
}
toRemove.forEach(n -> {
try {
group.unsetPermission(n);
} catch (ObjectLacksException ignored) {}
});
Message.BULK_CHANGE_SUCCESS.send(sender, toRemove.size());
save(group, sender, plugin);
return CommandResult.SUCCESS;
} else {
final String node = "suffix." + priority + "." + ArgumentChecker.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) {
group.unsetPermission(node, server);
Message.REMOVESUFFIX_SERVER_SUCCESS.send(sender, group.getDisplayName(), suffix, priority, server);
LogEntry.build().actor(sender).acted(group)
.action("removesuffix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
group.unsetPermission(node, server, world);
Message.REMOVESUFFIX_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), suffix, priority, server, world);
LogEntry.build().actor(sender).acted(group)
.action("removesuffix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.unsetPermission(node);
Message.REMOVESUFFIX_SUCCESS.send(sender, group.getDisplayName(), suffix, priority);
LogEntry.build().actor(sender).acted(group)
.action("removesuffix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_SUFFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
}
}
@@ -1,154 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.ArrayList;
import java.util.List;
public class GroupRemoveTempPrefix extends SubCommand<Group> {
public GroupRemoveTempPrefix() {
super("removetempprefix", "Removes a temporary prefix from the group", Permission.GROUP_REMOVE_TEMP_PREFIX,
Predicate.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to remove the prefix at"),
Arg.create("prefix", true, "the prefix string to remove"),
Arg.create("server", false, "the server to remove the prefix on"),
Arg.create("world", false, "the world to remove the prefix on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
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;
}
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 : group.getNodes()) {
if (!node.isPrefix()) continue;
if (node.getPrefix().getKey() != priority) continue;
if (node.isPermanent()) continue;
if (node.getServer().isPresent()) {
if (server == null) continue;
if (!node.getServer().get().equalsIgnoreCase(server)) continue;
} else {
if (server != null) continue;
}
if (node.getWorld().isPresent()) {
if (world == null) continue;
if (!node.getWorld().get().equalsIgnoreCase(world)) continue;
} else {
if (world != null) continue;
}
toRemove.add(node);
}
toRemove.forEach(n -> {
try {
group.unsetPermission(n);
} catch (ObjectLacksException ignored) {}
});
Message.BULK_CHANGE_SUCCESS.send(sender, toRemove.size());
save(group, sender, plugin);
return CommandResult.SUCCESS;
} else {
final String node = "prefix." + priority + "." + ArgumentChecker.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) {
group.unsetPermission(node, server, true);
Message.REMOVE_TEMP_PREFIX_SERVER_SUCCESS.send(sender, group.getDisplayName(), prefix, priority, server);
LogEntry.build().actor(sender).acted(group)
.action("removetempprefix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
group.unsetPermission(node, server, world, true);
Message.REMOVE_TEMP_PREFIX_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), prefix, priority, server, world);
LogEntry.build().actor(sender).acted(group)
.action("removetempprefix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.unsetPermission(node, true);
Message.REMOVE_TEMP_PREFIX_SUCCESS.send(sender, group.getDisplayName(), prefix, priority);
LogEntry.build().actor(sender).acted(group)
.action("removetempprefix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_PREFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
}
}
@@ -1,154 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.ArrayList;
import java.util.List;
public class GroupRemoveTempSuffix extends SubCommand<Group> {
public GroupRemoveTempSuffix() {
super("removetempsuffix", "Removes a temporary suffix from the group", Permission.GROUP_REMOVE_TEMP_SUFFIX,
Predicate.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to remove the suffix at"),
Arg.create("suffix", true, "the suffix string to remove"),
Arg.create("server", false, "the server to remove the suffix on"),
Arg.create("world", false, "the world to remove the suffix on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
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;
}
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 : group.getNodes()) {
if (!node.isSuffix()) continue;
if (node.getSuffix().getKey() != priority) continue;
if (node.isPermanent()) continue;
if (node.getServer().isPresent()) {
if (server == null) continue;
if (!node.getServer().get().equalsIgnoreCase(server)) continue;
} else {
if (server != null) continue;
}
if (node.getWorld().isPresent()) {
if (world == null) continue;
if (!node.getWorld().get().equalsIgnoreCase(world)) continue;
} else {
if (world != null) continue;
}
toRemove.add(node);
}
toRemove.forEach(n -> {
try {
group.unsetPermission(n);
} catch (ObjectLacksException ignored) {}
});
Message.BULK_CHANGE_SUCCESS.send(sender, toRemove.size());
save(group, sender, plugin);
return CommandResult.SUCCESS;
} else {
final String node = "suffix." + priority + "." + ArgumentChecker.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) {
group.unsetPermission(node, server, true);
Message.REMOVE_TEMP_SUFFIX_SERVER_SUCCESS.send(sender, group.getDisplayName(), suffix, priority, server);
LogEntry.build().actor(sender).acted(group)
.action("removetempsuffix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
group.unsetPermission(node, server, world, true);
Message.REMOVE_TEMP_SUFFIX_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), suffix, priority, server, world);
LogEntry.build().actor(sender).acted(group)
.action("removetempsuffix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.unsetPermission(node, true);
Message.REMOVE_TEMP_SUFFIX_SUCCESS.send(sender, group.getDisplayName(), suffix, priority);
LogEntry.build().actor(sender).acted(group)
.action("removetempsuffix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_SUFFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
}
}
@@ -1,111 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class GroupSetInherit extends SubCommand<Group> {
public GroupSetInherit() {
super("setinherit", "Sets another group for the group to inherit permissions from",
Permission.GROUP_SETINHERIT, Predicate.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"),
Arg.create("world", false, "the world to inherit the group on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (ArgumentChecker.checkNode(groupName)) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (!plugin.getDatastore().loadGroup(groupName)) {
Message.GROUP_DOES_NOT_EXIST.send(sender);
return CommandResult.INVALID_ARGS;
}
Group group1 = plugin.getGroupManager().get(groupName);
if (group1 == null) {
Message.GROUP_DOES_NOT_EXIST.send(sender);
return CommandResult.LOADING_ERROR;
}
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) {
group.setInheritGroup(group1, server);
Message.GROUP_SETINHERIT_SERVER_SUCCESS.send(sender, group.getDisplayName(), group1.getDisplayName(), server);
LogEntry.build().actor(sender).acted(group)
.action("setinherit " + group1.getName() + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(2).toLowerCase();
group.setInheritGroup(group1, server, world);
Message.GROUP_SETINHERIT_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), group1.getDisplayName(), server, world);
LogEntry.build().actor(sender).acted(group)
.action("setinherit " + group1.getName() + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.setInheritGroup(group1);
Message.GROUP_SETINHERIT_SUCCESS.send(sender, group.getDisplayName(), group1.getDisplayName());
LogEntry.build().actor(sender).acted(group)
.action("setinherit " + group1.getName())
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.GROUP_ALREADY_INHERITS.send(sender, group.getDisplayName(), group1.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@Override
public List<String> onTabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
return getGroupTabComplete(args, plugin);
}
}
@@ -1,113 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class GroupSetPermission extends SubCommand<Group> {
public GroupSetPermission() {
super("set", "Sets a permission for the group", Permission.GROUP_SETPERMISSION, Predicate.notInRange(2, 4),
Arg.list(
Arg.create("node", true, "the permission node to set"),
Arg.create("true|false", true, "the value of the node"),
Arg.create("server", false, "the server to add the permission node on"),
Arg.create("world", false, "the world to add the permission node on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String node = args.get(0).replace("{SPACE}", " ");
String bool = args.get(1).toLowerCase();
if (ArgumentChecker.checkNode(node)) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (node.toLowerCase().startsWith("group.")) {
Message.GROUP_USE_INHERIT.send(sender);
return CommandResult.INVALID_ARGS;
}
if (!bool.equalsIgnoreCase("true") && !bool.equalsIgnoreCase("false")) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
boolean b = Boolean.parseBoolean(bool);
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) {
group.setPermission(node, b, server);
Message.SETPERMISSION_SERVER_SUCCESS.send(sender, node, bool, group.getDisplayName(), server);
LogEntry.build().actor(sender).acted(group)
.action("set " + node + " " + b + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
group.setPermission(node, b, server, world);
Message.SETPERMISSION_SERVER_WORLD_SUCCESS.send(sender, node, bool, group.getDisplayName(), server, world);
LogEntry.build().actor(sender).acted(group)
.action("set " + node + " " + b + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.setPermission(node, b);
Message.SETPERMISSION_SUCCESS.send(sender, node, bool, group.getDisplayName());
LogEntry.build().actor(sender).acted(group)
.action("set " + node + " " + b)
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HASPERMISSION.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@Override
public List<String> onTabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
return getBoolTabComplete(args);
}
}
@@ -1,132 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.DateUtil;
import java.util.List;
public class GroupSetTempInherit extends SubCommand<Group> {
public GroupSetTempInherit() {
super("settempinherit", "Sets another group for the group to inherit permissions from temporarily",
Permission.GROUP_SET_TEMP_INHERIT, Predicate.notInRange(2, 4),
Arg.list(
Arg.create("group", true, "the group to inherit from"),
Arg.create("duration", true, "the duration of the group membership"),
Arg.create("server", false, "the server to add the group on"),
Arg.create("world", false, "the world to add the group on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (ArgumentChecker.checkNode(groupName)) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
long duration;
try {
duration = Long.parseLong(args.get(1));
} catch (NumberFormatException e) {
try {
duration = DateUtil.parseDateDiff(args.get(1), true);
} catch (DateUtil.IllegalDateException e1) {
Message.ILLEGAL_DATE_ERROR.send(sender, args.get(1));
return CommandResult.INVALID_ARGS;
}
}
if (DateUtil.shouldExpire(duration)) {
Message.PAST_DATE_ERROR.send(sender);
return CommandResult.INVALID_ARGS;
}
if (!plugin.getDatastore().loadGroup(groupName)) {
Message.GROUP_DOES_NOT_EXIST.send(sender);
return CommandResult.INVALID_ARGS;
}
Group group1 = plugin.getGroupManager().get(groupName);
if (group1 == null) {
Message.GROUP_DOES_NOT_EXIST.send(sender);
return CommandResult.INVALID_ARGS;
}
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) {
group.setInheritGroup(group1, server, duration);
Message.GROUP_SET_TEMP_INHERIT_SERVER_SUCCESS.send(sender, group.getDisplayName(), group1.getDisplayName(), server,
DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("settempinherit " + group1.getName() + " " + duration + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
group.setInheritGroup(group1, server, world, duration);
Message.GROUP_SET_TEMP_INHERIT_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), group1.getDisplayName(), server,
world, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("settempinherit " + group1.getName() + " " + duration + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.setInheritGroup(group1, duration);
Message.GROUP_SET_TEMP_INHERIT_SUCCESS.send(sender, group.getDisplayName(), group1.getDisplayName(), DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("settempinherit " + group1.getName() + " " + duration)
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.USER_ALREADY_TEMP_MEMBER_OF.send(sender, group.getDisplayName(), group1.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@Override
public List<String> onTabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
return getGroupTabComplete(args, plugin);
}
}
@@ -1,135 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.DateUtil;
import java.util.List;
public class GroupSetTempPermission extends SubCommand<Group> {
public GroupSetTempPermission() {
super("settemp", "Sets a permission for the group temporarily", Permission.GROUP_SET_TEMP_PERMISSION,
Predicate.notInRange(3, 5),
Arg.list(
Arg.create("node", true, "the permission node to set"),
Arg.create("true|false", true, "the value of the node"),
Arg.create("duration", true, "the duration until the permission node expires"),
Arg.create("server", false, "the server to add the permission node on"),
Arg.create("world", false, "the world to add the permission node on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String node = args.get(0).replace("{SPACE}", " ");
String bool = args.get(1).toLowerCase();
if (ArgumentChecker.checkNode(node)) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (node.toLowerCase().startsWith("group.")) {
Message.GROUP_USE_INHERIT.send(sender);
return CommandResult.INVALID_ARGS;
}
if (!bool.equalsIgnoreCase("true") && !bool.equalsIgnoreCase("false")) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
boolean b = Boolean.parseBoolean(bool);
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;
}
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) {
group.setPermission(node, b, server, duration);
Message.SETPERMISSION_TEMP_SERVER_SUCCESS.send(sender, node, bool, group.getDisplayName(), server,
DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("settemp " + node + " " + b + " " + duration + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(4).toLowerCase();
group.setPermission(node, b, server, world, duration);
Message.SETPERMISSION_TEMP_SERVER_WORLD_SUCCESS.send(sender, node, bool, group.getDisplayName(), server,
world, DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("settemp " + node + " " + b + " " + duration + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.setPermission(node, b, duration);
Message.SETPERMISSION_TEMP_SUCCESS.send(sender, node, bool, group.getDisplayName(), DateUtil.formatDateDiff(duration));
LogEntry.build().actor(sender).acted(group)
.action("settemp " + node + " " + b + " " + duration)
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_TEMP_PERMISSION.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@Override
public List<String> onTabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
return getBoolTabComplete(args);
}
}
@@ -1,99 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class GroupUnSetPermission extends SubCommand<Group> {
public GroupUnSetPermission() {
super("unset", "Unsets a permission for the group", Permission.GROUP_UNSETPERMISSION, Predicate.notInRange(1, 3),
Arg.list(
Arg.create("node", true, "the permission node to unset"),
Arg.create("server", false, "the server to remove the permission node on"),
Arg.create("world", false, "the world to remove the permission node on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String node = args.get(0).replace("{SPACE}", " ");
if (ArgumentChecker.checkNode(node)) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (node.toLowerCase().startsWith("group.")) {
Message.GROUP_USE_UNINHERIT.send(sender);
return CommandResult.INVALID_ARGS;
}
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) {
group.unsetPermission(node, server);
Message.UNSETPERMISSION_SERVER_SUCCESS.send(sender, node, group.getDisplayName(), server);
LogEntry.build().actor(sender).acted(group)
.action("unset " + node + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(2).toLowerCase();
group.unsetPermission(node, server, world);
Message.UNSETPERMISSION_SERVER_WORLD_SUCCESS.send(sender, node, group.getDisplayName(), server, world);
LogEntry.build().actor(sender).acted(group)
.action("unset " + node + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.unsetPermission(node);
Message.UNSETPERMISSION_SUCCESS.send(sender, node, group.getDisplayName());
LogEntry.build().actor(sender).acted(group)
.action("unset " + node)
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVEPERMISSION.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
}
@@ -1,100 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class GroupUnsetInherit extends SubCommand<Group> {
public GroupUnsetInherit() {
super("unsetinherit", "Removes a previously set inheritance rule", Permission.GROUP_UNSETINHERIT,
Predicate.notInRange(1, 3),
Arg.list(
Arg.create("group", true, "the group to uninherit"),
Arg.create("server", false, "the server to remove the group on"),
Arg.create("world", false, "the world to remove the group on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (ArgumentChecker.checkNode(groupName)) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
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) {
group.unsetPermission("group." + groupName, server);
Message.GROUP_UNSETINHERIT_SERVER_SUCCESS.send(sender, group.getDisplayName(), groupName, server);
LogEntry.build().actor(sender).acted(group)
.action("unsetinherit " + groupName + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(2).toLowerCase();
group.unsetPermission("group." + groupName, server, world);
Message.GROUP_UNSETINHERIT_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), groupName, server, world);
LogEntry.build().actor(sender).acted(group)
.action("unsetinherit " + groupName + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.unsetPermission("group." + groupName);
Message.GROUP_UNSETINHERIT_SUCCESS.send(sender, group.getDisplayName(), groupName);
LogEntry.build().actor(sender).acted(group)
.action("unsetinherit " + groupName)
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.GROUP_DOES_NOT_INHERIT.send(sender, group.getDisplayName(), groupName);
return CommandResult.STATE_ERROR;
}
}
@Override
public List<String> onTabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
return getGroupTabComplete(args, plugin);
}
}
@@ -1,100 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class GroupUnsetTempInherit extends SubCommand<Group> {
public GroupUnsetTempInherit() {
super("unsettempinherit", "Removes a previously set temporary inheritance rule",
Permission.GROUP_UNSET_TEMP_INHERIT, Predicate.notInRange(1, 3),
Arg.list(
Arg.create("group", true, "the group to uninherit"),
Arg.create("server", false, "the server to remove the group on"),
Arg.create("world", false, "the world to remove the group on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (ArgumentChecker.checkNode(groupName)) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
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) {
group.unsetPermission("group." + groupName, server, true);
Message.GROUP_UNSET_TEMP_INHERIT_SERVER_SUCCESS.send(sender, group.getDisplayName(), groupName, server);
LogEntry.build().actor(sender).acted(group)
.action("unsettempinherit " + groupName + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(2).toLowerCase();
group.unsetPermission("group." + groupName, server, world, true);
Message.GROUP_UNSET_TEMP_INHERIT_SERVER_WORLD_SUCCESS.send(sender, group.getDisplayName(), groupName, server, world);
LogEntry.build().actor(sender).acted(group)
.action("unsettempinherit " + groupName + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.unsetPermission("group." + groupName, true);
Message.GROUP_UNSET_TEMP_INHERIT_SUCCESS.send(sender, group.getDisplayName(), groupName);
LogEntry.build().actor(sender).acted(group)
.action("unsettempinherit " + groupName)
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.GROUP_DOES_NOT_TEMP_INHERIT.send(sender, group.getDisplayName(), groupName);
return CommandResult.STATE_ERROR;
}
}
@Override
public List<String> onTabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
return getGroupTabComplete(args, plugin);
}
}
@@ -1,100 +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.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class GroupUnsetTempPermission extends SubCommand<Group> {
public GroupUnsetTempPermission() {
super("unsettemp", "Unsets a temporary permission for the group", Permission.GROUP_UNSET_TEMP_PERMISSION,
Predicate.notInRange(1, 3),
Arg.list(
Arg.create("node", true, "the permission node to unset"),
Arg.create("server", false, "the server to remove the permission node on"),
Arg.create("world", false, "the world to remove the permission node on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String node = args.get(0).replace("{SPACE}", " ");
if (ArgumentChecker.checkNode(node)) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (node.toLowerCase().startsWith("group.")) {
Message.GROUP_USE_UNINHERIT.send(sender);
return CommandResult.INVALID_ARGS;
}
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) {
group.unsetPermission(node, server);
Message.UNSET_TEMP_PERMISSION_SERVER_SUCCESS.send(sender, node, group.getDisplayName(), server);
LogEntry.build().actor(sender).acted(group)
.action("unsettemp " + node + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(2).toLowerCase();
group.unsetPermission(node, server, world);
Message.UNSET_TEMP_PERMISSION_SERVER_WORLD_SUCCESS.send(sender, node, group.getDisplayName(), server, world);
LogEntry.build().actor(sender).acted(group)
.action("unsettemp " + node + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
group.unsetPermission(node, true);
Message.UNSET_TEMP_PERMISSION_SUCCESS.send(sender, node, group.getDisplayName());
LogEntry.build().actor(sender).acted(group)
.action("unsettemp " + node)
.build().submit(plugin, sender);
}
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_TEMP_PERMISSION.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
}
@@ -1,111 +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.commands.user.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class UserAddGroup extends SubCommand<User> {
public UserAddGroup() {
super("addgroup", "Adds the user to a group", Permission.USER_ADDGROUP, Predicate.notInRange(1, 3),
Arg.list(
Arg.create("group", true, "the group to add the user to"),
Arg.create("server", false, "the server to add the group on"),
Arg.create("world", false, "the world to add the group on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (ArgumentChecker.checkNode(groupName)) {
sendDetailedUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (!plugin.getDatastore().loadGroup(groupName)) {
Message.GROUP_DOES_NOT_EXIST.send(sender);
return CommandResult.INVALID_ARGS;
}
Group group = plugin.getGroupManager().get(groupName);
if (group == null) {
Message.GROUP_DOES_NOT_EXIST.send(sender);
return CommandResult.LOADING_ERROR;
}
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) {
user.addGroup(group, server);
Message.USER_ADDGROUP_SERVER_SUCCESS.send(sender, user.getName(), group.getDisplayName(), server);
LogEntry.build().actor(sender).acted(user)
.action("addgroup " + group.getName() + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(2).toLowerCase();
user.addGroup(group, server, world);
Message.USER_ADDGROUP_SERVER_WORLD_SUCCESS.send(sender, user.getName(), group.getDisplayName(), server, world);
LogEntry.build().actor(sender).acted(user)
.action("addgroup " + group.getName() + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
user.addGroup(group);
Message.USER_ADDGROUP_SUCCESS.send(sender, user.getName(), group.getDisplayName());
LogEntry.build().actor(sender).acted(user)
.action("addgroup " + group.getName())
.build().submit(plugin, sender);
}
save(user, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.USER_ALREADY_MEMBER_OF.send(sender, user.getName(), group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@Override
public List<String> onTabComplete(LuckPermsPlugin plugin, Sender sender, List<String> args) {
return getGroupTabComplete(args, plugin);
}
}
@@ -1,99 +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.commands.user.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
public class UserAddPrefix extends SubCommand<User> {
public UserAddPrefix() {
super("addprefix", "Adds a prefix to the user", Permission.USER_ADDPREFIX, Predicate.notInRange(2, 4),
Arg.list(
Arg.create("priority", true, "the priority to add the prefix at"),
Arg.create("prefix", true, "the prefix string"),
Arg.create("server", false, "the server to add the prefix on"),
Arg.create("world", false, "the world to add the prefix on")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
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;
}
final String node = "prefix." + priority + "." + ArgumentChecker.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) {
user.setPermission(node, true, server);
Message.ADDPREFIX_SERVER_SUCCESS.send(sender, user.getName(), prefix, priority, server);
LogEntry.build().actor(sender).acted(user)
.action("addprefix " + priority + " " + args.get(1) + " " + server)
.build().submit(plugin, sender);
} else {
final String world = args.get(3).toLowerCase();
user.setPermission(node, true, server, world);
Message.ADDPREFIX_SERVER_WORLD_SUCCESS.send(sender, user.getName(), prefix, priority, server, world);
LogEntry.build().actor(sender).acted(user)
.action("addprefix " + priority + " " + args.get(1) + " " + server + " " + world)
.build().submit(plugin, sender);
}
} else {
user.setPermission(node, true);
Message.ADDPREFIX_SUCCESS.send(sender, user.getName(), prefix, priority);
LogEntry.build().actor(sender).acted(user)
.action("addprefix " + priority + " " + args.get(1))
.build().submit(plugin, sender);
}
save(user, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_PREFIX.send(sender, user.getName());
return CommandResult.STATE_ERROR;
}
}
}
Loaded 100 of 355 files, more files were not shown because too many files have changed in this diff. Show more