Compare commits

...
66 Commits
Author SHA1 Message Date
Luck 3424b0542a Release 2.10 2016-09-25 17:32:58 +01:00
Luck fec90b8958 Add bulkchange commands 2016-09-25 17:29:11 +01:00
Luck 4da7fe4ff9 Small fixes to context system 2016-09-25 16:55:14 +01:00
Luck c53623dd67 Make command usage output easier to read 2016-09-25 14:34:27 +01:00
Luck 6540ffa4dd Refactor storage 2016-09-25 12:47:15 +01:00
Luck 5ee6db02ff Proper context implementation - WIP 2016-09-25 10:19:36 +01:00
Luck d8221f466a Fix messages not being formatted correctly 2016-09-24 17:22:33 +01:00
Luck 462bea2a09 Remove broken repo, maybe fix build 2016-09-24 16:58:45 +01:00
Luck f452a97278 fix typo 2016-09-23 22:19:17 +01:00
Luck eb9d2be587 Add locale file support 2016-09-23 22:14:40 +01:00
Luck df1e747861 Add commands to view inherited groups 2016-09-23 19:23:31 +01:00
Luck f48595b1ff Add world and group name rewriting, refactor configs 2016-09-23 18:58:19 +01:00
Luck 12cd4e19cb Update config comments 2016-09-22 18:25:49 +01:00
Luck a195e94522 Calculate defaults after all plugins have loaded 2016-09-22 17:34:51 +01:00
Luck 02abb39dc2 Change #isPermissionSet to be more like the Bukkit impl 2016-09-21 22:04:18 +01:00
Luck f7a0b1ef78 Refactor default permissions to be less bad 2016-09-21 21:30:42 +01:00
Luck 7678f25879 Fix default permissions not properly applying on Bukkit 2016-09-21 17:40:05 +01:00
Luck fa9324bda8 Implement basic standalone base, working towards #9 2016-09-20 21:50:28 +01:00
Luck 1e72f9d8fe Listen on lowest priority, may fix issues with plugins checking for permissions on login events 2016-09-20 21:04:53 +01:00
Luck 50fd954599 Use a BiMap in UuidCache 2016-09-19 21:13:45 +01:00
Luck b1e34b55f8 Re-add regex permissions & actually take note of the config options 2016-09-19 21:00:23 +01:00
Luck cff1b8a411 Separate PermissionProcessor into own class 2016-09-19 20:45:37 +01:00
Luck 6ffa6720be Make more specific wildcards take priority over less specific ones 2016-09-19 20:36:52 +01:00
Luck f52a106165 Order nodes alphabetically after other priority rules have been applied 2016-09-19 17:31:00 +01:00
Luck bf247b71e1 Fix possible race condition & maybe use better Hikari flags 2016-09-18 23:13:20 +01:00
Luck 66818e4c82 Fix build 2016-09-17 23:46:11 +01:00
Luck 23d53d39b4 Refactor permission calculation 2016-09-17 23:15:07 +01:00
Luck 30ea5a5b69 Fix no permissions applying when include-global is false, and better support per-server/per-world groups 2016-09-17 19:05:56 +01:00
Luck e7a210dc06 Update default configs 2016-09-16 22:09:55 +01:00
Luck 497de9824a Actually pass on a single wildcard node so it gets applied 2016-09-16 21:46:55 +01:00
Luck be74b50762 Fixes for offline mode servers 2016-09-16 21:24:25 +01:00
Luck f2e06b56e7 Cache permission lookups 2016-09-16 21:11:12 +01:00
Luck f6aa20c300 Fix compile 2016-09-15 17:12:19 +01:00
Luck 5e16134f6f Provide prefixes and suffixes through the PS options 2016-09-15 17:06:27 +01:00
Luck 6165fcbb21 Fix #getDefaults for users 2016-09-15 16:54:12 +01:00
Luck 831e882db0 Actually apply default permissions on Sponge 2016-09-15 16:53:03 +01:00
Luck feb8bf4bd3 Update readme 2016-09-14 20:16:36 +01:00
Luck ce3ee866ca Sponge fixes 2016-09-14 19:37:20 +01:00
Luck d29dd35689 Support the latest powerfulperms so-called "api" 2016-09-13 20:14:16 +01:00
Luck 3a0a89853f Apply negated wildcards 2016-09-13 17:23:16 +01:00
Luck e7ca79d251 Use Splitter instead of Patterns, don't split arguments in quotes 2016-09-12 19:00:37 +01:00
Luck 22426bab33 Update placeholders to use the latest API version 2016-09-11 15:36:19 +01:00
Luck 116094ea96 Maybe fix an issue with per-server prefixes/suffixes 2016-09-11 14:34:38 +01:00
Luck 9df39a9545 Inject PermissibleBase instead of using attachments. Resolves #14 2016-09-11 11:50:59 +01:00
Luck b8f44df723 Add missing headers 2016-09-10 22:40:36 +01:00
Luck 74f275eb69 Add more info the importer error output 2016-09-10 22:08:07 +01:00
Luck 1142cbcb2c Add platform type to the info command 2016-09-10 21:54:31 +01:00
Luck 37749e5829 Don't apply the default group when exporting users 2016-09-10 16:53:04 +01:00
Luck f9025c7a51 fix #getUniqueUsers for SQL storage types 2016-09-10 16:38:37 +01:00
Luck c7bfc38477 Build an extra jar with guava and gson shaded to support 1.7 2016-09-10 16:32:37 +01:00
Luck 7ca394d7b9 Add some extra console output to the debug command 2016-09-10 14:35:12 +01:00
Luck 31884ea59d Maybe fix race condition with messages not sending 2016-09-10 14:31:42 +01:00
Luck e79b7c7023 Update readme 2016-09-10 09:04:59 +01:00
Luck 1fdb4e8ade Merge pull request #11 from HeroCC/patch-1
Fix PermissionsEx false node migration
2016-09-09 21:49:43 +01:00
HeroCC 53db8c5928 Fix PermissionsEx false node migration
PermissionsEx false nodes begin with a '-' not a '!'
2016-09-09 16:39:13 -04:00
Luck 07514000a4 Fix global groups not being migrated from GroupManager 2016-09-09 18:41:15 +01:00
Luck f28721e55a Possible fix for permissions not applying on BungeeCord 2016-09-09 18:32:50 +01:00
Luck fc230291d3 Fix ops not receiving all permission nodes 2016-09-09 18:00:38 +01:00
Luck 89ff4cfa40 Add a much better system for exporting data 2016-09-08 21:01:37 +01:00
Luck d786b6abb2 Fix removing negative nodes 2016-09-08 17:28:31 +01:00
Luck fb0e694155 Add auto-op. Closes #8 2016-09-07 23:21:24 +01:00
Luck cd6cac1fb6 Fix bad grammar in config option comment 2016-09-07 21:01:03 +01:00
Luck ea07f05097 Release 2.8 2016-09-07 20:53:33 +01:00
Luck d84767af68 Fix blank users not receiving group permission updates 2016-09-06 22:28:37 +01:00
Luck aab73a8d81 Add more shorthand nodes 2016-09-06 22:27:46 +01:00
Luck 995fc2ccd8 Bump internal release version and add missing javadoc 2016-09-05 20:06:41 +01:00
193 changed files with 6153 additions and 2034 deletions

No files matched your search

+10 -1
View File
@@ -1,5 +1,6 @@
![alt text](https://i.imgur.com/7TwJZ5e.png "Banner")
# LuckPerms [![Build Status](https://ci.lucko.me/job/LuckPerms/badge/icon)](https://ci.lucko.me/job/LuckPerms/)
A permissions implementation for Bukkit/Spigot, BungeeCord and Sponge.
An advanced permissions implementation for Bukkit/Spigot, BungeeCord and Sponge.
## Links
* **Development Builds** - <https://ci.lucko.me/job/LuckPerms>
@@ -9,9 +10,17 @@ A permissions implementation for Bukkit/Spigot, BungeeCord and Sponge.
## Description
LuckPerms is an advanced permissions implementation aiming to be a flexible, performant and reliable alternative to other permission systems, providing all the features you could ever possibly need in a permissions plugin, along with an extensive and well documented API for developers.
* [Spigot Plugin Page](https://www.spigotmc.org/resources/luckperms-an-advanced-permissions-system.28140/ "Spigot Plugin Page")
* [Sponge Plugin Page](https://forums.spongepowered.org/t/luckperms-an-advanced-permissions-system/14274 "Sponge Plugin Page")
## LuckPerms vs Other Plugins
![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._
## License
See LICENSE.md.
## 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").
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.7-SNAPSHOT</version>
<version>2.10-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -62,6 +62,24 @@ public interface LPConfiguration {
*/
boolean getIncludeGlobalPerms();
/**
* @return if the users on this server will have their global world permissions applied
* @since 2.9
*/
boolean getIncludeGlobalWorldPerms();
/**
* @return true if the platform is applying global groups
* @since 2.9
*/
boolean getApplyGlobalGroups();
/**
* @return true if the platform is applying global world groups
* @since 2.9
*/
boolean getApplyGlobalWorldGroups();
/**
* @return the online mode setting in the config
*/
@@ -88,6 +106,30 @@ public interface LPConfiguration {
*/
boolean getLogNotify();
/**
* @return true if permission checks are being recorded / debugged
* @since 2.9
*/
boolean getDebugPermissionChecks();
/**
* @return true if the vanilla op system is enabled
* @since 2.8
*/
boolean getEnableOps();
/**
* @return true if opped players are allowed to use LuckPerms commands
* @since 2.8
*/
boolean getCommandsAllowOp();
/**
* @return true if auto op is enabled
* @since 2.9
*/
boolean getAutoOp();
/**
* @return the name of the server used within Vault operations
* @since 2.7
@@ -22,6 +22,8 @@
package me.lucko.luckperms.api;
import me.lucko.luckperms.api.context.ContextListener;
import me.lucko.luckperms.api.context.IContextCalculator;
import me.lucko.luckperms.api.event.LPListener;
import java.util.Optional;
@@ -52,6 +54,7 @@ public interface LuckPermsApi {
/**
* @return the platform LuckPerms is running on
* @since 2.7
*/
PlatformType getPlatformType();
@@ -186,7 +189,7 @@ public interface LuckPermsApi {
Track getTrack(String name);
/**
* Gets a wrapped tracj object from the track storage. This method does not return null, unlike {@link #getTrack}
* Gets a wrapped track object from the track storage. This method does not return null, unlike {@link #getTrack}
* @param name the name of the track to get
* @return an optional {@link Track} object
* @throws NullPointerException if the name is null
@@ -217,4 +220,18 @@ public interface LuckPermsApi {
*/
Node.Builder buildNode(String permission) throws IllegalArgumentException;
/**
* Register a custom context calculator to the server
* @param contextCalculator the context calculator to register. The type MUST be the player class of the platform.
* @throws ClassCastException if the type is not the player class of the platform.
*/
void registerContextCalculator(IContextCalculator<?> contextCalculator);
/**
* Registers a custom context listener to the server,
* @param contextListener the context listener to register. The type MUST be the player class of the platform.
* @throws ClassCastException if the type is not the player class of the platform.
*/
void registerContextListener(ContextListener<?> contextListener);
}
@@ -36,6 +36,8 @@ import java.util.Set;
*/
public class MetaUtils {
private MetaUtils(){}
/**
* Escapes special characters used within LuckPerms, so the string can be saved without issues
* @param s the string to escape
@@ -105,7 +105,15 @@ public interface Node extends Map.Entry<String, Boolean> {
boolean shouldApplyOnWorld(String world, boolean includeGlobal, boolean applyRegex);
/**
* If this node should apply given the specific 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
*/
boolean shouldApplyWithContext(Map<String, String> 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
*/
@@ -247,18 +255,34 @@ public interface Node extends Map.Entry<String, Boolean> {
Map.Entry<Integer, String> getSuffix();
/**
* Similar to {@link #equals(Object)}, except doesn't take note of the value
* @param node the other node
* @return true if the two nodes are almost equal
* Checks if this Node is equal to another node
* @param obj the other node
* @return true if this node is equal to the other provided
* @see #equalsIgnoringValue(Node) for a less strict implementation of this method
*/
boolean equalsIgnoringValue(Node node);
boolean equals(Object obj);
/**
* Similar to {@link #equals(Object)}, except doesn't take note of the expiry time or value
* @param node the other node
* Similar to {@link Node#equals(Object)}, except doesn't take note of the value
* @param other the other node
* @return true if the two nodes are almost equal
*/
boolean almostEquals(Node node);
boolean equalsIgnoringValue(Node other);
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the expiry time or value
* @param other the other node
* @return true if the two nodes are almost equal
*/
boolean almostEquals(Node other);
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the value or if the node is temporary
* @param other the other node
* @return true if the two nodes are almost equal
* @since 2.8
*/
boolean equalsIgnoringValueOrTemp(Node other);
/**
* Builds a Node instance
@@ -30,7 +30,12 @@ public enum PlatformType {
BUKKIT("Bukkit"),
BUNGEE("Bungee"),
SPONGE("Sponge");
SPONGE("Sponge"),
/**
* @since 2.9
*/
STANDALONE("Standalone");
private final String friendlyName;
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.context;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A simple implementation of the listener aspects of {@link IContextCalculator<T>}
* @param <T> the subject type
*/
public abstract class ContextCalculator<T> implements IContextCalculator<T> {
private final List<ContextListener<T>> listeners = new CopyOnWriteArrayList<>();
/**
* Pushes an update to all registered {@link ContextListener}s.
* Make sure any changes are applied internally before this method is called.
* @param subject the subject that changed
* @param before the context state before the change
* @param current the context state after the change (now)
* @throws NullPointerException if any parameters are null
*/
protected void pushUpdate(T subject, Map.Entry<String, String> before, Map.Entry<String, String> current) {
if (subject == null) {
throw new NullPointerException("subject");
}
if (before == null) {
throw new NullPointerException("before");
}
if (current == null) {
throw new NullPointerException("current");
}
for (ContextListener<T> listener : listeners) {
try {
listener.onContextChange(subject, before, current);
} catch (Exception e) {
System.out.println("Exception whilst passing context change to listener: " + listener);
e.printStackTrace();
}
}
}
@Override
public void addListener(ContextListener<T> listener) {
if (listener == null) {
throw new NullPointerException("listener");
}
listeners.add(listener);
}
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.context;
import java.util.Map;
/**
* Listens to context changes
* @param <T> the subject type, Is ALWAYS the player class of the platform.
*/
public interface ContextListener<T> {
/**
* Called whenever a context changes on the
* @param subject the subject that had context changed
* @param before the context state before the change
* @param current the context state after the change (now)
*/
void onContextChange(T subject, Map.Entry<String, String> before, Map.Entry<String, String> current) throws Exception;
}
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.context;
import java.util.Map;
/**
* Calculates whether contexts are applicable to {@link T}
*
* <p>Somewhat inspired by the system used on Sponge.
* @param <T> the subject type. Is ALWAYS the player class of the platform.
*/
public interface IContextCalculator<T> {
/**
* Gives the subject all of the applicable contexts they meet
* @param subject the subject to add contexts tp
* @param accumulator a map of contexts to add to
* @return the map
*/
Map<String, String> giveApplicableContext(T subject, Map<String, String> accumulator);
/**
* Checks to see if a context is applicable to a subject
* @param subject the subject to check against
* @param context the context to check for
* @return true if met, or false if not. If this calculator does not calculate the given context, return false.
*/
boolean isContextApplicable(T subject, Map.Entry<String, String> context);
/**
* Adds a listener to be called whenever a context handled by this calculator changes
* @param listener the listener instance
* @throws NullPointerException if listener is null
*/
void addListener(ContextListener<T> listener);
}
@@ -1,3 +1,25 @@
/*
* 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.exceptions;
/**
+119
View File
@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.10-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>luckperms-bukkit-legacy</artifactId>
<build>
<defaultGoal>clean package</defaultGoal>
<finalName>LuckPerms-bukkit-legacy-${release.version}.${git.closest.tag.commit.count}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<artifactSet>
<excludes>
<exclude>org.xerial:*</exclude>
</excludes>
</artifactSet>
<relocations>
<relocation>
<pattern>org.slf4j</pattern>
<shadedPattern>me.lucko.luckperms.lib.slf4j</shadedPattern>
</relocation>
<relocation>
<pattern>com.zaxxer.hikari</pattern>
<shadedPattern>me.lucko.luckperms.lib.hikari</shadedPattern>
</relocation>
<relocation>
<pattern>com.mongodb</pattern>
<shadedPattern>me.lucko.luckperms.lib.mongodb</shadedPattern>
</relocation>
<relocation>
<pattern>org.bson</pattern>
<shadedPattern>me.lucko.luckperms.lib.bson</shadedPattern>
</relocation>
<relocation>
<pattern>org.h2</pattern>
<shadedPattern>me.lucko.luckperms.lib.h2</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<injectAllReactorProjects>true</injectAllReactorProjects>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- LuckPerms Bukkit -->
<dependency>
<groupId>me.lucko.luckperms</groupId>
<artifactId>luckperms-bukkit</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<!-- Shade gson and guava, as they are not included in earlier Bukkit releases -->
<!-- gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.7</version>
<scope>compile</scope>
</dependency>
<!-- guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
+3 -3
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.7-SNAPSHOT</version>
<version>2.10-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -30,8 +30,8 @@
<dependency>
<groupId>me.lucko.luckperms</groupId>
<artifactId>luckperms-api</artifactId>
<version>2.5</version>
<scope>compile</scope>
<version>2.8</version>
<scope>provided</scope>
</dependency>
<!-- BukkitAPI -->
<dependency>
@@ -25,15 +25,11 @@ package me.lucko.luckperms.api.placeholders;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.util.TimeUtil;
import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.*;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
/*
* PlaceholderAPI Expansion for LuckPerms, implemented using the LuckPerms API.
@@ -75,7 +71,7 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
@Override
public String getVersion() {
return "2.5";
return "2.8";
}
@Override
@@ -84,7 +80,7 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
return "";
}
Optional<User> u = api.getUserSafe(player.getUniqueId());
Optional<User> u = api.getUserSafe(api.getUuidCache().getUUID(player.getUniqueId()));
if (!u.isPresent()) {
return "";
}
@@ -127,17 +123,11 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
if (identifier.startsWith("expiry_time_") && identifier.length() > "expiry_time_".length()) {
String node = identifier.substring("expiry_time_".length());
long currentTime = System.currentTimeMillis() / 1000L;
Map<Map.Entry<String, Boolean>, Long> temps = user.getTemporaryNodes();
for (Map.Entry<Map.Entry<String, Boolean>, Long> e : temps.entrySet()) {
if (!e.getKey().getKey().equalsIgnoreCase(node)) {
continue;
for (Node n : user.getTemporaryPermissionNodes()) {
if (n.getPermission().equalsIgnoreCase(node)) {
return TimeUtil.getTime((int) (n.getExpiryUnixTime() - currentTime));
}
return TimeUtil.getTime((int) (e.getValue() - currentTime));
}
return "";
@@ -145,42 +135,27 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
if (identifier.startsWith("group_expiry_time_") && identifier.length() > "group_expiry_time_".length()) {
String node = "group." + identifier.substring("group_expiry_time_".length());
long currentTime = System.currentTimeMillis() / 1000L;
Map<Map.Entry<String, Boolean>, Long> temps = user.getTemporaryNodes();
for (Map.Entry<Map.Entry<String, Boolean>, Long> e : temps.entrySet()) {
if (!e.getKey().getKey().equalsIgnoreCase(node)) {
continue;
for (Node n : user.getTemporaryPermissionNodes()) {
if (n.getPermission().equalsIgnoreCase(node)) {
return TimeUtil.getTime((int) (n.getExpiryUnixTime() - currentTime));
}
return TimeUtil.getTime((int) (e.getValue() - currentTime));
}
return "";
}
if (identifier.equalsIgnoreCase("prefix")) {
return getChatMeta(PREFIX_PATTERN, user);
return MetaUtils.getPrefix(user, null, null, true);
}
if (identifier.equalsIgnoreCase("suffix")) {
return getChatMeta(SUFFIX_PATTERN, user);
return MetaUtils.getSuffix(user, null, null, true);
}
if (identifier.startsWith("meta_") && identifier.length() > "meta_".length()) {
String node = "meta." + escapeCharacters(identifier.substring("meta_".length())) + ".";
Map<String, Boolean> nodes = user.getNodes();
for (Map.Entry<String, Boolean> e : nodes.entrySet()) {
if (!e.getValue()) continue;
if (!e.getKey().toLowerCase().startsWith(node)) continue;
String meta = e.getKey().substring(node.length());
return unescapeCharacters(meta);
}
return "";
String node = identifier.substring("meta_".length());
return MetaUtils.getMeta(user, null, null, node, "", true);
}
return null;
@@ -204,44 +179,4 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
private static String formatBoolean(boolean b) {
return b ? PlaceholderAPIPlugin.booleanTrue() : PlaceholderAPIPlugin.booleanFalse();
}
private static String escapeCharacters(String s) {
s = s.replace(".", "{SEP}");
s = s.replace("/", "{FSEP}");
s = s.replace("$", "{DSEP}");
return s;
}
private static String unescapeCharacters(String s) {
s = s.replace("{SEP}", ".");
s = s.replace("{FSEP}", "/");
s = s.replace("{DSEP}", "$");
return s;
}
private static final Pattern PREFIX_PATTERN = Pattern.compile("(?i)prefix\\.\\d+\\..*");
private static final Pattern SUFFIX_PATTERN = Pattern.compile("(?i)suffix\\.\\d+\\..*");
private static final Pattern DOT_PATTERN = Pattern.compile("\\.");
private static String getChatMeta(Pattern pattern, User user) {
int priority = 0;
String meta = null;
for (Map.Entry<String, Boolean> e : user.getLocalPermissions(null, null).entrySet()) {
if (!e.getValue()) continue;
if (pattern.matcher(e.getKey()).matches()) {
String[] parts = DOT_PATTERN.split(e.getKey(), 3);
int p = Integer.parseInt(parts[1]);
if (meta == null || p > priority) {
meta = parts[2];
priority = p;
}
}
}
return meta == null ? "" : unescapeCharacters(meta);
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.7-SNAPSHOT</version>
<version>2.10-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -22,8 +22,12 @@
package me.lucko.luckperms;
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 org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
@@ -39,13 +43,18 @@ class BukkitCommand extends CommandManager implements CommandExecutor, TabExecut
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
onCommand(BukkitSenderFactory.get().wrap(sender), label, Arrays.asList(args), Callback.empty());
onCommand(
BukkitSenderFactory.get(getPlugin()).wrap(sender),
label,
Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(Joiner.on(' ').join(args))),
Callback.empty()
);
return true;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
return onTabComplete(BukkitSenderFactory.get().wrap(sender), Arrays.asList(args));
return onTabComplete(BukkitSenderFactory.get(getPlugin()).wrap(sender), Arrays.asList(args));
}
}
@@ -22,14 +22,17 @@
package me.lucko.luckperms;
import me.lucko.luckperms.core.LPConfiguration;
import me.lucko.luckperms.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.Map;
class BukkitConfig extends LPConfiguration<LPBukkitPlugin> {
class BukkitConfig extends AbstractConfiguration<LPBukkitPlugin> {
private YamlConfiguration configuration;
BukkitConfig(LPBukkitPlugin plugin) {
@@ -55,11 +58,6 @@ class BukkitConfig extends LPConfiguration<LPBukkitPlugin> {
}
}
@Override
protected void set(String path, Object value) {
configuration.set(path, value);
}
@Override
protected String getString(String path, String def) {
return configuration.getString(path, def);
@@ -74,4 +72,20 @@ class BukkitConfig extends LPConfiguration<LPBukkitPlugin> {
protected boolean getBoolean(String path, boolean def) {
return configuration.getBoolean(path, def);
}
@SuppressWarnings("unchecked")
@Override
protected Map<String, String> getMap(String path, Map<String, String> def) {
Map<String, String> map = new HashMap<>();
ConfigurationSection section = configuration.getConfigurationSection(path);
if (section == null) {
return def;
}
for (String key : section.getKeys(false)) {
map.put(key, section.getString(key));
}
return map;
}
}
@@ -23,17 +23,18 @@
package me.lucko.luckperms;
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 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.permissions.PermissionAttachment;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.UUID;
class BukkitListener extends AbstractListener implements Listener {
private final LPBukkitPlugin plugin;
@@ -43,7 +44,7 @@ class BukkitListener extends AbstractListener implements Listener {
this.plugin = plugin;
}
@EventHandler
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerPreLogin(AsyncPlayerPreLoginEvent e) {
if (!plugin.getDatastore().isAcceptingLogins()) {
// The datastore is disabled, prevent players from joining the server
@@ -54,7 +55,7 @@ class BukkitListener extends AbstractListener implements Listener {
onAsyncLogin(e.getUniqueId(), e.getName());
}
@EventHandler
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerLogin(PlayerLoginEvent e) {
final Player player = e.getPlayer();
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
@@ -67,42 +68,47 @@ class BukkitListener extends AbstractListener implements Listener {
if (user instanceof BukkitUser) {
BukkitUser u = (BukkitUser) user;
PermissionAttachment attachment = player.addAttachment(plugin);
Map<String, Boolean> newPermMap = new ConcurrentHashMap<>();
try {
/* Replace the standard LinkedHashMap in the attachment with a ConcurrentHashMap.
This means that we can iterate over and change the permissions within our attachment asynchronously,
without worrying about thread safety. The Bukkit side of things should still operate normally. Internal
permission stuff should work the same. This is by far the most easy and efficient way to do things, without
having to do tons of reflection. */
BukkitUser.getPermissionsField().set(attachment, newPermMap);
LPPermissible lpPermissible = new LPPermissible(player, plugin, plugin.getDefaultsProvider());
Injector.inject(player, lpPermissible);
u.setLpPermissible(lpPermissible);
} catch (Throwable t) {
t.printStackTrace();
}
u.setAttachment(new BukkitUser.PermissionAttachmentHolder(attachment, newPermMap));
}
plugin.doAsync(user::refreshPermissions);
}
@EventHandler
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoin(PlayerJoinEvent e) {
// Refresh permissions again
plugin.getUserManager().getWorldCache().put(e.getPlayer().getUniqueId(), e.getPlayer().getWorld().getName());
plugin.doAsync(() -> refreshPlayer(e.getPlayer().getUniqueId()));
UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
plugin.getWorldCalculator().getWorldCache().put(internal, e.getPlayer().getWorld().getName());
plugin.doAsync(() -> refreshPlayer(internal));
}
@EventHandler
public void onPlayerChangedWorld(PlayerChangedWorldEvent e) {
plugin.getUserManager().getWorldCache().put(e.getPlayer().getUniqueId(), e.getPlayer().getWorld().getName());
plugin.doAsync(() -> refreshPlayer(e.getPlayer().getUniqueId()));
}
@EventHandler
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerQuit(PlayerQuitEvent e) {
plugin.getUserManager().getWorldCache().remove(e.getPlayer().getUniqueId());
plugin.getWorldCalculator().getWorldCache().remove(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
onLeave(e.getPlayer().getUniqueId());
}
@EventHandler
public void onPlayerCommand(PlayerCommandPreprocessEvent e) {
if (plugin.getConfiguration().isOpsEnabled()) {
return;
}
String s = e.getMessage()
.replace("/", "")
.replace("bukkit:", "")
.replace("spigot:", "")
.replace("minecraft:", "");
if (s.startsWith("op") || s.startsWith("deop")) {
e.setCancelled(true);
e.getPlayer().sendMessage(Message.OP_DISABLED.toString());
}
}
}
@@ -22,8 +22,6 @@
package me.lucko.luckperms;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import me.lucko.luckperms.commands.SenderFactory;
import me.lucko.luckperms.constants.Constants;
import org.bukkit.command.CommandSender;
@@ -31,12 +29,16 @@ import org.bukkit.entity.Player;
import java.util.UUID;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BukkitSenderFactory extends SenderFactory<CommandSender> {
private static BukkitSenderFactory instance = null;
public static BukkitSenderFactory get() {
if (instance == null){
instance = new BukkitSenderFactory();
private BukkitSenderFactory(LuckPermsPlugin plugin) {
super(plugin);
}
public static synchronized BukkitSenderFactory get(LuckPermsPlugin plugin) {
if (instance == null) {
instance = new BukkitSenderFactory(plugin);
}
return instance;
}
@@ -30,20 +30,27 @@ import me.lucko.luckperms.api.implementation.ApiProvider;
import me.lucko.luckperms.api.vault.VaultHook;
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.core.LPConfiguration;
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.inject.DefaultsProvider;
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;
@@ -66,6 +73,10 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
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() {
@@ -74,6 +85,20 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
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);
@@ -89,20 +114,27 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
datastore = StorageFactory.getDatastore(this, "h2");
getLog().info("Loading internal permission managers...");
uuidCache = new UuidCache(getConfiguration().getOnlineMode());
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(), 1L, 1L);
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);
@@ -133,6 +165,11 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
e.printStackTrace();
}
registerPermissions(getConfiguration().isCommandsAllowOp() ? PermissionDefault.OP : PermissionDefault.FALSE);
if (!getConfiguration().isOpsEnabled()) {
getServer().getOperators().forEach(o -> o.setOp(false));
}
getLog().info("Successfully loaded.");
}
@@ -187,13 +224,16 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
@Override
public List<Sender> getSenders() {
return getServer().getOnlinePlayers().stream().map(p -> BukkitSenderFactory.get().wrap(p)).collect(Collectors.toList());
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().wrap(getServer().getConsoleSender());
return BukkitSenderFactory.get(this).wrap(getServer().getConsoleSender());
}
@Override
@@ -237,4 +277,34 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
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))));
}
}
@@ -26,6 +26,7 @@ import lombok.NonNull;
import lombok.Setter;
import me.lucko.luckperms.LPBukkitPlugin;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.contexts.Contexts;
import me.lucko.luckperms.core.PermissionHolder;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
@@ -89,7 +90,7 @@ public class VaultChatHook extends Chat {
}
}
Node.Builder metaNode = new me.lucko.luckperms.utils.Node.Builder("meta." + node + "." + value).setValue(true);
Node.Builder metaNode = new me.lucko.luckperms.core.Node.Builder("meta." + node + "." + value).setValue(true);
if (!perms.getServer().equalsIgnoreCase("global")) {
metaNode.setServer(perms.getServer());
}
@@ -109,7 +110,7 @@ public class VaultChatHook extends Chat {
if (node.equals("")) return defaultValue;
node = escapeCharacters(node);
for (Node n : holder.getPermissions()) {
for (Node n : holder.getPermissions(true)) {
if (!n.getValue()) {
continue;
}
@@ -118,10 +119,8 @@ public class VaultChatHook extends Chat {
continue;
}
if (!perms.getServer().equalsIgnoreCase("global")) {
if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) {
continue;
}
if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) {
continue;
}
if (!n.shouldApplyOnWorld(world, perms.isIncludeGlobal(), false)) {
@@ -141,7 +140,7 @@ public class VaultChatHook extends Chat {
if (holder == null) return;
if (value.equals("")) return;
Node.Builder node = new me.lucko.luckperms.utils.Node.Builder(prefix ? "prefix" : "suffix" + ".1000." + escapeCharacters(value));
Node.Builder node = new me.lucko.luckperms.core.Node.Builder(prefix ? "prefix" : "suffix" + ".1000." + escapeCharacters(value));
node.setValue(true);
if (!perms.getServer().equalsIgnoreCase("global")) {
node.setServer(perms.getServer());
@@ -164,22 +163,20 @@ public class VaultChatHook extends Chat {
int priority = Integer.MIN_VALUE;
String meta = null;
for (Node n : holder.getAllNodes(null)) {
for (Node n : holder.getAllNodes(null, Contexts.allowAll())) {
if (!n.getValue()) {
continue;
}
if (!perms.getServer().equalsIgnoreCase("global")) {
if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) {
continue;
}
}
if (!n.shouldApplyOnWorld(world, perms.isIncludeGlobal(), false)) {
if (prefix ? !n.isPrefix() : !n.isSuffix()) {
continue;
}
if (prefix ? !n.isPrefix() : !n.isSuffix()) {
if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) {
continue;
}
if (!n.shouldApplyOnWorld(world, perms.isIncludeGlobal(), false)) {
continue;
}
@@ -40,7 +40,7 @@ public class VaultHook {
}
permissionHook.setPlugin(plugin);
permissionHook.setServer(plugin.getConfiguration().getVaultServer());
permissionHook.setIncludeGlobal(plugin.getConfiguration().getVaultIncludeGlobal());
permissionHook.setIncludeGlobal(plugin.getConfiguration().isVaultIncludingGlobal());
if (chatHook == null) {
chatHook = new VaultChatHook(permissionHook);
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.contexts;
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 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 java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@RequiredArgsConstructor
public class WorldCalculator extends ContextCalculator<Player> implements Listener {
private static final String WORLD_KEY = "world";
private final LuckPermsPlugin plugin;
@Getter
private final Map<UUID, String> worldCache = new ConcurrentHashMap<>();
@Override
public Map<String, String> giveApplicableContext(Player subject, Map<String, String> accumulator) {
String world = getWorld(subject);
if (world != null) {
accumulator.put(WORLD_KEY, world);
}
return accumulator;
}
@Override
public boolean isContextApplicable(Player subject, Map.Entry<String, String> context) {
if (!context.getKey().equals(WORLD_KEY)) {
return false;
}
String world = getWorld(subject);
return world != null && world.equals(context.getValue());
}
private String getWorld(Player player) {
UUID internal = plugin.getUuidCache().getUUID(player.getUniqueId());
if (!worldCache.containsKey(internal)) {
return null;
}
String world = worldCache.get(internal);
return plugin.getConfiguration().getWorldRewrites().getOrDefault(world, world);
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerChangedWorld(PlayerChangedWorldEvent e) {
UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
worldCache.put(internal, e.getPlayer().getWorld().getName());
pushUpdate(
e.getPlayer(),
Maps.immutableEntry(WORLD_KEY, e.getFrom().getName()),
Maps.immutableEntry(WORLD_KEY, e.getPlayer().getWorld().getName())
);
}
}
@@ -0,0 +1,177 @@
/*
* 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.inject;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.Tristate;
import org.bukkit.Bukkit;
import org.bukkit.permissions.Permissible;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class DefaultsProvider {
private final DummyPermissible opDummy = new DummyPermissible(this::refreshOp);
private final DummyPermissible nonOpDummy = new DummyPermissible(this::refreshNonOp);
private final Map<String, Boolean> op = new HashMap<>();
private final Map<String, Boolean> nonOp = new HashMap<>();
public void refresh() {
refreshOp();
refreshNonOp();
}
private void refreshOp() {
calculateDefaults(op, opDummy, true);
}
private void refreshNonOp() {
calculateDefaults(nonOp, nonOpDummy, false);
}
private static void calculateDefaults(Map<String, Boolean> map, DummyPermissible p, boolean op) {
Set<String> perms = map.keySet();
for (String name : perms) {
Bukkit.getServer().getPluginManager().unsubscribeFromPermission(name, p);
}
Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(false, p);
Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(true, p);
map.clear();
Set<Permission> defaults = Bukkit.getServer().getPluginManager().getDefaultPermissions(op);
Bukkit.getServer().getPluginManager().subscribeToDefaultPerms(op, p);
for (Permission perm : defaults) {
String name = perm.getName().toLowerCase();
map.put(name, true);
Bukkit.getServer().getPluginManager().subscribeToPermission(name, p);
calculateChildPermissions(map, p, perm.getChildren(), false);
}
}
private static void calculateChildPermissions(Map<String, Boolean> map, DummyPermissible p, Map<String, Boolean> children, boolean invert) {
for (Map.Entry<String, Boolean> e : children.entrySet()) {
Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey());
boolean value = e.getValue() ^ invert;
String lName = e.getKey().toLowerCase();
map.put(lName, value);
Bukkit.getServer().getPluginManager().subscribeToPermission(e.getKey(), p);
if (perm != null) {
calculateChildPermissions(map, p, perm.getChildren(), !value);
}
}
}
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));
}
@AllArgsConstructor
private static class DummyPermissible implements Permissible {
private final Runnable onRefresh;
@Override
public void recalculatePermissions() {
onRefresh.run();
}
@Override
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
return Collections.emptySet();
}
@Override
public boolean isPermissionSet(String name) {
return false;
}
@Override
public boolean isPermissionSet(Permission perm) {
return false;
}
@Override
public boolean hasPermission(String name) {
return false;
}
@Override
public boolean hasPermission(Permission perm) {
return false;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
return null;
}
@Override
public void removeAttachment(PermissionAttachment attachment) {
}
@Override
public boolean isOp() {
return false;
}
@Override
public void setOp(boolean value) {
}
}
}
@@ -0,0 +1,108 @@
/*
* 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.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;
/**
* Injects a {@link LPPermissible} into a {@link Player}
*/
@UtilityClass
public class Injector {
private static Field HUMAN_ENTITY_FIELD;
static {
try {
HUMAN_ENTITY_FIELD = Class.forName(getInternalClassName("entity.CraftHumanEntity")).getDeclaredField("perm");
HUMAN_ENTITY_FIELD.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public static boolean inject(CommandSender sender, PermissibleBase permissible) {
try {
Field f = getPermField(sender);
f.set(sender, permissible);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static boolean unInject(CommandSender sender) {
try {
Permissible permissible = getPermissible(sender);
if (permissible instanceof LPPermissible) {
getPermField(sender).set(sender, new PermissibleBase(sender));
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private static Permissible getPermissible(CommandSender sender) {
try {
Field f = getPermField(sender);
return (Permissible) f.get(sender);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
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) {
Class server = Bukkit.getServer().getClass();
if (!server.getSimpleName().equals("CraftServer")) {
throw new RuntimeException("Couldn't inject into server " + server);
}
String version;
if (server.getName().equals("org.bukkit.craftbukkit.CraftServer")) {
// Non versioned class
version = ".";
} else {
version = server.getName().substring("org.bukkit.craftbukkit".length());
version = version.substring(0, version.length() - "CraftServer".length());
}
return "org.bukkit.craftbukkit" + version + className;
}
}
@@ -0,0 +1,301 @@
/*
* 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.inject;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.calculators.PermissionCalculator;
import me.lucko.luckperms.calculators.PermissionProcessor;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.*;
import org.bukkit.plugin.Plugin;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.stream.Collectors;
/**
* Modified PermissibleBase for LuckPerms
*/
public class LPPermissible extends PermissibleBase {
@Getter
private final CommandSender parent;
private final PermissionCalculator calculator;
@Getter
private final Map<String, Boolean> luckPermsPermissions = new ConcurrentHashMap<>();
private final List<PermissionAttachment> attachments = new LinkedList<>();
private final Map<String, PermissionAttachmentInfo> attachmentPermissions = new HashMap<>();
public LPPermissible(@NonNull CommandSender sender, LuckPermsPlugin plugin, DefaultsProvider defaultsProvider) {
super(sender);
this.parent = sender;
List<PermissionProcessor> processors = new ArrayList<>(5);
processors.add(new PermissionCalculator.MapProcessor(luckPermsPermissions));
processors.add(new AttachmentProcessor(attachmentPermissions));
if (plugin.getConfiguration().isApplyingWildcards()) {
processors.add(new PermissionCalculator.WildcardProcessor(luckPermsPermissions));
}
if (plugin.getConfiguration().isApplyingRegex()) {
processors.add(new PermissionCalculator.RegexProcessor(luckPermsPermissions));
}
processors.add(new BukkitDefaultsProcessor(parent::isOp, defaultsProvider));
calculator = new PermissionCalculator(plugin, parent.getName(), plugin.getConfiguration().isDebugPermissionChecks(), processors);
recalculatePermissions();
}
public void invalidateCache() {
calculator.invalidateCache();
}
@Override
public boolean isOp() {
return parent.isOp();
}
@Override
public void setOp(boolean value) {
parent.setOp(value);
}
@Override
public boolean isPermissionSet(@NonNull String name) {
return calculator.getPermissionValue(name) != Tristate.UNDEFINED;
}
@Override
public boolean isPermissionSet(@NonNull Permission perm) {
return isPermissionSet(perm.getName());
}
@Override
public boolean hasPermission(@NonNull String name) {
Tristate ts = calculator.getPermissionValue(name);
if (ts != Tristate.UNDEFINED) {
return ts.asBoolean();
}
return Permission.DEFAULT_PERMISSION.getValue(isOp());
}
@Override
public boolean hasPermission(@NonNull Permission perm) {
Tristate ts = calculator.getPermissionValue(perm.getName());
if (ts != Tristate.UNDEFINED) {
return ts.asBoolean();
}
return perm.getDefault().getValue(isOp());
}
@Override
public PermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String name, boolean value) {
if (!plugin.isEnabled()) {
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
}
PermissionAttachment result = addAttachment(plugin);
result.setPermission(name, value);
recalculatePermissions();
return result;
}
@Override
public PermissionAttachment addAttachment(@NonNull Plugin plugin) {
if (!plugin.isEnabled()) {
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
}
PermissionAttachment result = new PermissionAttachment(plugin, parent);
attachments.add(result);
recalculatePermissions();
return result;
}
@Override
public PermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String name, boolean value, int ticks) {
if (!plugin.isEnabled()) {
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
}
PermissionAttachment result = addAttachment(plugin, ticks);
if (result != null) {
result.setPermission(name, value);
}
return result;
}
@Override
public PermissionAttachment addAttachment(@NonNull Plugin plugin, int ticks) {
if (!plugin.isEnabled()) {
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
}
PermissionAttachment result = addAttachment(plugin);
if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new RemoveAttachmentRunnable(result), 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;
} else {
return result;
}
}
@Override
public void removeAttachment(@NonNull PermissionAttachment attachment) {
if (attachments.contains(attachment)) {
attachments.remove(attachment);
PermissionRemovedExecutor ex = attachment.getRemovalCallback();
if (ex != null) {
ex.attachmentRemoved(attachment);
}
recalculatePermissions();
} else {
throw new IllegalArgumentException("Given attachment is not part of Permissible object " + parent);
}
}
@Override
public void recalculatePermissions() {
if (attachmentPermissions == null) {
return;
}
attachmentPermissions.clear();
for (PermissionAttachment attachment : attachments) {
calculateChildPermissions(attachment.getPermissions(), false, attachment);
}
invalidateCache();
}
@Override
public synchronized void clearPermissions() {
Set<String> perms = attachmentPermissions.keySet();
for (String name : perms) {
Bukkit.getServer().getPluginManager().unsubscribeFromPermission(name, parent);
}
Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(false, parent);
Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(true, parent);
attachmentPermissions.clear();
}
private void calculateChildPermissions(Map<String, Boolean> children, boolean invert, PermissionAttachment attachment) {
for (Map.Entry<String, Boolean> e : children.entrySet()) {
Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey());
boolean value = e.getValue() ^ invert;
String name = e.getKey().toLowerCase();
attachmentPermissions.put(name, new PermissionAttachmentInfo(parent, name, attachment, value));
Bukkit.getServer().getPluginManager().subscribeToPermission(name, parent);
if (perm != null) {
calculateChildPermissions(perm.getChildren(), !value, attachment);
}
}
}
@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();
}
}
@AllArgsConstructor
private static class AttachmentProcessor implements PermissionProcessor {
@Getter
private final Map<String, PermissionAttachmentInfo> map;
@Override
public Tristate hasPermission(String permission) {
if (map.containsKey(permission)) {
return Tristate.fromBoolean(map.get(permission).getValue());
}
return Tristate.UNDEFINED;
}
}
@AllArgsConstructor
private static class BukkitDefaultsProcessor implements PermissionProcessor {
private final Supplier<Boolean> isOp;
private final DefaultsProvider defaultsProvider;
@Override
public Tristate hasPermission(String permission) {
Tristate t = defaultsProvider.hasDefault(permission, isOp.get());
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;
}
}
}
}
@@ -22,39 +22,27 @@
package me.lucko.luckperms.users;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import me.lucko.luckperms.LPBukkitPlugin;
import me.lucko.luckperms.api.event.events.UserPermissionRefreshEvent;
import me.lucko.luckperms.api.implementation.internal.UserLink;
import org.bukkit.permissions.PermissionAttachment;
import me.lucko.luckperms.contexts.Contexts;
import me.lucko.luckperms.inject.LPPermissible;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permissible;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class BukkitUser extends User {
private static Field permissionsField = null;
public static Field getPermissionsField() {
if (permissionsField == null) {
try {
permissionsField = PermissionAttachment.class.getDeclaredField("permissions");
permissionsField.setAccessible(true);
} catch (SecurityException | NoSuchFieldException e) {
e.printStackTrace();
}
}
return permissionsField;
}
private final LPBukkitPlugin plugin;
@Getter
@Setter
private PermissionAttachmentHolder attachment = null;
private LPPermissible lpPermissible = null;
BukkitUser(UUID uuid, LPBukkitPlugin plugin) {
super(uuid, plugin);
@@ -68,24 +56,26 @@ public class BukkitUser extends User {
@SuppressWarnings("unchecked")
@Override
public void refreshPermissions() {
if (attachment == null) {
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(
getPlugin().getConfiguration().getServer(),
plugin.getUserManager().getWorldCache().get(getUuid()),
null,
plugin.getConfiguration().getIncludeGlobalPerms(),
true,
plugin.getPossiblePermissions()
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()
);
try {
// The map in the LP PermissionAttachment is a ConcurrentHashMap. We can modify and iterate over its contents async.
Map<String, Boolean> existing = attachment.getPermissions();
Map<String, Boolean> existing = lpPermissible.getLuckPermsPermissions();
boolean different = false;
if (toApply.size() != existing.size()) {
@@ -103,26 +93,30 @@ public class BukkitUser extends User {
if (!different) return;
existing.clear();
lpPermissible.invalidateCache();
existing.putAll(toApply);
/* Must be called sync, as #recalculatePermissions is an unmodified Bukkit API call that is absolutely not thread safe.
Shouldn't be too taxing on the server. This only gets called when permissions have actually changed,
which is like once per user per login, assuming their permissions don't get modified. */
plugin.doSync(() -> {
attachment.getAttachment().getPermissible().recalculatePermissions();
plugin.getApiProvider().fireEventAsync(new UserPermissionRefreshEvent(new UserLink(this)));
});
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();
}
}
@Getter
@EqualsAndHashCode
@AllArgsConstructor
public static class PermissionAttachmentHolder {
private final PermissionAttachment attachment;
private final Map<String, Boolean> permissions;
}
}
@@ -22,22 +22,19 @@
package me.lucko.luckperms.users;
import lombok.Getter;
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.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class BukkitUserManager extends UserManager {
public class BukkitUserManager extends UserManager implements ContextListener<Player> {
private final LPBukkitPlugin plugin;
@Getter
private final Map<UUID, String> worldCache = new ConcurrentHashMap<>();
public BukkitUserManager(LPBukkitPlugin plugin) {
super(plugin);
this.plugin = plugin;
@@ -47,14 +44,16 @@ public class BukkitUserManager extends UserManager {
public void preUnload(User user) {
if (user instanceof BukkitUser) {
BukkitUser u = (BukkitUser) user;
if (u.getAttachment() != null) {
Player player = plugin.getServer().getPlayer(plugin.getUuidCache().getExternalUUID(u.getUuid()));
if (player != null) {
player.removeAttachment(u.getAttachment().getAttachment());
Player player = plugin.getServer().getPlayer(plugin.getUuidCache().getExternalUUID(u.getUuid()));
if (player != null) {
if (u.getLpPermissible() != null) {
Injector.unInject(player);
u.setLpPermissible(null);
}
if (plugin.getConfiguration().isAutoOp()) {
player.setOp(false);
}
u.setAttachment(null);
}
}
}
@@ -86,4 +85,14 @@ public class BukkitUserManager extends UserManager {
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);
}
}
}
+42 -7
View File
@@ -8,9 +8,20 @@
# The name of the server, used for server specific permissions. Set to 'global' to disable.
server: global
# If users on this server should have their global permissions/groups applied.
# If users on this server should have their global permissions applied.
# If set to false, only server specific permissions will apply for users on this server
include-global: true
# If users on this server should have their global world permissions applied.
# If set to false, only world specific permissions will apply for users on this server
include-global-world: true
# If users on this server should have global (non-server specific) groups applied
apply-global-groups: true
# If users on this server should have global (non-world specific) groups applied
apply-global-world-groups: true
# If 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.
@@ -30,13 +41,12 @@ online-mode: true
# 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. This will only work for plugins that define all of their permissions to the server.
# the wildcard.
apply-wildcards: true
# If the plugin should parse regex permissions.
# If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the node, and resolve &
# apply all registered permissions matching the regex. This will only work for plugins that define all of their
# permissions to the server.
# apply all registered permissions matching the regex.
apply-regex: true
# If the plugin should complete and apply shorthand permissions.
@@ -46,6 +56,23 @@ apply-shorthand: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# If LuckPerms should print to console every time a plugin checks if a player has a permission
debug-permission-checks: false
# 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
# If set to true, any user with the permission "luckperms.autoop" will automatically be granted server operator status.
# This permission can be inherited, or set on specific servers/worlds, temporarily, etc.
# Additionally, setting this to true will force the "enable-ops" option above to false. All users will be de-opped unless
# they have the permission node, and the op/deop commands will be disabled.
#
# It is recommended that you use this option instead of assigning a single '*' permission.
auto-op: false
# If opped players should be allowed to use LuckPerms commands. Set to false to only allow users who have the permissions access to the commands
commands-allow-op: true
# 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
@@ -53,14 +80,22 @@ vault-server: global
# If global permissions should be considered when retrieving meta or player groups
vault-include-global: 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
# Which storage method the plugin should use.
# Currently supported: mysql, sqlite, h2, json, yaml, mongodb
# Fill out connection info below if you're using MySQL or MongoDB
storage-method: h2
# This block enables support for split datastores.
# Only touch this if you're sure that you know what you're doing.
# I (the author) do not endorse nor recommend the use of this feature.
split-storage:
enabled: false
methods:
@@ -78,4 +113,4 @@ data:
# 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
+2 -156
View File
@@ -12,159 +12,5 @@ commands:
description: Manage permissions
aliases: [perms, permissions, lp, p, perm]
permissions:
luckperms.*:
description: Gives access to all LuckPerms commands
children:
luckperms.sync: true
luckperms.info: true
luckperms.debug: true
luckperms.import: true
luckperms.creategroup: true
luckperms.deletegroup: true
luckperms.listgroups: true
luckperms.createtrack: true
luckperms.deletetrack: true
luckperms.listtracks: true
luckperms.user.info: true
luckperms.user.getuuid: true
luckperms.user.listnodes: true
luckperms.user.haspermission: true
luckperms.user.inheritspermission: true
luckperms.user.setpermission: true
luckperms.user.unsetpermission: true
luckperms.user.addgroup: true
luckperms.user.removegroup: true
luckperms.user.settemppermission: true
luckperms.user.unsettemppermission: true
luckperms.user.addtempgroup: true
luckperms.user.removetempgroup: true
luckperms.user.setprimarygroup: true
luckperms.user.showtracks: true
luckperms.user.promote: true
luckperms.user.demote: true
luckperms.user.showpos: true
luckperms.user.chatmeta: true
luckperms.user.addprefix: true
luckperms.user.addsuffix: true
luckperms.user.removeprefix: true
luckperms.user.removesuffix: true
luckperms.user.addtempprefix: true
luckperms.user.addtempsuffix: true
luckperms.user.removetempprefix: true
luckperms.user.removetempsuffix: true
luckperms.user.clear: true
luckperms.group.info: true
luckperms.group.listnodes: true
luckperms.group.haspermission: true
luckperms.group.inheritspermission: true
luckperms.group.setpermission: true
luckperms.group.unsetpermission: true
luckperms.group.setinherit: true
luckperms.group.unsetinherit: true
luckperms.group.settemppermission: true
luckperms.group.unsettemppermission: true
luckperms.group.settempinherit: true
luckperms.group.unsettempinherit: true
luckperms.group.showtracks: true
luckperms.group.chatmeta: true
luckperms.group.addprefix: true
luckperms.group.addsuffix: true
luckperms.group.removeprefix: true
luckperms.group.removesuffix: true
luckperms.group.addtempprefix: true
luckperms.group.addtempsuffix: true
luckperms.group.removetempprefix: true
luckperms.group.removetempsuffix: true
luckperms.group.clear: true
luckperms.group.rename: true
luckperms.track.info: true
luckperms.track.append: true
luckperms.track.insert: true
luckperms.track.remove: true
luckperms.track.clear: true
luckperms.track.rename: true
luckperms.log.export: true
luckperms.log.userhistory: true
luckperms.log.grouphistory: true
luckperms.log.trackhistory: true
luckperms.log.notify: true
luckperms.log.recent: true
luckperms.log.search: true
luckperms.user.*:
description: Gives access to all LuckPerms user commands
children:
luckperms.user.info: true
luckperms.user.getuuid: true
luckperms.user.listnodes: true
luckperms.user.haspermission: true
luckperms.user.inheritspermission: true
luckperms.user.setpermission: true
luckperms.user.unsetpermission: true
luckperms.user.addgroup: true
luckperms.user.removegroup: true
luckperms.user.settemppermission: true
luckperms.user.unsettemppermission: true
luckperms.user.addtempgroup: true
luckperms.user.removetempgroup: true
luckperms.user.setprimarygroup: true
luckperms.user.showtracks: true
luckperms.user.promote: true
luckperms.user.demote: true
luckperms.user.showpos: true
luckperms.user.chatmeta: true
luckperms.user.addprefix: true
luckperms.user.addsuffix: true
luckperms.user.removeprefix: true
luckperms.user.removesuffix: true
luckperms.user.addtempprefix: true
luckperms.user.addtempsuffix: true
luckperms.user.removetempprefix: true
luckperms.user.removetempsuffix: true
luckperms.user.clear: true
luckperms.group.*:
description: Gives access to all LuckPerms group commands
children:
luckperms.group.info: true
luckperms.group.listnodes: true
luckperms.group.haspermission: true
luckperms.group.inheritspermission: true
luckperms.group.setpermission: true
luckperms.group.unsetpermission: true
luckperms.group.setinherit: true
luckperms.group.unsetinherit: true
luckperms.group.settemppermission: true
luckperms.group.unsettemppermission: true
luckperms.group.settempinherit: true
luckperms.group.unsettempinherit: true
luckperms.group.showtracks: true
luckperms.group.chatmeta: true
luckperms.group.addprefix: true
luckperms.group.addsuffix: true
luckperms.group.removeprefix: true
luckperms.group.removesuffix: true
luckperms.group.addtempprefix: true
luckperms.group.addtempsuffix: true
luckperms.group.removetempprefix: true
luckperms.group.removetempsuffix: true
luckperms.group.clear: true
luckperms.group.rename: true
luckperms.track.*:
description: Gives access to all LuckPerms track commands
children:
luckperms.track.info: true
luckperms.track.append: true
luckperms.track.insert: true
luckperms.track.remove: true
luckperms.track.clear: true
luckperms.track.rename: true
luckperms.log.*:
description: Gives access to all LuckPerms log commands
children:
luckperms.log.export: true
luckperms.log.userhistory: true
luckperms.log.grouphistory: true
luckperms.log.trackhistory: true
luckperms.log.notify: true
luckperms.log.recent: true
luckperms.log.search: true
# Permissions are registered programmatically instead of here.
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.7-SNAPSHOT</version>
<version>2.10-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -22,8 +22,12 @@
package me.lucko.luckperms;
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 net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
@@ -40,11 +44,16 @@ class BungeeCommand extends Command implements TabExecutor {
@Override
public void execute(CommandSender sender, String[] args) {
manager.onCommand(BungeeSenderFactory.get().wrap(sender), "bperms", Arrays.asList(args), Callback.empty());
manager.onCommand(
BungeeSenderFactory.get(manager.getPlugin()).wrap(sender),
"bperms",
Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(Joiner.on(' ').join(args))),
Callback.empty()
);
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
return manager.onTabComplete(BungeeSenderFactory.get().wrap(sender), Arrays.asList(args));
return manager.onTabComplete(BungeeSenderFactory.get(manager.getPlugin()).wrap(sender), Arrays.asList(args));
}
}
@@ -22,7 +22,7 @@
package me.lucko.luckperms;
import me.lucko.luckperms.core.LPConfiguration;
import me.lucko.luckperms.config.AbstractConfiguration;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
@@ -31,8 +31,10 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
class BungeeConfig extends LPConfiguration<LPBungeePlugin> {
class BungeeConfig extends AbstractConfiguration<LPBungeePlugin> {
private Configuration configuration;
BungeeConfig(LPBungeePlugin plugin) {
@@ -62,11 +64,6 @@ class BungeeConfig extends LPConfiguration<LPBungeePlugin> {
}
}
@Override
protected void set(String path, Object value) {
configuration.set(path, value);
}
@Override
protected String getString(String path, String def) {
return configuration.getString(path, def);
@@ -81,4 +78,19 @@ class BungeeConfig extends LPConfiguration<LPBungeePlugin> {
protected boolean getBoolean(String path, boolean def) {
return configuration.getBoolean(path, def);
}
@Override
protected Map<String, String> getMap(String path, Map<String, String> def) {
Map<String, String> map = new HashMap<>();
Configuration section = configuration.getSection(path);
if (section == null) {
return def;
}
for (String key : section.getKeys()) {
map.put(key, section.getString(key));
}
return map;
}
}
@@ -29,12 +29,13 @@ import me.lucko.luckperms.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;
import net.md_5.bungee.api.event.*;
import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.api.event.PermissionCheckEvent;
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 java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -51,22 +52,18 @@ public class BungeeListener extends AbstractListener implements Listener {
@EventHandler
public void onPlayerPermissionCheck(PermissionCheckEvent e) {
if (!(e.getSender() instanceof ProxiedPlayer)) {
e.setHasPermission(true);
return;
}
final ProxiedPlayer player = ((ProxiedPlayer) e.getSender());
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
if (user == null) return;
final String server = player.getServer() == null ? null : (player.getServer().getInfo() == null ? null : player.getServer().getInfo().getName());
Map<String, Boolean> local = user.getLocalPermissions(plugin.getConfiguration().getServer(), server, null, Collections.singletonList(e.getPermission()));
for (Map.Entry<String, Boolean> en : local.entrySet()) {
if (en.getKey().equalsIgnoreCase(e.getPermission())) {
e.setHasPermission(en.getValue());
return;
}
BungeePlayerCache playerCache = plugin.getPlayerCache().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
if (playerCache == null) {
return;
}
e.setHasPermission(playerCache.getPermissionValue(e.getPermission()));
}
@EventHandler
@@ -108,22 +105,20 @@ public class BungeeListener extends AbstractListener implements Listener {
@EventHandler
public void onPlayerPostLogin(PostLoginEvent e) {
final ProxiedPlayer player = e.getPlayer();
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
final UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
final User user = plugin.getUserManager().get(internal);
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());
}
@EventHandler
public void onPlayerServerSwitch(ServerSwitchEvent e) {
refreshPlayer(e.getPlayer().getUniqueId());
}
}
@@ -0,0 +1,61 @@
/*
* 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.calculators.PermissionCalculator;
import me.lucko.luckperms.calculators.PermissionProcessor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class BungeePlayerCache {
private final PermissionCalculator calculator;
@Getter
private final Map<String, Boolean> permissions = new ConcurrentHashMap<>();
public BungeePlayerCache(LuckPermsPlugin plugin, String name) {
List<PermissionProcessor> processors = new ArrayList<>(3);
processors.add(new PermissionCalculator.MapProcessor(permissions));
if (plugin.getConfiguration().isApplyingWildcards()) {
processors.add(new PermissionCalculator.WildcardProcessor(permissions));
}
if (plugin.getConfiguration().isApplyingRegex()) {
processors.add(new PermissionCalculator.RegexProcessor(permissions));
}
calculator = new PermissionCalculator(plugin, name, plugin.getConfiguration().isDebugPermissionChecks(), processors);
}
public void invalidateCache() {
calculator.invalidateCache();
}
public boolean getPermissionValue(String permission) {
return calculator.getPermissionValue(permission).asBoolean();
}
}
@@ -22,8 +22,6 @@
package me.lucko.luckperms;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import me.lucko.luckperms.commands.SenderFactory;
import me.lucko.luckperms.constants.Constants;
import net.md_5.bungee.api.CommandSender;
@@ -32,12 +30,16 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.UUID;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BungeeSenderFactory extends SenderFactory<CommandSender> {
private static BungeeSenderFactory instance = null;
public static BungeeSenderFactory get() {
if (instance == null){
instance = new BungeeSenderFactory();
private BungeeSenderFactory(LuckPermsPlugin plugin) {
super(plugin);
}
public static synchronized BungeeSenderFactory get(LuckPermsPlugin plugin) {
if (instance == null) {
instance = new BungeeSenderFactory(plugin);
}
return instance;
}
@@ -29,8 +29,12 @@ 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.core.LPConfiguration;
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;
@@ -40,25 +44,23 @@ 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.users.UserManager;
import me.lucko.luckperms.utils.LocaleManager;
import me.lucko.luckperms.utils.LogFactory;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
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 final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private LPConfiguration configuration;
private UserManager userManager;
private BungeeUserManager userManager;
private GroupManager groupManager;
private TrackManager trackManager;
private Datastore datastore;
@@ -67,6 +69,8 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
private Logger log;
private Importer importer;
private ConsecutiveExecutor consecutiveExecutor;
private LocaleManager localeManager;
private ContextManager<ProxiedPlayer> contextManager;
@Override
public void onEnable() {
@@ -75,6 +79,17 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
getLog().info("Loading configuration...");
configuration = new BungeeConfig(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();
}
}
// register events
getProxy().getPluginManager().registerListener(this, new BungeeListener(this));
@@ -89,20 +104,27 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
datastore = StorageFactory.getDatastore(this, "h2");
getLog().info("Loading internal permission managers...");
uuidCache = new UuidCache(getConfiguration().getOnlineMode());
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
userManager = new BungeeUserManager(this);
groupManager = new GroupManager(this);
trackManager = new TrackManager();
importer = new Importer(commandManager);
consecutiveExecutor = new ConsecutiveExecutor(commandManager);
contextManager = new ContextManager<>();
BackendServerCalculator serverCalculator = new BackendServerCalculator();
getProxy().getPluginManager().registerListener(this, serverCalculator);
contextManager.registerCalculator(serverCalculator);
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
contextManager.registerListener(userManager);
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(), 50L, 50L, TimeUnit.MILLISECONDS);
getProxy().getScheduler().schedule(this, BungeeSenderFactory.get(this), 50L, 50L, TimeUnit.MILLISECONDS);
getProxy().getScheduler().schedule(this, new ExpireTemporaryTask(this), 3L, 3L, TimeUnit.SECONDS);
getProxy().getScheduler().schedule(this, consecutiveExecutor, 1L, 1L, TimeUnit.SECONDS);
@@ -161,13 +183,16 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
}
@Override
public List<Sender> getSenders() {
return getProxy().getPlayers().stream().map(p -> BungeeSenderFactory.get().wrap(p)).collect(Collectors.toList());
public List<Sender> getNotifyListeners() {
return getProxy().getPlayers().stream()
.map(p -> BungeeSenderFactory.get(this).wrap(p, Collections.singleton(Permission.LOG_NOTIFY)))
.filter(Permission.LOG_NOTIFY::isAuthorized)
.collect(Collectors.toList());
}
@Override
public Sender getConsoleSender() {
return BungeeSenderFactory.get().wrap(getProxy().getConsole());
return BungeeSenderFactory.get(this).wrap(getProxy().getConsole());
}
@Override
@@ -0,0 +1,66 @@
/*
* 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.contexts;
import com.google.common.collect.Maps;
import me.lucko.luckperms.api.context.ContextCalculator;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerSwitchEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import java.util.Map;
public class BackendServerCalculator extends ContextCalculator<ProxiedPlayer> implements Listener {
private static final String WORLD_KEY = "world";
@Override
public Map<String, String> giveApplicableContext(ProxiedPlayer subject, Map<String, String> accumulator) {
String server = getServer(subject);
if (server != null) {
accumulator.put(WORLD_KEY, server);
}
return accumulator;
}
@Override
public boolean isContextApplicable(ProxiedPlayer subject, Map.Entry<String, String> context) {
if (!context.getKey().equals(WORLD_KEY)) {
return false;
}
String server = getServer(subject);
return server != null && server.equals(context.getValue());
}
@EventHandler
public void onPlayerServerSwitch(ServerSwitchEvent e) {
pushUpdate(e.getPlayer(), Maps.immutableEntry("null", "null"), Maps.immutableEntry(WORLD_KEY, getServer(e.getPlayer())));
}
private static String getServer(ProxiedPlayer player) {
return player.getServer() == null ? null : (player.getServer().getInfo() == null ? null : player.getServer().getInfo().getName());
}
}
@@ -22,21 +22,77 @@
package me.lucko.luckperms.users;
import me.lucko.luckperms.BungeePlayerCache;
import me.lucko.luckperms.LPBungeePlugin;
import me.lucko.luckperms.api.event.events.UserPermissionRefreshEvent;
import me.lucko.luckperms.api.implementation.internal.UserLink;
import me.lucko.luckperms.contexts.Contexts;
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 void refreshPermissions() {
// Do nothing. Permissions are applied when needed in a listener.
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()
);
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)));
}
}
@@ -23,10 +23,13 @@
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 {
public class BungeeUserManager extends UserManager implements ContextListener<ProxiedPlayer> {
private final LPBungeePlugin plugin;
public BungeeUserManager(LPBungeePlugin plugin) {
@@ -57,4 +60,14 @@ public class BungeeUserManager extends UserManager {
.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);
}
}
}
+29 -6
View File
@@ -8,9 +8,20 @@
# The name of the server, used for server specific permissions. Set to 'global' to disable.
server: bungee
# If users on this server should have their global permissions/groups applied.
# If users on this server should have their global permissions applied.
# If set to false, only server specific permissions will apply for users on this server
include-global: false
# If users on this server should have their global world permissions applied.
# If set to false, only world specific permissions will apply for users on this server
include-global-world: true
# If users on this server should have global (non-server specific) groups applied
apply-global-groups: true
# If users on this server should have global (non-world specific) groups applied
apply-global-world-groups: true
# If 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.
@@ -30,13 +41,12 @@ online-mode: true
# 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. This will only work for plugins that define all of their permissions to the server.
# the wildcard.
apply-wildcards: true
# If the plugin should parse regex permissions.
# If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the node, and resolve &
# apply all registered permissions matching the regex. This will only work for plugins that define all of their
# permissions to the server.
# apply all registered permissions matching the regex.
apply-regex: true
# If the plugin should complete and apply shorthand permissions.
@@ -46,14 +56,27 @@ apply-shorthand: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# If LuckPerms should print to console every time a plugin checks if a player has a permission
debug-permission-checks: false
# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in this list, the value assigned
# will be sent forward for permission calculation instead.
# 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
# Which storage method the plugin should use.
# Currently supported: mysql, sqlite, h2, json, yaml, mongodb
# Fill out connection info below if you're using MySQL or MongoDB
storage-method: h2
# This block enables support for split datastores.
# Only touch this if you're sure that you know what you're doing.
# I (the author) do not endorse nor recommend the use of this feature.
split-storage:
enabled: false
methods:
+5 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.7-SNAPSHOT</version>
<version>2.10-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -112,6 +112,10 @@
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
<exclusion>
<groupId>net.gravitydevelopment.updater</groupId>
<artifactId>updater</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
@@ -27,14 +27,16 @@ 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.core.LPConfiguration;
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;
@@ -60,6 +62,8 @@ public interface LuckPermsPlugin {
ApiProvider getApiProvider();
Importer getImporter();
ConsecutiveExecutor getConsecutiveExecutor();
LocaleManager getLocaleManager();
ContextManager getContextManager();
/**
* @return the version of the plugin
@@ -103,7 +107,7 @@ public interface LuckPermsPlugin {
/**
* @return a {@link List} of senders online on the platform
*/
List<Sender> getSenders();
List<Sender> getNotifyListeners();
/**
* @return the console sender of the instance
@@ -27,6 +27,8 @@ import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.*;
import me.lucko.luckperms.api.context.ContextListener;
import me.lucko.luckperms.api.context.IContextCalculator;
import me.lucko.luckperms.api.event.LPEvent;
import me.lucko.luckperms.api.event.LPListener;
import me.lucko.luckperms.api.implementation.internal.*;
@@ -67,7 +69,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public double getApiVersion() {
return 2.6;
return 2.10;
}
@Override
@@ -208,6 +210,18 @@ public class ApiProvider implements LuckPermsApi {
@Override
public Node.Builder buildNode(@NonNull String permission) throws IllegalArgumentException {
return new me.lucko.luckperms.utils.Node.Builder(checkNode(permission));
return new me.lucko.luckperms.core.Node.Builder(checkNode(permission));
}
@SuppressWarnings("unchecked")
@Override
public void registerContextCalculator(IContextCalculator<?> contextCalculator) {
plugin.getContextManager().registerCalculator(contextCalculator);
}
@SuppressWarnings("unchecked")
@Override
public void registerContextListener(ContextListener<?> contextListener) {
plugin.getContextManager().registerListener(contextListener);
}
}
@@ -30,11 +30,11 @@ import me.lucko.luckperms.api.data.MySQLConfiguration;
import java.util.Map;
/**
* Provides a link between {@link LPConfiguration} and {@link me.lucko.luckperms.core.LPConfiguration}
* Provides a link between {@link LPConfiguration} and {@link me.lucko.luckperms.config.LPConfiguration}
*/
@AllArgsConstructor
public class LPConfigurationLink implements LPConfiguration {
private final me.lucko.luckperms.core.LPConfiguration master;
private final me.lucko.luckperms.config.LPConfiguration master;
@Override
public String getServer() {
@@ -58,32 +58,67 @@ public class LPConfigurationLink implements LPConfiguration {
@Override
public boolean getIncludeGlobalPerms() {
return master.getIncludeGlobalPerms();
return master.isIncludingGlobalPerms();
}
@Override
public boolean getIncludeGlobalWorldPerms() {
return master.isIncludingGlobalWorldPerms();
}
@Override
public boolean getApplyGlobalGroups() {
return master.isApplyingGlobalGroups();
}
@Override
public boolean getApplyGlobalWorldGroups() {
return master.isApplyingGlobalWorldGroups();
}
@Override
public boolean getOnlineMode() {
return master.getOnlineMode();
return master.isOnlineMode();
}
@Override
public boolean getApplyWildcards() {
return master.getApplyWildcards();
return master.isApplyingWildcards();
}
@Override
public boolean getApplyRegex() {
return master.getApplyRegex();
return master.isApplyingRegex();
}
@Override
public boolean getApplyShorthand() {
return master.getApplyShorthand();
return master.isApplyingShorthand();
}
@Override
public boolean getLogNotify() {
return master.getLogNotify();
return master.isLogNotify();
}
@Override
public boolean getDebugPermissionChecks() {
return master.isDebugPermissionChecks();
}
@Override
public boolean getEnableOps() {
return master.isOpsEnabled();
}
@Override
public boolean getCommandsAllowOp() {
return master.isCommandsAllowOp();
}
@Override
public boolean getAutoOp() {
return master.isAutoOp();
}
@Override
@@ -93,7 +128,7 @@ public class LPConfigurationLink implements LPConfiguration {
@Override
public boolean getVaultIncludeGlobal() {
return master.getVaultIncludeGlobal();
return master.isVaultIncludingGlobal();
}
@SuppressWarnings("deprecation")
@@ -114,10 +149,9 @@ public class LPConfigurationLink implements LPConfiguration {
@Override
public boolean getSplitStorage() {
return master.getSplitStorage();
return master.isSplitStorage();
}
@SuppressWarnings("unchecked")
@Override
public Map<String, String> getSplitStorageOptions() {
return master.getSplitStorageOptions();
@@ -27,6 +27,7 @@ import lombok.NonNull;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.PermissionHolder;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.contexts.Contexts;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
@@ -52,7 +53,7 @@ public class PermissionHolderLink implements PermissionHolder {
@Override
public SortedSet<Node> getPermissions() {
return Collections.unmodifiableSortedSet(master.getPermissions());
return Collections.unmodifiableSortedSet(master.getPermissions(false));
}
@Override
@@ -67,7 +68,7 @@ public class PermissionHolderLink implements PermissionHolder {
@Override
public Set<Node> getAllNodes() {
return Collections.unmodifiableSet(master.getAllNodes(null));
return Collections.unmodifiableSet(master.getAllNodes(Collections.emptyList(), Contexts.allowAll()));
}
@Override
@@ -252,7 +253,16 @@ public class PermissionHolderLink implements PermissionHolder {
@Override
public Map<String, Boolean> getPermissions(String server, String world, Map<String, String> extraContext, boolean includeGlobal, List<String> possibleNodes, boolean applyGroups) {
return master.exportNodes(server, world, extraContext, includeGlobal, applyGroups, possibleNodes);
if (extraContext == null) {
extraContext = new HashMap<>();
}
if (server != null && !server.equals("")) {
extraContext.put("server", server);
}
if (world != null && !world.equals("")) {
extraContext.put("world", world);
}
return master.exportNodes(new Contexts(extraContext, includeGlobal, includeGlobal, applyGroups, true, true), possibleNodes);
}
@Override
@@ -0,0 +1,165 @@
/*
* 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.calculators;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.constants.Patterns;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
/**
* Calculates and caches permissions
*/
@RequiredArgsConstructor
public class PermissionCalculator {
private final LuckPermsPlugin plugin;
private final String objectName;
private final boolean debug;
private final List<PermissionProcessor> processors;
private final Map<String, Tristate> cache = new ConcurrentHashMap<>();
public void invalidateCache() {
cache.clear();
}
public Tristate getPermissionValue(String permission) {
if (debug) {
plugin.getLog().info("Checking if " + objectName + " has permission: " + permission);
}
permission = permission.toLowerCase();
return cache.computeIfAbsent(permission, this::lookupPermissionValue);
}
private Tristate lookupPermissionValue(String permission) {
for (PermissionProcessor processor : processors) {
Tristate v = processor.hasPermission(permission);
if (v == Tristate.UNDEFINED) {
continue;
}
return v;
}
return Tristate.UNDEFINED;
}
@AllArgsConstructor
public static class MapProcessor implements PermissionProcessor {
@Getter
private final Map<String, Boolean> map;
@Override
public Tristate hasPermission(String permission) {
if (map.containsKey(permission)) {
return Tristate.fromBoolean(map.get(permission));
}
return Tristate.UNDEFINED;
}
}
@AllArgsConstructor
public static class RegexProcessor implements PermissionProcessor {
@Getter
private final Map<String, Boolean> map;
@Override
public Tristate hasPermission(String permission) {
for (Map.Entry<String, Boolean> e : map.entrySet()) {
if (e.getKey().toLowerCase().startsWith("r=")) {
Pattern p = Patterns.compile(e.getKey().substring(2));
if (p == null) {
continue;
}
if (p.matcher(permission).matches()) {
return Tristate.fromBoolean(e.getValue());
}
}
}
return Tristate.UNDEFINED;
}
}
@AllArgsConstructor
public static class WildcardProcessor implements PermissionProcessor {
@Getter
private final Map<String, Boolean> map;
@Override
public Tristate hasPermission(String permission) {
String node = permission;
while (node.contains(".")) {
int endIndex = node.lastIndexOf('.');
if (endIndex == -1) {
break;
}
node = node.substring(0, endIndex);
if (!isEmpty(node)) {
if (map.containsKey(node + ".*")) {
return Tristate.fromBoolean(map.get(node + ".*"));
}
}
}
if (map.containsKey("'*'")) {
return Tristate.fromBoolean(map.get("'*'"));
}
if (map.containsKey("*")) {
return Tristate.fromBoolean(map.get("*"));
}
return Tristate.UNDEFINED;
}
private static boolean isEmpty(String s) {
if (s.equals("")) {
return true;
}
char[] chars = s.toCharArray();
for (char c : chars) {
if (c != '.') {
return false;
}
}
return true;
}
}
}
@@ -0,0 +1,31 @@
/*
* 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.calculators;
import me.lucko.luckperms.api.Tristate;
public interface PermissionProcessor {
Tristate hasPermission(String permission);
}
@@ -39,7 +39,6 @@ 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.constants.Message;
import java.util.ArrayList;
import java.util.Collections;
@@ -49,6 +48,7 @@ import java.util.stream.Collectors;
@AllArgsConstructor
public class CommandManager {
@Getter
private final LuckPermsPlugin plugin;
@Getter
@@ -61,6 +61,7 @@ public class CommandManager {
.add(new InfoCommand())
.add(new DebugCommand())
.add(new ImportCommand())
.add(new ExportCommand())
.add(new QueueCommand())
.add(new MigrationMainCommand())
.add(new CreateGroup())
@@ -176,8 +177,7 @@ public class CommandManager {
}
private void sendCommandUsage(Sender sender, String label) {
Message.INFO_BRIEF.send(sender, plugin.getVersion());
Util.sendPluginMessage(sender, "&6Running &bLuckPerms v" + plugin.getVersion() + "&6.");
mainCommands.stream()
.filter(c -> c.isAuthorized(sender))
.forEach(c -> Util.sendPluginMessage(sender, "&e-> &d" + String.format(c.getUsage(), label)));
@@ -98,7 +98,7 @@ public abstract class MainCommand<T> {
}
if (sub.getIsArgumentInvalid().test(strippedArgs.size())) {
sub.sendUsage(sender, label);
sub.sendUsage(sender);
return CommandResult.INVALID_ARGS;
}
@@ -146,10 +146,10 @@ public abstract class MainCommand<T> {
.collect(Collectors.toList());
if (subs.size() > 0) {
Util.sendPluginMessage(sender, "&e" + getName() + " Sub Commands:");
Util.sendPluginMessage(sender, "&e" + getName() + " Sub Commands: &7(" + String.format(getUsage(), label) + " ...)");
for (SubCommand s : subs) {
s.sendUsage(sender, label);
s.sendUsage(sender);
}
} else {
@@ -22,6 +22,7 @@
package me.lucko.luckperms.commands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.constants.Permission;
import java.util.UUID;
@@ -31,6 +32,7 @@ import java.util.UUID;
*/
public interface Sender {
LuckPermsPlugin getPlatform();
String getName();
UUID getUuid();
void sendMessage(String s);
@@ -24,6 +24,9 @@ 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;
@@ -35,7 +38,9 @@ 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;
@@ -46,39 +51,11 @@ public abstract class SenderFactory<T> implements Runnable {
protected abstract boolean hasPermission(T t, String node);
public final Sender wrap(T t) {
return new Sender() {
final WeakReference<T> tRef = new WeakReference<>(t);
return new SenderImp(plugin, t, null);
}
// Cache these permissions, so they can be accessed async
final Map<Permission, Boolean> perms = ImmutableMap.copyOf(Arrays.stream(Permission.values())
.collect(Collectors.toMap(p -> p, p -> factory.hasPermission(t, p.getNode()))));
@Getter
final String name = factory.getName(t);
@Getter
final UUID uuid = factory.getUuid(t);
@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 perms.get(permission);
}
};
public final Sender wrap(T t, Set<Permission> toCheck) {
return new SenderImp(plugin, t, toCheck);
}
@Override
@@ -97,4 +74,59 @@ public abstract class SenderFactory<T> implements Runnable {
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);
}
}
}
@@ -22,7 +22,6 @@
package me.lucko.luckperms.commands;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.constants.Message;
@@ -42,7 +41,6 @@ import java.util.stream.Collectors;
* Abstract SubCommand class
*/
@Getter
@AllArgsConstructor
public abstract class SubCommand<T> {
/**
@@ -70,6 +68,14 @@ public abstract class SubCommand<T> {
*/
private final Predicate<? super Integer> isArgumentInvalid;
public SubCommand(String name, String description, String usage, Permission permission, Predicate<? super Integer> isArgumentInvalid) {
this.name = name;
this.description = description;
this.permission = permission;
this.isArgumentInvalid = isArgumentInvalid;
this.usage = usage.replace("<", "&8<&7").replace(">", "&8>&7").replace("[", "&8[&7").replace("]", "&8]&7");
}
/**
* Called when this sub command is ran
* @param plugin a link to the main plugin instance
@@ -95,10 +101,9 @@ public abstract class SubCommand<T> {
/**
* Send the command usage to a sender
* @param sender the sender to send the usage to
* @param label the command label used
*/
public void sendUsage(Sender sender, String label) {
Util.sendPluginMessage(sender, "&e-> &d" + String.format(getUsage(), label));
public void sendUsage(Sender sender) {
Util.sendPluginMessage(sender, "&e-> &6" + getName() + (usage.isEmpty() ? "" : "&e - &7" + getUsage()));
}
/**
@@ -37,6 +37,22 @@ public class Util {
sender.sendMessage(color(Message.PREFIX + message));
}
public static List<String> stripQuotes(List<String> input) {
input = new ArrayList<>(input);
ListIterator<String> iterator = input.listIterator();
while (iterator.hasNext()) {
String value = iterator.next();
if (!(value.length() >= 3)) {
continue;
}
if (value.charAt(0) == '"' && value.charAt(value.length() - 1) == '"') {
iterator.set(value.substring(1, value.length() - 1));
}
}
return input;
}
public static String color(String s) {
return translateAlternateColorCodes('&', s);
}
@@ -165,6 +181,64 @@ public class Util {
return sb.toString();
}
public static String permGroupsToString(SortedSet<Node> nodes) {
StringBuilder sb = new StringBuilder();
for (Node node : nodes) {
if (!node.isGroupNode()) {
continue;
}
if (node.isTemporary()) {
continue;
}
sb.append("&a-> &b").append(node.getGroupName());
if (node.isServerSpecific()) {
sb.append(" &7(&f").append(node.getServer().get()).append("&7)");
}
if (node.isWorldSpecific()) {
sb.append(" &7(&f").append(node.getWorld().get()).append("&7)");
}
sb.append("\n");
}
if (sb.length() == 0) {
return "&6None";
}
return sb.toString();
}
public static String tempGroupsToString(SortedSet<Node> nodes) {
StringBuilder sb = new StringBuilder();
for (Node node : nodes) {
if (!node.isGroupNode()) {
continue;
}
if (!node.isTemporary()) {
continue;
}
sb.append("&a-> &b").append(node.getGroupName());
if (node.isServerSpecific()) {
sb.append(" &7(&f").append(node.getServer().get()).append("&7)");
}
if (node.isWorldSpecific()) {
sb.append(" &7(&f").append(node.getWorld().get()).append("&7)");
}
sb.append("&6 - expires in ").append(DateUtil.formatDateDiff(node.getExpiryUnixTime())).append("\n");
}
if (sb.length() == 0) {
return "&6None";
}
return sb.toString();
}
public static UUID parseUuid(String s) {
try {
return UUID.fromString(s);
@@ -71,7 +71,7 @@ public class DeleteGroup extends SingleMainCommand {
return CommandResult.FAILURE;
}
Message.DELETE_SUCCESS.send(sender, groupName);
Message.DELETE_SUCCESS.send(sender, group.getDisplayName());
LogEntry.build().actor(sender).actedName(groupName).type('G').action("delete").build().submit(plugin, sender);
plugin.runUpdateTask();
return CommandResult.SUCCESS;
@@ -39,6 +39,7 @@ public class GroupMainCommand extends MainCommand<Group> {
super("Group", "/%s group <group>", 2, ImmutableList.<SubCommand<Group>>builder()
.add(new GroupInfo())
.add(new GroupListNodes())
.add(new GroupListParents())
.add(new GroupHasPerm())
.add(new GroupInheritsPerm())
.add(new GroupSetPermission())
@@ -59,6 +60,7 @@ public class GroupMainCommand extends MainCommand<Group> {
.add(new GroupAddTempSuffix())
.add(new GroupRemoveTempPrefix())
.add(new GroupRemoveTempSuffix())
.add(new GroupBulkChange())
.add(new GroupClear())
.add(new GroupRename())
.build()
@@ -29,9 +29,11 @@ import me.lucko.luckperms.commands.SingleMainCommand;
import me.lucko.luckperms.commands.Util;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.groups.Group;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class ListGroups extends SingleMainCommand {
public ListGroups() {
@@ -45,7 +47,13 @@ public class ListGroups extends SingleMainCommand {
return CommandResult.LOADING_ERROR;
}
Message.GROUPS_LIST.send(sender, Util.listToCommaSep(new ArrayList<>(plugin.getGroupManager().getAll().keySet())));
Message.GROUPS_LIST.send(
sender,
Util.listToCommaSep(new ArrayList<>(plugin.getGroupManager().getAll().values().stream()
.map(Group::getDisplayName)
.collect(Collectors.toList()))
)
);
return CommandResult.SUCCESS;
}
}
@@ -38,7 +38,7 @@ import java.util.List;
public class GroupAddPrefix extends SubCommand<Group> {
public GroupAddPrefix() {
super("addprefix", "Adds a prefix to the group", "/%s group <group> addprefix <priority> <prefix> [server] [world]",
super("addprefix", "Adds a prefix to the group", "<priority> <prefix> [server] [world]",
Permission.GROUP_ADDPREFIX, Predicate.notInRange(2, 4));
}
@@ -65,14 +65,14 @@ public class GroupAddPrefix extends SubCommand<Group> {
if (args.size() == 3) {
group.setPermission(node, true, server);
Message.ADDPREFIX_SERVER_SUCCESS.send(sender, group.getName(), prefix, priority, 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.getName(), prefix, priority, 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);
@@ -80,7 +80,7 @@ public class GroupAddPrefix extends SubCommand<Group> {
} else {
group.setPermission(node, true);
Message.ADDPREFIX_SUCCESS.send(sender, group.getName(), prefix, priority);
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);
@@ -89,7 +89,7 @@ public class GroupAddPrefix extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_PREFIX.send(sender, group.getName());
Message.ALREADY_HAS_PREFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -38,7 +38,7 @@ import java.util.List;
public class GroupAddSuffix extends SubCommand<Group> {
public GroupAddSuffix() {
super("addsuffix", "Adds a suffix to the group", "/%s group <group> addsuffix <priority> <suffix> [server] [world]",
super("addsuffix", "Adds a suffix to the group", "<priority> <suffix> [server] [world]",
Permission.GROUP_ADDSUFFIX, Predicate.notInRange(2, 4));
}
@@ -65,14 +65,14 @@ public class GroupAddSuffix extends SubCommand<Group> {
if (args.size() == 3) {
group.setPermission(node, true, server);
Message.ADDSUFFIX_SERVER_SUCCESS.send(sender, group.getName(), suffix, priority, 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.getName(), suffix, priority, 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);
@@ -80,7 +80,7 @@ public class GroupAddSuffix extends SubCommand<Group> {
} else {
group.setPermission(node, true);
Message.ADDSUFFIX_SUCCESS.send(sender, group.getName(), suffix, priority);
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);
@@ -89,7 +89,7 @@ public class GroupAddSuffix extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_SUFFIX.send(sender, group.getName());
Message.ALREADY_HAS_SUFFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -39,7 +39,7 @@ import java.util.List;
public class GroupAddTempPrefix extends SubCommand<Group> {
public GroupAddTempPrefix() {
super("addtempprefix", "Adds a prefix to the group temporarily", "/%s group <group> addtempprefix <priority> <prefix> <duration> [server] [world]",
super("addtempprefix", "Adds a prefix to the group temporarily", "<priority> <prefix> <duration> [server] [world]",
Permission.GROUP_ADD_TEMP_PREFIX, Predicate.notInRange(3, 5));
}
@@ -83,14 +83,14 @@ public class GroupAddTempPrefix extends SubCommand<Group> {
if (args.size() == 4) {
group.setPermission(node, true, server, duration);
Message.ADD_TEMP_PREFIX_SERVER_SUCCESS.send(sender, group.getName(), prefix, priority, server, DateUtil.formatDateDiff(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.getName(), prefix, priority, server, world, DateUtil.formatDateDiff(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);
@@ -98,7 +98,7 @@ public class GroupAddTempPrefix extends SubCommand<Group> {
} else {
group.setPermission(node, true, duration);
Message.ADD_TEMP_PREFIX_SUCCESS.send(sender, group.getName(), prefix, priority, DateUtil.formatDateDiff(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);
@@ -107,7 +107,7 @@ public class GroupAddTempPrefix extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_PREFIX.send(sender, group.getName());
Message.ALREADY_HAS_PREFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -39,7 +39,7 @@ import java.util.List;
public class GroupAddTempSuffix extends SubCommand<Group> {
public GroupAddTempSuffix() {
super("addtempsuffix", "Adds a suffix to the group temporarily", "/%s group <group> addtempsuffix <priority> <suffix> <duration> [server] [world]",
super("addtempsuffix", "Adds a suffix to the group temporarily", "<priority> <suffix> <duration> [server] [world]",
Permission.GROUP_ADD_TEMP_SUFFIX, Predicate.notInRange(3, 5));
}
@@ -83,14 +83,14 @@ public class GroupAddTempSuffix extends SubCommand<Group> {
if (args.size() == 4) {
group.setPermission(node, true, server, duration);
Message.ADD_TEMP_SUFFIX_SERVER_SUCCESS.send(sender, group.getName(), suffix, priority, server, DateUtil.formatDateDiff(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.getName(), suffix, priority, server, world, DateUtil.formatDateDiff(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);
@@ -98,7 +98,7 @@ public class GroupAddTempSuffix extends SubCommand<Group> {
} else {
group.setPermission(node, true, duration);
Message.ADD_TEMP_SUFFIX_SUCCESS.send(sender, group.getName(), suffix, priority, DateUtil.formatDateDiff(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);
@@ -107,7 +107,7 @@ public class GroupAddTempSuffix extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_SUFFIX.send(sender, group.getName());
Message.ALREADY_HAS_SUFFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.commands.group.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Node;
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.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.groups.Group;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class GroupBulkChange extends SubCommand<Group> {
public GroupBulkChange() {
super("bulkchange", "Applies a bulk permission change to the groups permissions", "<server|world> <from> <to>",
Permission.GROUP_BULKCHANGE, Predicate.not(3));
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String type = args.get(0).toLowerCase();
String from = args.get(1);
String to = args.get(2);
if (to.equals("null")) {
to = null;
}
Set<Node> toAdd = new HashSet<>();
if (!type.equals("world") && !type.equals("server")) {
Message.BULK_CHANGE_TYPE_ERROR.send(sender);
return CommandResult.FAILURE;
}
Iterator<Node> iterator = group.getNodes().iterator();
if (type.equals("world")) {
while (iterator.hasNext()) {
Node element = iterator.next();
String world = element.getWorld().orElse("null");
if (!world.equals(from)) {
continue;
}
iterator.remove();
toAdd.add(me.lucko.luckperms.core.Node.builderFromExisting(element).setWorld(to).build());
}
} else {
while (iterator.hasNext()) {
Node element = iterator.next();
String server = element.getServer().orElse("global");
if (!server.equals(from)) {
continue;
}
iterator.remove();
toAdd.add(me.lucko.luckperms.core.Node.builderFromExisting(element).setServer(to).build());
}
}
group.getNodes().addAll(toAdd);
save(group, sender, plugin);
Message.BULK_CHANGE_SUCCESS.send(sender, toAdd.size());
return CommandResult.SUCCESS;
}
}
@@ -27,14 +27,14 @@ 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.contexts.Contexts;
import me.lucko.luckperms.groups.Group;
import java.util.*;
public class GroupChatMeta extends SubCommand<Group> {
public GroupChatMeta() {
super("chatmeta", "Displays a groups chat meta", "/%s group <group> chatmeta", Permission.GROUP_CHATMETA,
Predicate.alwaysFalse());
super("chatmeta", "Displays a groups chat meta", "", Permission.GROUP_CHATMETA, Predicate.alwaysFalse());
}
@Override
@@ -42,7 +42,7 @@ public class GroupChatMeta extends SubCommand<Group> {
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)) {
for (Node node : group.getAllNodes(null, Contexts.allowAll())) {
if (!node.isSuffix() && !node.isPrefix()) {
continue;
}
@@ -67,18 +67,18 @@ public class GroupChatMeta extends SubCommand<Group> {
}
if (prefixes.isEmpty()) {
Message.CHAT_META_PREFIX_NONE.send(sender, group.getName());
Message.CHAT_META_PREFIX_NONE.send(sender, group.getDisplayName());
} else {
Message.CHAT_META_PREFIX_HEADER.send(sender, group.getName());
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.getName());
Message.CHAT_META_SUFFIX_NONE.send(sender, group.getDisplayName());
} else {
Message.CHAT_META_SUFFIX_HEADER.send(sender, group.getName());
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());
}
@@ -36,14 +36,13 @@ import java.util.List;
public class GroupClear extends SubCommand<Group> {
public GroupClear() {
super("clear", "Clears a groups permissions", "/%s group <group> clear", Permission.GROUP_CLEAR,
Predicate.alwaysFalse());
super("clear", "Clears a groups permissions", "", Permission.GROUP_CLEAR, Predicate.alwaysFalse());
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
group.clearNodes();
Message.CLEAR_SUCCESS.send(sender, group.getName());
Message.CLEAR_SUCCESS.send(sender, group.getDisplayName());
LogEntry.build().actor(sender).acted(group).action("clear").build().submit(plugin, sender);
save(group, sender, plugin);
return CommandResult.SUCCESS;
@@ -33,9 +33,8 @@ import java.util.List;
public class GroupHasPerm extends SubCommand<Group> {
public GroupHasPerm() {
super("haspermission", "Checks to see if a group has a certain permission node",
"/%s group <group> haspermission <node> [server] [world]", Permission.GROUP_HASPERMISSION,
Predicate.notInRange(1, 3));
super("haspermission", "Checks to see if a group has a certain permission node", "<node> [server] [world]",
Permission.GROUP_HASPERMISSION, Predicate.notInRange(1, 3));
}
@Override
@@ -35,14 +35,13 @@ import java.util.List;
public class GroupInfo extends SubCommand<Group> {
public GroupInfo() {
super("info", "Gives info about the group", "/%s group <group> info", Permission.GROUP_INFO,
Predicate.alwaysFalse());
super("info", "Gives info about the group", "", Permission.GROUP_INFO, Predicate.alwaysFalse());
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
Message.GROUP_INFO.send(sender,
group.getName(),
group.getDisplayName(),
group.getPermanentNodes().size(),
group.getTemporaryNodes().size(),
label,
@@ -33,9 +33,8 @@ import java.util.List;
public class GroupInheritsPerm extends SubCommand<Group> {
public GroupInheritsPerm() {
super("inheritspermission", "Checks to see if a group inherits a certain permission node",
"/%s group <group> inheritspermission <node> [server] [world]", Permission.GROUP_INHERITSPERMISSION,
Predicate.notInRange(1, 3));
super("inheritspermission", "Checks to see if a group inherits a certain permission node", "<node> [server] [world]",
Permission.GROUP_INHERITSPERMISSION, Predicate.notInRange(1, 3));
}
@Override
@@ -32,14 +32,13 @@ import java.util.List;
public class GroupListNodes extends SubCommand<Group> {
public GroupListNodes() {
super("listnodes", "Lists the permission nodes the group has", "/%s group <group> listnodes",
Permission.GROUP_LISTNODES, Predicate.alwaysFalse());
super("listnodes", "Lists the permission nodes the group has", "", Permission.GROUP_LISTNODES, Predicate.alwaysFalse());
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
Message.LISTNODES.send(sender, group.getName(), Util.permNodesToString(group.getPermissions()));
Message.LISTNODES_TEMP.send(sender, group.getName(), Util.tempNodesToString(group.getPermissions()));
Message.LISTNODES.send(sender, group.getDisplayName(), Util.permNodesToString(group.getPermissions(false)));
Message.LISTNODES_TEMP.send(sender, group.getDisplayName(), Util.tempNodesToString(group.getPermissions(false)));
return CommandResult.SUCCESS;
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.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.groups.Group;
import java.util.List;
public class GroupListParents extends SubCommand<Group> {
public GroupListParents() {
super("listparents", "Lists the groups that this group inherits from", "", Permission.GROUP_LISTPARENTS, Predicate.alwaysFalse());
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
Message.LISTPARENTS.send(sender, group.getDisplayName(), Util.permGroupsToString(group.getPermissions(false)));
Message.LISTPARENTS_TEMP.send(sender, group.getDisplayName(), Util.tempGroupsToString(group.getPermissions(false)));
return CommandResult.SUCCESS;
}
}
@@ -38,7 +38,7 @@ import java.util.List;
public class GroupRemovePrefix extends SubCommand<Group> {
public GroupRemovePrefix() {
super("removeprefix", "Removes a prefix from a group", "/%s group <group> removeprefix <priority> <prefix> [server] [world]",
super("removeprefix", "Removes a prefix from a group", "<priority> <prefix> [server] [world]",
Permission.GROUP_REMOVEPREFIX, Predicate.notInRange(2, 4));
}
@@ -65,14 +65,14 @@ public class GroupRemovePrefix extends SubCommand<Group> {
if (args.size() == 3) {
group.unsetPermission(node, server);
Message.REMOVEPREFIX_SERVER_SUCCESS.send(sender, group.getName(), prefix, priority, 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.getName(), prefix, priority, 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);
@@ -80,7 +80,7 @@ public class GroupRemovePrefix extends SubCommand<Group> {
} else {
group.unsetPermission(node);
Message.REMOVEPREFIX_SUCCESS.send(sender, group.getName(), prefix, priority);
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);
@@ -89,7 +89,7 @@ public class GroupRemovePrefix extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_PREFIX.send(sender, group.getName());
Message.DOES_NOT_HAVE_PREFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -38,7 +38,7 @@ import java.util.List;
public class GroupRemoveSuffix extends SubCommand<Group> {
public GroupRemoveSuffix() {
super("removesuffix", "Removes a suffix from a group", "/%s group <group> removesuffix <priority> <suffix> [server] [world]",
super("removesuffix", "Removes a suffix from a group", "<priority> <suffix> [server] [world]",
Permission.GROUP_REMOVESUFFIX, Predicate.notInRange(2, 4));
}
@@ -65,14 +65,14 @@ public class GroupRemoveSuffix extends SubCommand<Group> {
if (args.size() == 3) {
group.unsetPermission(node, server);
Message.REMOVESUFFIX_SERVER_SUCCESS.send(sender, group.getName(), suffix, priority, 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.getName(), suffix, priority, 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);
@@ -80,7 +80,7 @@ public class GroupRemoveSuffix extends SubCommand<Group> {
} else {
group.unsetPermission(node);
Message.REMOVESUFFIX_SUCCESS.send(sender, group.getName(), suffix, priority);
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);
@@ -89,7 +89,7 @@ public class GroupRemoveSuffix extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_SUFFIX.send(sender, group.getName());
Message.DOES_NOT_HAVE_SUFFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -38,7 +38,7 @@ import java.util.List;
public class GroupRemoveTempPrefix extends SubCommand<Group> {
public GroupRemoveTempPrefix() {
super("removetempprefix", "Removes a temporary prefix from a group", "/%s group <group> removetempprefix <priority> <prefix> [server] [world]",
super("removetempprefix", "Removes a temporary prefix from a group", "<priority> <prefix> [server] [world]",
Permission.GROUP_REMOVE_TEMP_PREFIX, Predicate.notInRange(2, 4));
}
@@ -65,14 +65,14 @@ public class GroupRemoveTempPrefix extends SubCommand<Group> {
if (args.size() == 3) {
group.unsetPermission(node, server, true);
Message.REMOVE_TEMP_PREFIX_SERVER_SUCCESS.send(sender, group.getName(), prefix, priority, server);
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.getName(), prefix, priority, server, world);
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);
@@ -80,7 +80,7 @@ public class GroupRemoveTempPrefix extends SubCommand<Group> {
} else {
group.unsetPermission(node, true);
Message.REMOVE_TEMP_PREFIX_SUCCESS.send(sender, group.getName(), prefix, priority);
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);
@@ -89,7 +89,7 @@ public class GroupRemoveTempPrefix extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_PREFIX.send(sender, group.getName());
Message.DOES_NOT_HAVE_PREFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -38,7 +38,7 @@ import java.util.List;
public class GroupRemoveTempSuffix extends SubCommand<Group> {
public GroupRemoveTempSuffix() {
super("removetempsuffix", "Removes a temporary suffix from a group", "/%s group <group> removetempsuffix <priority> <suffix> [server] [world]",
super("removetempsuffix", "Removes a temporary suffix from a group", "<priority> <suffix> [server] [world]",
Permission.GROUP_REMOVE_TEMP_SUFFIX, Predicate.notInRange(2, 4));
}
@@ -65,14 +65,14 @@ public class GroupRemoveTempSuffix extends SubCommand<Group> {
if (args.size() == 3) {
group.unsetPermission(node, server, true);
Message.REMOVE_TEMP_SUFFIX_SERVER_SUCCESS.send(sender, group.getName(), suffix, priority, server);
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.getName(), suffix, priority, server, world);
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);
@@ -80,7 +80,7 @@ public class GroupRemoveTempSuffix extends SubCommand<Group> {
} else {
group.unsetPermission(node, true);
Message.REMOVE_TEMP_SUFFIX_SUCCESS.send(sender, group.getName(), suffix, priority);
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);
@@ -89,7 +89,7 @@ public class GroupRemoveTempSuffix extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_SUFFIX.send(sender, group.getName());
Message.DOES_NOT_HAVE_SUFFIX.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -37,8 +37,7 @@ import java.util.List;
public class GroupRename extends SubCommand<Group> {
public GroupRename() {
super("rename", "Rename this group", "/%s group <group> rename <new name>",
Permission.TRACK_APPEND, Predicate.not(1));
super("rename", "Rename this group", "<new name>", Permission.TRACK_APPEND, Predicate.not(1));
}
@Override
@@ -38,9 +38,8 @@ import java.util.List;
public class GroupSetInherit extends SubCommand<Group> {
public GroupSetInherit() {
super("setinherit", "Sets another group for this group to inherit permissions from",
"/%s group <group> setinherit <group> [server] [world]", Permission.GROUP_SETINHERIT,
Predicate.notInRange(1, 3));
super("setinherit", "Sets another group for this group to inherit permissions from", "<group> [server] [world]",
Permission.GROUP_SETINHERIT, Predicate.notInRange(1, 3));
}
@Override
@@ -48,7 +47,7 @@ public class GroupSetInherit extends SubCommand<Group> {
String groupName = args.get(0).toLowerCase();
if (ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
sendUsage(sender);
return CommandResult.INVALID_ARGS;
}
@@ -73,14 +72,14 @@ public class GroupSetInherit extends SubCommand<Group> {
if (args.size() == 2) {
group.setInheritGroup(group1, server);
Message.GROUP_SETINHERIT_SERVER_SUCCESS.send(sender, group.getName(), group1.getName(), 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.getName(), group1.getName(), 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);
@@ -88,7 +87,7 @@ public class GroupSetInherit extends SubCommand<Group> {
} else {
group.setInheritGroup(group1);
Message.GROUP_SETINHERIT_SUCCESS.send(sender, group.getName(), group1.getName());
Message.GROUP_SETINHERIT_SUCCESS.send(sender, group.getDisplayName(), group1.getDisplayName());
LogEntry.build().actor(sender).acted(group)
.action("setinherit " + group1.getName())
.build().submit(plugin, sender);
@@ -97,7 +96,7 @@ public class GroupSetInherit extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.GROUP_ALREADY_INHERITS.send(sender, group.getName(), group1.getName());
Message.GROUP_ALREADY_INHERITS.send(sender, group.getDisplayName(), group1.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -28,7 +28,6 @@ import me.lucko.luckperms.commands.Predicate;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.commands.SubCommand;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Patterns;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
@@ -39,8 +38,8 @@ import java.util.List;
public class GroupSetPermission extends SubCommand<Group> {
public GroupSetPermission() {
super("set", "Sets a permission for a group", "/%s group <group> set <node> <true|false> [server] [world]",
Permission.GROUP_SETPERMISSION, Predicate.notInRange(2, 4));
super("set", "Sets a permission for a group", "<node> <true|false> [server] [world]", Permission.GROUP_SETPERMISSION,
Predicate.notInRange(2, 4));
}
@Override
@@ -49,17 +48,17 @@ public class GroupSetPermission extends SubCommand<Group> {
String bool = args.get(1).toLowerCase();
if (ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
sendUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (Patterns.GROUP_MATCH.matcher(node).matches()) {
if (node.toLowerCase().startsWith("group.")) {
Message.GROUP_USE_INHERIT.send(sender);
return CommandResult.INVALID_ARGS;
}
if (!bool.equalsIgnoreCase("true") && !bool.equalsIgnoreCase("false")) {
sendUsage(sender, label);
sendUsage(sender);
return CommandResult.INVALID_ARGS;
}
@@ -75,14 +74,14 @@ public class GroupSetPermission extends SubCommand<Group> {
if (args.size() == 3) {
group.setPermission(node, b, server);
Message.SETPERMISSION_SERVER_SUCCESS.send(sender, node, bool, group.getName(), 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.getName(), 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);
@@ -90,7 +89,7 @@ public class GroupSetPermission extends SubCommand<Group> {
} else {
group.setPermission(node, b);
Message.SETPERMISSION_SUCCESS.send(sender, node, bool, group.getName());
Message.SETPERMISSION_SUCCESS.send(sender, node, bool, group.getDisplayName());
LogEntry.build().actor(sender).acted(group)
.action("set " + node + " " + b)
.build().submit(plugin, sender);
@@ -99,7 +98,7 @@ public class GroupSetPermission extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HASPERMISSION.send(sender, group.getName());
Message.ALREADY_HASPERMISSION.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -40,8 +40,7 @@ import java.util.List;
public class GroupSetTempInherit extends SubCommand<Group> {
public GroupSetTempInherit() {
super("settempinherit", "Sets another group for this group to inherit permissions from temporarily",
"/%s group <group> settempinherit <group> <duration> [server] [world]",
Permission.GROUP_SET_TEMP_INHERIT, Predicate.notInRange(2, 4));
"<group> <duration> [server] [world]", Permission.GROUP_SET_TEMP_INHERIT, Predicate.notInRange(2, 4));
}
@Override
@@ -49,7 +48,7 @@ public class GroupSetTempInherit extends SubCommand<Group> {
String groupName = args.get(0).toLowerCase();
if (ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
sendUsage(sender);
return CommandResult.INVALID_ARGS;
}
@@ -91,7 +90,7 @@ public class GroupSetTempInherit extends SubCommand<Group> {
if (args.size() == 3) {
group.setInheritGroup(group1, server, duration);
Message.GROUP_SET_TEMP_INHERIT_SERVER_SUCCESS.send(sender, group.getName(), group1.getName(), server,
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)
@@ -99,7 +98,7 @@ public class GroupSetTempInherit extends SubCommand<Group> {
} 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.getName(), group1.getName(), server,
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)
@@ -108,7 +107,7 @@ public class GroupSetTempInherit extends SubCommand<Group> {
} else {
group.setInheritGroup(group1, duration);
Message.GROUP_SET_TEMP_INHERIT_SUCCESS.send(sender, group.getName(), group1.getName(), DateUtil.formatDateDiff(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);
@@ -117,7 +116,7 @@ public class GroupSetTempInherit extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.USER_ALREADY_TEMP_MEMBER_OF.send(sender, group.getName(), group1.getName());
Message.USER_ALREADY_TEMP_MEMBER_OF.send(sender, group.getDisplayName(), group1.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -28,7 +28,6 @@ import me.lucko.luckperms.commands.Predicate;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.commands.SubCommand;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Patterns;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
@@ -40,8 +39,7 @@ import java.util.List;
public class GroupSetTempPermission extends SubCommand<Group> {
public GroupSetTempPermission() {
super("settemp", "Sets a temporary permission for a group",
"/%s group <group> settemp <node> <true|false> <duration> [server] [world]",
super("settemp", "Sets a temporary permission for a group", "<node> <true|false> <duration> [server] [world]",
Permission.GROUP_SET_TEMP_PERMISSION, Predicate.notInRange(3, 5));
}
@@ -51,17 +49,17 @@ public class GroupSetTempPermission extends SubCommand<Group> {
String bool = args.get(1).toLowerCase();
if (ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
sendUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (Patterns.GROUP_MATCH.matcher(node).matches()) {
if (node.toLowerCase().startsWith("group.")) {
Message.GROUP_USE_INHERIT.send(sender);
return CommandResult.INVALID_ARGS;
}
if (!bool.equalsIgnoreCase("true") && !bool.equalsIgnoreCase("false")) {
sendUsage(sender, label);
sendUsage(sender);
return CommandResult.INVALID_ARGS;
}
@@ -94,7 +92,7 @@ public class GroupSetTempPermission extends SubCommand<Group> {
if (args.size() == 4) {
group.setPermission(node, b, server, duration);
Message.SETPERMISSION_TEMP_SERVER_SUCCESS.send(sender, node, bool, group.getName(), server,
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)
@@ -102,7 +100,7 @@ public class GroupSetTempPermission extends SubCommand<Group> {
} 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.getName(), server,
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)
@@ -111,7 +109,7 @@ public class GroupSetTempPermission extends SubCommand<Group> {
} else {
group.setPermission(node, b, duration);
Message.SETPERMISSION_TEMP_SUCCESS.send(sender, node, bool, group.getName(), DateUtil.formatDateDiff(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);
@@ -120,7 +118,7 @@ public class GroupSetTempPermission extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectAlreadyHasException e) {
Message.ALREADY_HAS_TEMP_PERMISSION.send(sender, group.getName());
Message.ALREADY_HAS_TEMP_PERMISSION.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -34,8 +34,7 @@ import java.util.stream.Collectors;
public class GroupShowTracks extends SubCommand<Group> {
public GroupShowTracks() {
super("showtracks", "Lists the tracks that this group features on", "/%s group <group> showtracks",
Permission.GROUP_SHOWTRACKS, Predicate.alwaysFalse());
super("showtracks", "Lists the tracks that this group features on", "", Permission.GROUP_SHOWTRACKS, Predicate.alwaysFalse());
}
@Override
@@ -28,7 +28,6 @@ import me.lucko.luckperms.commands.Predicate;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.commands.SubCommand;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Patterns;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectLacksException;
@@ -39,8 +38,8 @@ import java.util.List;
public class GroupUnSetPermission extends SubCommand<Group> {
public GroupUnSetPermission() {
super("unset", "Unsets a permission for a group", "/%s group <group> unset <node> [server] [world]",
Permission.GROUP_UNSETPERMISSION, Predicate.notInRange(1, 3));
super("unset", "Unsets a permission for a group", "<node> [server] [world]", Permission.GROUP_UNSETPERMISSION,
Predicate.notInRange(1, 3));
}
@Override
@@ -48,11 +47,11 @@ public class GroupUnSetPermission extends SubCommand<Group> {
String node = args.get(0).replace("{SPACE}", " ");
if (ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
sendUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (Patterns.GROUP_MATCH.matcher(node).matches()) {
if (node.toLowerCase().startsWith("group.")) {
Message.GROUP_USE_UNINHERIT.send(sender);
return CommandResult.INVALID_ARGS;
}
@@ -67,14 +66,14 @@ public class GroupUnSetPermission extends SubCommand<Group> {
if (args.size() == 2) {
group.unsetPermission(node, server);
Message.UNSETPERMISSION_SERVER_SUCCESS.send(sender, node, group.getName(), 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.getName(), 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);
@@ -82,7 +81,7 @@ public class GroupUnSetPermission extends SubCommand<Group> {
} else {
group.unsetPermission(node);
Message.UNSETPERMISSION_SUCCESS.send(sender, node, group.getName());
Message.UNSETPERMISSION_SUCCESS.send(sender, node, group.getDisplayName());
LogEntry.build().actor(sender).acted(group)
.action("unset " + node)
.build().submit(plugin, sender);
@@ -91,7 +90,7 @@ public class GroupUnSetPermission extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVEPERMISSION.send(sender, group.getName());
Message.DOES_NOT_HAVEPERMISSION.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -39,8 +39,7 @@ import java.util.List;
public class GroupUnsetInherit extends SubCommand<Group> {
public GroupUnsetInherit() {
super("unsetinherit", "Unsets another group for this group to inherit permissions from",
"/%s group <group> unsetinherit <group> [server] [world]", Permission.GROUP_UNSETINHERIT,
Predicate.notInRange(1, 3));
"<group> [server] [world]", Permission.GROUP_UNSETINHERIT, Predicate.notInRange(1, 3));
}
@Override
@@ -48,7 +47,7 @@ public class GroupUnsetInherit extends SubCommand<Group> {
String groupName = args.get(0).toLowerCase();
if (ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
sendUsage(sender);
return CommandResult.INVALID_ARGS;
}
@@ -62,14 +61,14 @@ public class GroupUnsetInherit extends SubCommand<Group> {
if (args.size() == 2) {
group.unsetPermission("group." + groupName, server);
Message.GROUP_UNSETINHERIT_SERVER_SUCCESS.send(sender, group.getName(), 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.getName(), 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);
@@ -77,7 +76,7 @@ public class GroupUnsetInherit extends SubCommand<Group> {
} else {
group.unsetPermission("group." + groupName);
Message.GROUP_UNSETINHERIT_SUCCESS.send(sender, group.getName(), groupName);
Message.GROUP_UNSETINHERIT_SUCCESS.send(sender, group.getDisplayName(), groupName);
LogEntry.build().actor(sender).acted(group)
.action("unsetinherit " + groupName)
.build().submit(plugin, sender);
@@ -86,7 +85,7 @@ public class GroupUnsetInherit extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.GROUP_DOES_NOT_INHERIT.send(sender, group.getName(), groupName);
Message.GROUP_DOES_NOT_INHERIT.send(sender, group.getDisplayName(), groupName);
return CommandResult.STATE_ERROR;
}
}
@@ -39,8 +39,7 @@ import java.util.List;
public class GroupUnsetTempInherit extends SubCommand<Group> {
public GroupUnsetTempInherit() {
super("unsettempinherit", "Unsets another group for this group to inherit permissions from",
"/%s group <group> unsettempinherit <group> [server] [world]", Permission.GROUP_UNSET_TEMP_INHERIT,
Predicate.notInRange(1, 3));
"<group> [server] [world]", Permission.GROUP_UNSET_TEMP_INHERIT, Predicate.notInRange(1, 3));
}
@Override
@@ -48,7 +47,7 @@ public class GroupUnsetTempInherit extends SubCommand<Group> {
String groupName = args.get(0).toLowerCase();
if (ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
sendUsage(sender);
return CommandResult.INVALID_ARGS;
}
@@ -62,14 +61,14 @@ public class GroupUnsetTempInherit extends SubCommand<Group> {
if (args.size() == 2) {
group.unsetPermission("group." + groupName, server, true);
Message.GROUP_UNSET_TEMP_INHERIT_SERVER_SUCCESS.send(sender, group.getName(), groupName, server);
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.getName(), groupName, server, world);
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);
@@ -77,7 +76,7 @@ public class GroupUnsetTempInherit extends SubCommand<Group> {
} else {
group.unsetPermission("group." + groupName, true);
Message.GROUP_UNSET_TEMP_INHERIT_SUCCESS.send(sender, group.getName(), groupName);
Message.GROUP_UNSET_TEMP_INHERIT_SUCCESS.send(sender, group.getDisplayName(), groupName);
LogEntry.build().actor(sender).acted(group)
.action("unsettempinherit " + groupName)
.build().submit(plugin, sender);
@@ -86,7 +85,7 @@ public class GroupUnsetTempInherit extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.GROUP_DOES_NOT_TEMP_INHERIT.send(sender, group.getName(), groupName);
Message.GROUP_DOES_NOT_TEMP_INHERIT.send(sender, group.getDisplayName(), groupName);
return CommandResult.STATE_ERROR;
}
}
@@ -28,7 +28,6 @@ import me.lucko.luckperms.commands.Predicate;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.commands.SubCommand;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Patterns;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.data.LogEntry;
import me.lucko.luckperms.exceptions.ObjectLacksException;
@@ -39,9 +38,8 @@ import java.util.List;
public class GroupUnsetTempPermission extends SubCommand<Group> {
public GroupUnsetTempPermission() {
super("unsettemp", "Unsets a temporary permission for a group",
"/%s group <group> unsettemp <node> [server] [world]", Permission.GROUP_UNSET_TEMP_PERMISSION,
Predicate.notInRange(1, 3));
super("unsettemp", "Unsets a temporary permission for a group", "<node> [server] [world]",
Permission.GROUP_UNSET_TEMP_PERMISSION, Predicate.notInRange(1, 3));
}
@Override
@@ -49,11 +47,11 @@ public class GroupUnsetTempPermission extends SubCommand<Group> {
String node = args.get(0).replace("{SPACE}", " ");
if (ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
sendUsage(sender);
return CommandResult.INVALID_ARGS;
}
if (Patterns.GROUP_MATCH.matcher(node).matches()) {
if (node.toLowerCase().startsWith("group.")) {
Message.GROUP_USE_UNINHERIT.send(sender);
return CommandResult.INVALID_ARGS;
}
@@ -68,14 +66,14 @@ public class GroupUnsetTempPermission extends SubCommand<Group> {
if (args.size() == 2) {
group.unsetPermission(node, server);
Message.UNSET_TEMP_PERMISSION_SERVER_SUCCESS.send(sender, node, group.getName(), 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.getName(), 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);
@@ -83,7 +81,7 @@ public class GroupUnsetTempPermission extends SubCommand<Group> {
} else {
group.unsetPermission(node, true);
Message.UNSET_TEMP_PERMISSION_SUCCESS.send(sender, node, group.getName());
Message.UNSET_TEMP_PERMISSION_SUCCESS.send(sender, node, group.getDisplayName());
LogEntry.build().actor(sender).acted(group)
.action("unsettemp " + node)
.build().submit(plugin, sender);
@@ -92,7 +90,7 @@ public class GroupUnsetTempPermission extends SubCommand<Group> {
save(group, sender, plugin);
return CommandResult.SUCCESS;
} catch (ObjectLacksException e) {
Message.DOES_NOT_HAVE_TEMP_PERMISSION.send(sender, group.getName());
Message.DOES_NOT_HAVE_TEMP_PERMISSION.send(sender, group.getDisplayName());
return CommandResult.STATE_ERROR;
}
}
@@ -41,7 +41,7 @@ import java.util.List;
public class LogExport extends SubCommand<Log> {
public LogExport() {
super("export", "Export the log to a file", "/%s log export <file>", Permission.LOG_EXPORT, Predicate.not(1));
super("export", "Export the log to a file", "<file>", Permission.LOG_EXPORT, Predicate.not(1));
}
@Override
@@ -40,7 +40,7 @@ import java.util.SortedMap;
public class LogGroupHistory extends SubCommand<Log> {
public LogGroupHistory() {
super("grouphistory", "View an objects history", "/%s log grouphistory <group> [page]", Permission.LOG_GROUP_HISTORY,
super("grouphistory", "View an objects history", "<group> [page]", Permission.LOG_GROUP_HISTORY,
Predicate.notInRange(1, 2));
}
@@ -37,8 +37,7 @@ import java.util.UUID;
public class LogNotify extends SubCommand<Log> {
public LogNotify() {
super("notify", "Toggle notifications", "/%s log notify [on|off]", Permission.LOG_NOTIFY,
Predicate.notInRange(0, 1));
super("notify", "Toggle notifications", "[on|off]", Permission.LOG_NOTIFY, Predicate.notInRange(0, 1));
}
@Override
@@ -38,8 +38,7 @@ import java.util.UUID;
public class LogRecent extends SubCommand<Log> {
public LogRecent() {
super("recent", "View recent actions", "/%s log recent [user] [page]", Permission.LOG_RECENT,
Predicate.notInRange(0, 2));
super("recent", "View recent actions", "[user] [page]", Permission.LOG_RECENT, Predicate.notInRange(0, 2));
}
@Override
@@ -40,8 +40,7 @@ import java.util.stream.Collectors;
public class LogSearch extends SubCommand<Log> {
public LogSearch() {
super("search", "Search the log for an entry", "/%s log search <query> [page]", Permission.LOG_SEARCH,
Predicate.is(0));
super("search", "Search the log for an entry", "<query> [page]", Permission.LOG_SEARCH, Predicate.is(0));
}
@Override
@@ -40,8 +40,7 @@ import java.util.SortedMap;
public class LogTrackHistory extends SubCommand<Log> {
public LogTrackHistory() {
super("trackhistory", "View an objects history", "/%s log trackhistory <track> [page]", Permission.LOG_TRACK_HISTORY,
Predicate.notInRange(1, 2));
super("trackhistory", "View an objects history", "<track> [page]", Permission.LOG_TRACK_HISTORY, Predicate.notInRange(1, 2));
}
@Override
@@ -38,8 +38,7 @@ import java.util.UUID;
public class LogUserHistory extends SubCommand<Log> {
public LogUserHistory() {
super("userhistory", "View an objects history", "/%s log userhistory <user> [page]", Permission.LOG_USER_HISTORY,
Predicate.notInRange(1, 2));
super("userhistory", "View an objects history", "<user> [page]", Permission.LOG_USER_HISTORY, Predicate.notInRange(1, 2));
}
@Override
@@ -1,3 +1,25 @@
/*
* 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.migration.subcommands;
import de.bananaco.bpermissions.api.*;
@@ -60,7 +82,7 @@ public class MigrationBPermissions extends SubCommand<Object> {
}
public MigrationBPermissions() {
super("bpermissions", "Migration from bPermissions", "/%s migration bpermissions", MIGRATION, Predicate.alwaysFalse());
super("bpermissions", "Migration from bPermissions", "", MIGRATION, Predicate.alwaysFalse());
}
@Override
@@ -43,8 +43,7 @@ import java.util.Map;
*/
public class MigrationBungeePerms extends SubCommand<Object> {
public MigrationBungeePerms() {
super("bungeeperms", "Migration from BungeePerms", "/%s migration bungeeperms",
Permission.MIGRATION, Predicate.alwaysFalse());
super("bungeeperms", "Migration from BungeePerms", "", Permission.MIGRATION, Predicate.alwaysFalse());
}
@Override
@@ -45,8 +45,7 @@ import java.util.stream.Collectors;
public class MigrationGroupManager extends SubCommand<Object> {
public MigrationGroupManager() {
super("groupmanager", "Migration from GroupManager", "/%s migration groupmanager [world names]",
Permission.MIGRATION, Predicate.is(0));
super("groupmanager", "Migration from GroupManager", "[world names...]", Permission.MIGRATION, Predicate.is(0));
}
@Override
@@ -123,6 +122,7 @@ public class MigrationGroupManager extends SubCommand<Object> {
}
}
plugin.getDatastore().saveGroup(group);
}
Map<UUID, Map<Map.Entry<String, String>, Boolean>> users = new HashMap<>();
@@ -50,8 +50,7 @@ import java.util.stream.Collectors;
public class MigrationPermissionsEx extends SubCommand<Object> {
public MigrationPermissionsEx() {
super("permissionsex", "Migration from PermissionsEx", "/%s migration permissionsex [world names]",
Permission.MIGRATION, Predicate.alwaysFalse());
super("permissionsex", "Migration from PermissionsEx", "[world names...]", Permission.MIGRATION, Predicate.alwaysFalse());
}
@SuppressWarnings("deprecation")
@@ -118,7 +117,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
try {
for (String node : group.getOwnPermissions(null)) {
boolean value = true;
if (node.startsWith("!")) {
if (node.startsWith("-")) {
node = node.substring(1);
value = false;
}
@@ -143,7 +142,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
for (String world : worlds) {
for (String node : group.getOwnPermissions(world)) {
boolean value = true;
if (node.startsWith("!")) {
if (node.startsWith("-")) {
node = node.substring(1);
value = false;
}
@@ -262,7 +261,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
try {
for (String node : user.getOwnPermissions(null)) {
boolean value = true;
if (node.startsWith("!")) {
if (node.startsWith("-")) {
node = node.substring(1);
value = false;
}
@@ -287,7 +286,7 @@ public class MigrationPermissionsEx extends SubCommand<Object> {
for (String world : worlds) {
for (String node : user.getOwnPermissions(world)) {
boolean value = true;
if (node.startsWith("!")) {
if (node.startsWith("-")) {
node = node.substring(1);
value = false;
}
@@ -23,14 +23,17 @@
package me.lucko.luckperms.commands.migration.subcommands;
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.CommandResult;
import me.lucko.luckperms.commands.Predicate;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.commands.SubCommand;
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;
@@ -45,46 +48,79 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import static me.lucko.luckperms.constants.Permission.MIGRATION;
@SuppressWarnings("unchecked")
public class MigrationPowerfulPerms extends SubCommand<Object> {
/* <sadness>
The PowerfulPerms API is a complete joke. Seriously, it would probably be easier reflecting into the actual plugin.
Methods move about randomly every version...
What kind of API requires reflection to function with multiple versions...
Doesn't that just defeat the whole god damn point of having an API in the first place?
Whatever happened to the concept of depreciation and responsible API creation?
I tried to keep reflection to a minimum, but in some places there's no other option.
This class is a complete fucking mess for that reason. I sad now :(
</sadness> */
Whatever happened to depreciation?
</sadness> */
private static Method getPlayerPermissionsMethod = null;
private static Method getPlayerGroupsMethod = null;
private static Method getGroupMethod = null;
// lol
private static boolean superLegacy = false;
private static boolean legacy = false;
static {
try {
getPlayerGroupsMethod = PermissionManager.class.getMethod("getPlayerOwnGroups", UUID.class, ResultRunnable.class);
getPlayerGroupsMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
Class.forName("com.github.cheesesoftware.PowerfulPermsAPI.ResponseRunnable");
legacy = true;
} catch (ClassNotFoundException ignored) {}
if (legacy) {
try {
getPlayerGroupsMethod = PermissionManager.class.getMethod("getPlayerGroups", UUID.class, ResultRunnable.class);
getPlayerGroupsMethod.setAccessible(true);
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
}
getPlayerPermissionsMethod = PermissionManager.class.getMethod("getPlayerOwnPermissions", UUID.class, ResultRunnable.class);
getPlayerPermissionsMethod.setAccessible(true);
} catch (NoSuchMethodException ignored) {}
} else {
try {
getPlayerPermissionsMethod = PermissionManager.class.getMethod("getPlayerOwnPermissions", UUID.class);
getPlayerPermissionsMethod.setAccessible(true);
} catch (NoSuchMethodException ignored) {}
}
try {
getGroupMethod = CachedGroup.class.getMethod("getGroup");
getGroupMethod.setAccessible(true);
legacy = true;
} catch (NoSuchMethodException ignored) {
superLegacy = true;
} catch (NoSuchMethodException ignored) {}
if (!legacy) {
try {
getPlayerGroupsMethod = PermissionManager.class.getMethod("getPlayerOwnGroups", UUID.class);
getPlayerGroupsMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
} else {
try {
getPlayerGroupsMethod = PermissionManager.class.getMethod("getPlayerOwnGroups", UUID.class, ResultRunnable.class);
getPlayerGroupsMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
try {
getPlayerGroupsMethod = PermissionManager.class.getMethod("getPlayerGroups", UUID.class, ResultRunnable.class);
getPlayerGroupsMethod.setAccessible(true);
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
}
}
}
}
public MigrationPowerfulPerms() {
super("powerfulperms", "Migration from PowerfulPerms",
"/%s migration powerfulperms <address> <database> <username> <password> <db table>", MIGRATION, Predicate.not(5));
super("powerfulperms", "Migration from PowerfulPerms", "<address> <database> <username> <password> <db table>",
MIGRATION, Predicate.not(5));
}
@Override
@@ -97,6 +133,42 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
}
}
private static void getPlayerPermissions(PermissionManager manager, UUID uuid, Callback<List<Permission>> callback) {
if (legacy) {
try {
getPlayerPermissionsMethod.invoke(manager, uuid, new LPResultRunnable<List<Permission>>() {
@Override
public void run() {
callback.onComplete(getResult());
}
});
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
} else {
try {
ListenableFuture<List<Permission>> lf = (ListenableFuture<List<Permission>>) getPlayerPermissionsMethod.invoke(manager, uuid);
try {
if (lf.isDone()) {
callback.onComplete(lf.get());
} else {
lf.addListener(() -> {
try {
callback.onComplete(lf.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}, Runnable::run);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
private CommandResult run(LuckPermsPlugin plugin, List<String> args) {
final Logger log = plugin.getLog();
if (!plugin.isPluginLoaded("PowerfulPerms")) {
@@ -168,7 +240,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
// Groups first.
log.info("PowerfulPerms Migration: Starting group migration.");
Map<Integer, Group> groups = pm.getGroups();
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());
@@ -181,16 +253,16 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
ex.printStackTrace();
}
for (Permission p : g.getOwnPermissions()) {
for (Permission p : g.getOwnPermissions()) { // All versions
applyPerm(group, p, plugin);
}
for (Group parent : g.getParents()) {
for (Group parent : g.getParents()) { // All versions
try {
group.setPermission("group." + parent.getName().toLowerCase(), true);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(group).action("setinherit " + parent.getName().toLowerCase())
.acted(group).action("setinherit " + parent.getName().toLowerCase()) // All versions
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
@@ -216,156 +288,176 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
User user = plugin.getUserManager().get(uuid);
// Get a list of Permissions held by the user from the PP API.
pm.getPlayerOwnPermissions(uuid, new LPResultRunnable<List<Permission>>() {
@Override
public void run() {
List<Permission> perms = this.getResult();
perms.forEach(p -> applyPerm(user, p, plugin));
getPlayerPermissions(pm, uuid, perms -> { // Changes each version
perms.forEach(p -> applyPerm(user, p, plugin));
// Update the progress so the user can be saved and unloaded.
synchronized (progress) {
progress.get(uuid).countDown();
if (progress.get(uuid).getCount() == 0) {
plugin.getDatastore().saveUser(user);
plugin.getUserManager().cleanup(user);
}
// Update the progress so the user can be saved and unloaded.
synchronized (progress) {
progress.get(uuid).countDown();
if (progress.get(uuid).getCount() == 0) {
plugin.getDatastore().saveUser(user);
plugin.getUserManager().cleanup(user);
}
}
});
// Migrate the user's groups to LuckPerms from PP.
try {
getPlayerGroupsMethod.invoke(pm, uuid, new LPResultRunnable<LinkedHashMap<String, List<CachedGroup>>>() {
@Override
public void run() {
Map<String, List<CachedGroup>> groups = getResult();
for (Map.Entry<String, List<CachedGroup>> e : groups.entrySet()) {
final String server;
if (e.getKey() != null && (e.getKey().equals("") || e.getKey().equalsIgnoreCase("all"))) {
server = null;
} else {
server = e.getKey();
}
// This is horrible. So many random API changes through versions, no depreciation.
if (legacy) {
e.getValue().stream()
.filter(cg -> !cg.isNegated())
.map(cg -> {
try {
return (Group) getGroupMethod.invoke(cg);
} catch (IllegalAccessException | InvocationTargetException e1) {
e1.printStackTrace();
return null;
}
})
.forEach(g -> {
if (g != null) {
if (server == null) {
try {
user.setPermission("group." + g.getName().toLowerCase(), true);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addgroup " + g.getName().toLowerCase())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
} else {
try {
user.setPermission("group." + g.getName().toLowerCase(), true, server);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addgroup " + g.getName().toLowerCase() + " " + server)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
}
});
} else {
e.getValue().stream()
.filter(g -> !g.hasExpired() && !g.isNegated())
.forEach(g -> {
final Group group = pm.getGroup(g.getGroupId());
if (g.willExpire()) {
if (server == null) {
try {
user.setPermission("group." + group.getName().toLowerCase(), true, g.getExpirationDate().getTime() / 1000L);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addtempgroup " + group.getName().toLowerCase() + " " + g.getExpirationDate().getTime() / 1000L)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
} else {
try {
user.setPermission("group." + group.getName().toLowerCase(), true, server, g.getExpirationDate().getTime() / 1000L);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addtempgroup " + group.getName().toLowerCase() + " " + g.getExpirationDate().getTime() / 1000L + " " + server)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
} else {
if (server == null) {
try {
user.setPermission("group." + group.getName().toLowerCase(), true);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addgroup " + group.getName().toLowerCase())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
} else {
try {
user.setPermission("group." + group.getName().toLowerCase(), true, server);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addgroup " + group.getName().toLowerCase() + " " + server)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
}
});
}
}
// Update the progress so the user can be saved and unloaded.
synchronized (progress) {
progress.get(uuid).countDown();
if (progress.get(uuid).getCount() == 0) {
plugin.getDatastore().saveUser(user);
plugin.getUserManager().cleanup(user);
}
}
Callback<Map<String, List<CachedGroup>>> callback = groups1 -> {
for (Map.Entry<String, List<CachedGroup>> e : groups1.entrySet()) {
final String server;
if (e.getKey() != null && (e.getKey().equals("") || e.getKey().equalsIgnoreCase("all"))) {
server = null;
} else {
server = e.getKey();
}
});
} catch (IllegalAccessException | InvocationTargetException e) {
log.info("PowerfulPerms Migration: Error");
e.printStackTrace();
if (superLegacy) {
e.getValue().stream()
.filter(cg -> !cg.isNegated())
.map(cg -> {
try {
return (Group) getGroupMethod.invoke(cg);
} catch (IllegalAccessException | InvocationTargetException e1) {
e1.printStackTrace();
return null;
}
})
.forEach(g -> {
if (g != null) {
if (server == null) {
try {
user.setPermission("group." + g.getName().toLowerCase(), true);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addgroup " + g.getName().toLowerCase())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
} else {
try {
user.setPermission("group." + g.getName().toLowerCase(), true, server);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addgroup " + g.getName().toLowerCase() + " " + server)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
}
});
} else {
e.getValue().stream()
.filter(g -> !g.hasExpired() && !g.isNegated())
.forEach(g -> {
final Group group = pm.getGroup(g.getGroupId());
if (g.willExpire()) {
if (server == null) {
try {
user.setPermission("group." + group.getName().toLowerCase(), true, g.getExpirationDate().getTime() / 1000L);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addtempgroup " + group.getName().toLowerCase() + " " + g.getExpirationDate().getTime() / 1000L)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
} else {
try {
user.setPermission("group." + group.getName().toLowerCase(), true, server, g.getExpirationDate().getTime() / 1000L);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addtempgroup " + group.getName().toLowerCase() + " " + g.getExpirationDate().getTime() / 1000L + " " + server)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
} else {
if (server == null) {
try {
user.setPermission("group." + group.getName().toLowerCase(), true);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addgroup " + group.getName().toLowerCase())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
} else {
try {
user.setPermission("group." + group.getName().toLowerCase(), true, server);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addgroup " + group.getName().toLowerCase() + " " + server)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
}
});
}
}
// Update the progress so the user can be saved and unloaded.
synchronized (progress) {
progress.get(uuid).countDown();
if (progress.get(uuid).getCount() == 0) {
plugin.getDatastore().saveUser(user);
plugin.getUserManager().cleanup(user);
}
}
};
if (!legacy) {
try {
ListenableFuture<LinkedHashMap<String, List<CachedGroup>>> future = (ListenableFuture<LinkedHashMap<String, List<CachedGroup>>>) getPlayerGroupsMethod.invoke(pm, uuid);
try {
if (future.isDone()) {
callback.onComplete(future.get());
} else {
future.addListener(() -> {
try {
callback.onComplete(future.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}, Runnable::run);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
} catch (IllegalAccessException | InvocationTargetException e) {
log.info("PowerfulPerms Migration: Error");
e.printStackTrace();
}
} else {
try {
getPlayerGroupsMethod.invoke(pm, uuid, new LPResultRunnable<LinkedHashMap<String, List<CachedGroup>>>() {
@Override
public void run() {
callback.onComplete(getResult());
}
});
} catch (IllegalAccessException | InvocationTargetException e) {
log.info("PowerfulPerms Migration: Error");
e.printStackTrace();
}
}
}
@@ -417,7 +509,7 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
}
long expireAt = 0L;
if (!legacy) {
if (!superLegacy) {
if (p.willExpire()) {
expireAt = p.getExpirationDate().getTime() / 1000L;
}
@@ -508,22 +600,4 @@ public class MigrationPowerfulPerms extends SubCommand<Object> {
}
}
}
/**
* Overrides the default ResultRunnable, callbacks will always run in the same thread. (an async one, hopefully.)
* @param <T> type
*/
@SuppressWarnings("WeakerAccess")
public abstract class LPResultRunnable<T> extends ResultRunnable<T> {
public LPResultRunnable() {
super();
super.sameThread = true;
}
public T getResult() {
return super.result;
}
}
}
@@ -49,8 +49,7 @@ import java.util.stream.Collectors;
*/
public class MigrationZPermissions extends SubCommand<Object> {
public MigrationZPermissions() {
super("zpermissions", "Migration from zPermissions", "/%s migration zpermissions [world names]",
Permission.MIGRATION, Predicate.alwaysFalse());
super("zpermissions", "Migration from zPermissions", "[world names...]", Permission.MIGRATION, Predicate.alwaysFalse());
}
@Override
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.commands.migration.subcommands.utils;
import com.github.cheesesoftware.PowerfulPermsAPI.ResultRunnable;
/**
* Overrides the default ResultRunnable, callbacks will always run in the same thread. (an async one, hopefully.)
* @param <T> type
*/
public abstract class LPResultRunnable<T> extends ResultRunnable<T> {
public LPResultRunnable() {
super();
super.sameThread = true;
}
public T getResult() {
return super.result;
}
}
@@ -38,6 +38,7 @@ public class DebugCommand extends SingleMainCommand {
@Override
protected CommandResult execute(LuckPermsPlugin plugin, Sender sender, List<String> args, String label) {
plugin.getLog().info(sender.getName() + " used the debug command.");
Message.DEBUG.send(sender,
plugin.getPlayerCount(),
plugin.getUserManager().getAll().size(),
@@ -0,0 +1,209 @@
/*
* 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.misc;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.commands.CommandResult;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.commands.SingleMainCommand;
import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.storage.Datastore;
import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.users.User;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public class ExportCommand extends SingleMainCommand {
public ExportCommand() {
super("Export", "/%s export <file>", 1, Permission.MIGRATION);
}
@Override
protected CommandResult execute(LuckPermsPlugin plugin, Sender sender, List<String> args, String label) {
final Logger log = plugin.getLog();
if (!sender.getUuid().equals(Constants.getConsoleUUID())) {
Message.MIGRATION_NOT_CONSOLE.send(sender);
return CommandResult.NO_PERMISSION;
}
File f = new File(plugin.getMainDir(), args.get(0));
if (f.exists()) {
Message.LOG_EXPORT_ALREADY_EXISTS.send(sender, f.getAbsolutePath());
return CommandResult.INVALID_ARGS;
}
try {
f.createNewFile();
} catch (IOException e) {
Message.LOG_EXPORT_FAILURE.send(sender);
e.printStackTrace();
return CommandResult.FAILURE;
}
if (!Files.isWritable(f.toPath())) {
Message.LOG_EXPORT_NOT_WRITABLE.send(sender, f.getAbsolutePath());
return CommandResult.FAILURE;
}
try (FileWriter fWriter = new FileWriter(f, true); BufferedWriter writer = new BufferedWriter(fWriter)) {
log.info("Export: Starting export process.");
// Export Groups
log.info("Export: Exporting all groups.");
// Create the groups first
for (Group group : plugin.getGroupManager().getAll().values()) {
write(writer, "/luckperms creategroup " + group.getName());
}
int groupCount = 0;
for (Group group : plugin.getGroupManager().getAll().values()) {
groupCount++;
for (Node node : group.getNodes()) {
write(writer, nodeToString(node, group.getName(), true));
}
}
log.info("Export: Exported " + groupCount + " groups.");
// Export tracks
log.info("Export: Exporting all tracks.");
// Create the tracks first
for (Track track : plugin.getTrackManager().getAll().values()) {
write(writer, "/luckperms createtrack " + track.getName());
}
int trackCount = 0;
for (Track track : plugin.getTrackManager().getAll().values()) {
trackCount++;
for (String group : track.getGroups()) {
write(writer, "/luckperms track " + track.getName() + " append " + group);
}
}
log.info("Export: Exported " + trackCount + " tracks.");
// Export users
log.info("Export: Exporting all users. Finding a list of unique users to export.");
Datastore ds = plugin.getDatastore();
Set<UUID> users = ds.getUniqueUsers();
log.info("Export: Found " + users.size() + " unique users to export.");
int userCount = 0;
for (UUID uuid : users) {
userCount++;
plugin.getDatastore().loadUser(uuid, "null");
User user = plugin.getUserManager().get(uuid);
for (Node node : user.getNodes()) {
if (node.isGroupNode() && node.getGroupName().equalsIgnoreCase("default")) {
continue;
}
write(writer, nodeToString(node, user.getUuid().toString(), false));
}
write(writer, "/luckperms user " + user.getUuid().toString() + " setprimarygroup " + user.getPrimaryGroup());
plugin.getUserManager().cleanup(user);
}
log.info("Export: Exported " + userCount + " users.");
try {
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
Message.LOG_EXPORT_SUCCESS.send(sender, f.getAbsolutePath());
return CommandResult.SUCCESS;
} catch (Throwable t) {
t.printStackTrace();
return CommandResult.FAILURE;
}
}
@Override
protected boolean isAuthorized(Sender sender) {
return sender.getUuid().equals(Constants.getConsoleUUID());
}
private static void write(BufferedWriter writer, String s) {
try {
writer.write(s);
writer.newLine();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String nodeToString(Node node, String id, boolean group) {
StringBuilder sb = new StringBuilder();
sb.append("/luckperms ").append(group ? "group " : "user ").append(id).append(" ");
if (node.isGroupNode()) {
if (node.isTemporary()) {
sb.append(group ? "settempinherit " : "addtempgroup ");
sb.append(node.getGroupName());
sb.append(" ").append(node.getExpiryUnixTime());
} else {
sb.append(group ? "setinherit " : "addgroup ");
sb.append(node.getGroupName());
}
if (node.isWorldSpecific()) {
sb.append(" ").append(node.getServer().get()).append(" ").append(node.getWorld().get());
} else if (node.isServerSpecific()) {
sb.append(" ").append(node.getServer().get());
}
return sb.toString();
}
sb.append(node.isTemporary() ? "settemp " : "set ");
sb.append(node.getPermission()).append(" ").append(node.getValue());
if (node.isTemporary()) {
sb.append(" ").append(node.getExpiryUnixTime());
}
if (node.isWorldSpecific()) {
sb.append(" ").append(node.getServer().get()).append(" ").append(node.getWorld().get());
} else if (node.isServerSpecific()) {
sb.append(" ").append(node.getServer().get());
}
return sb.toString();
}
}
@@ -26,9 +26,9 @@ import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.CommandResult;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.commands.SingleMainCommand;
import me.lucko.luckperms.config.LPConfiguration;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.core.LPConfiguration;
import java.util.List;
@@ -44,14 +44,18 @@ public class InfoCommand extends SingleMainCommand {
final LPConfiguration c = plugin.getConfiguration();
Message.INFO.send(sender,
plugin.getVersion(),
plugin.getType().getFriendlyName(),
plugin.getDatastore().getName(),
c.getServer(),
c.getSyncTime(),
formatBoolean(c.getIncludeGlobalPerms()),
formatBoolean(c.getOnlineMode()),
formatBoolean(c.getApplyWildcards()),
formatBoolean(c.getApplyRegex()),
formatBoolean(c.getApplyShorthand())
formatBoolean(c.isIncludingGlobalPerms()),
formatBoolean(c.isIncludingGlobalWorldPerms()),
formatBoolean(c.isApplyingGlobalGroups()),
formatBoolean(c.isApplyingGlobalWorldGroups()),
formatBoolean(c.isOnlineMode()),
formatBoolean(c.isApplyingWildcards()),
formatBoolean(c.isApplyingRegex()),
formatBoolean(c.isApplyingShorthand())
);
return CommandResult.SUCCESS;
Loaded 100 of 193 files, more files were not shown because too many files have changed in this diff. Show more