Compare commits

...
24 Commits
Author SHA1 Message Date
Luck f1606ac51b API changes for 2.15 2016-11-22 18:27:40 +00:00
Luck d13eb1a55d Fix default assignments never being applied on Bungee 2016-11-21 18:26:37 +00:00
Luck 384fbf5464 Revert: Use faster wildcard parsing method 2016-11-21 17:07:13 +00:00
Luck 4874f9d051 Use faster wildcard parsing method 2016-11-20 20:41:39 +00:00
Luck 51732fa660 Rearrange some packages, general cleanup 2016-11-20 13:44:36 +00:00
Luck bb25632178 Improve info command 2016-11-19 21:56:11 +00:00
Luck 9a2cf82623 Improve user info command 2016-11-19 17:52:39 +00:00
Luck c0734fc29e refactor contexts slightly 2016-11-18 22:39:00 +00:00
Luck c60067e733 Maybe fix zPerms migration & tidy up shorthand parser 2016-11-17 22:02:47 +00:00
Luck 6293634e36 refactor shorthand nodes 2016-11-17 20:50:37 +00:00
Luck a047695a84 Fix issue with nodes never being removed on sync with flatfile storage types 2016-11-17 19:01:58 +00:00
Luck db9d84ed76 Maybe fix issue with corrupted permission migration 2016-11-15 20:18:32 +00:00
Luck e296b1df60 Fix migration commands never being executed 2016-11-15 18:17:35 +00:00
Luck b72e5f5437 Update plugin.yml to make LuckPerms always enable before Vault 2016-11-14 22:50:11 +00:00
Luck de09ae94b8 Fix Vault hook - thanks @Yann151924 2016-11-14 22:32:06 +00:00
Luck b36a33f015 Make meta info command show where meta was inherited from 2016-11-14 20:40:33 +00:00
Luck d95891256b Setup a users calculated data when loaded by the SubjectCollection 2016-11-14 18:55:10 +00:00
Luck 9c8097ecb9 Sponge: Implement support for editing more than just users/groups with commands 2016-11-14 18:45:48 +00:00
Luck 18a3dfd604 cleanup 2016-11-13 19:30:46 +00:00
Luck 59fd337e44 remove debug messages, woops 2016-11-13 11:12:06 +00:00
Luck 696cd235fd Fix meta serialization. Resolves #41 2016-11-13 11:09:57 +00:00
Luck 59c7efccb2 Fix Sponge plugin guice load failure. Thanks @gravityfox 2016-11-13 09:44:34 +00:00
Luck b031ebbffd Update readme 2016-11-12 17:27:15 +00:00
Luck 67415babc2 Fix javadocs & fix compile 2016-11-12 16:25:44 +00:00
100 changed files with 2224 additions and 603 deletions

No files matched your search

+9 -4
View File
@@ -8,10 +8,14 @@ An advanced permissions implementation for Bukkit/Spigot, BungeeCord and Sponge.
* **Wiki** - <https://github.com/lucko/LuckPerms/wiki>
## Description
LuckPerms is an advanced permissions implementation aiming to be a flexible, performant and reliable alternative to other permission systems, providing all the features you could ever possibly need in a permissions plugin, along with an extensive and well documented API for developers.
LuckPerms is an advanced permissions implementation aiming to be a fast, reliable and flexible alternative to existing permission plugins. The project's main goals are centered around high performance and a wide feature set, filling the gaps of functionality and building upon existing features found in other plugins.
* [Spigot Plugin Page](https://www.spigotmc.org/resources/luckperms-an-advanced-permissions-system.28140/ "Spigot Plugin Page")
* [Sponge Plugin Page](https://forums.spongepowered.org/t/luckperms-an-advanced-permissions-system/14274 "Sponge Plugin Page")
LuckPerms also includes an extensive API for developers, and support for a variety of Minecraft server software & data storage options.
See the charts below for a partial list of features & comparison with other providers.
* [Spigot Plugin Release Page](https://www.spigotmc.org/resources/luckperms-an-advanced-permissions-system.28140/ "Spigot Plugin Page")
* [Sponge Plugin Release Page](https://forums.spongepowered.org/t/luckperms-an-advanced-permissions-system/14274 "Sponge Plugin Page")
## LuckPerms vs Other Plugins
### Bukkit
@@ -20,10 +24,11 @@ _Features checked on 23rd Aug 2016. If you find any inaccuracies, please do let
### Sponge
![alt text](https://static.lucko.me/luckperms-compare-sponge.png "Feature comparison")
_Features checked on 8th Oct 2016. If you find any inaccuracies, please do let me know. I tried to be as fair as possible, and copy all major features from the respective plugin pages._
## License
LuckPerms is licensed under the permissive MIT license. See LICENSE.md for more info.
## Thanks to:
## Sponsor
[![JProfiler](https://www.ej-technologies.com/images/product_banners/jprofiler_large.png)](http://www.ej-technologies.com/products/jprofiler/overview.html)
Thanks to ej-technologies for granting LuckPerms an open source licence to their [Java Profiling Software](http://www.ej-technologies.com/products/jprofiler/overview.html "Java Profiler").
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.14-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -32,6 +32,7 @@ import java.util.Map;
* @since 2.11
*/
public class Contexts {
private static final Contexts ALLOW_ALL = new Contexts(ContextSet.empty(), true, true, true, true, true, true);
public static final String SERVER_KEY = "server";
public static final String WORLD_KEY = "world";
@@ -40,7 +41,7 @@ public class Contexts {
* @return a context that will not apply any filters
*/
public static Contexts allowAll() {
return new Contexts(ContextSet.empty(), true, true, true, true, true, true);
return ALLOW_ALL;
}
public static Contexts of(ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
@@ -250,4 +250,12 @@ public interface LuckPermsApi {
*/
void registerContextListener(ContextListener<?> contextListener);
/**
* Gets a calculated context instance for the user using the rules of the platform.
* These values are calculated using the options in the configuration, and the provided calculators.
* @param user the user to get contexts for
* @return an optional containing contexts. Will return empty if the user is not online.
*/
Optional<Contexts> getContextForUser(User user);
}
@@ -61,7 +61,7 @@ public interface Storage {
Executor getSyncExecutor();
/**
* Returns an executor which will run all passed runnables asynchronously using the platforms scheduler & thread pools.
* Returns an executor which will run all passed runnables asynchronously using the platforms scheduler and thread pools.
* @return an executor instance
*/
Executor getAsyncExecutor();
@@ -37,6 +37,7 @@ import java.util.stream.Collectors;
* @since 2.13
*/
public class ContextSet {
private static final ContextSet EMPTY = new ContextSet();
/**
* Make a singleton ContextSet from a context pair
@@ -112,7 +113,7 @@ public class ContextSet {
* @return a new ContextSet
*/
public static ContextSet empty() {
return new ContextSet();
return EMPTY;
}
final Set<Map.Entry<String, String>> contexts;
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.14-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
+2 -2
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.14-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -30,7 +30,7 @@
<dependency>
<groupId>me.lucko.luckperms</groupId>
<artifactId>luckperms-api</artifactId>
<version>2.13-SNAPSHOT</version>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<!-- BukkitAPI -->
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.14-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -29,8 +29,13 @@ import me.lucko.luckperms.bukkit.calculators.AttachmentProcessor;
import me.lucko.luckperms.bukkit.calculators.ChildProcessor;
import me.lucko.luckperms.bukkit.calculators.DefaultsProcessor;
import me.lucko.luckperms.bukkit.inject.Injector;
import me.lucko.luckperms.bukkit.inject.LPPermissible;
import me.lucko.luckperms.common.calculators.*;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.calculators.PermissionCalculator;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import me.lucko.luckperms.common.calculators.processors.MapProcessor;
import me.lucko.luckperms.common.calculators.processors.RegexProcessor;
import me.lucko.luckperms.common.calculators.processors.WildcardProcessor;
import me.lucko.luckperms.common.users.User;
import java.util.UUID;
@@ -24,7 +24,6 @@ package me.lucko.luckperms.bukkit;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Patterns;
@@ -50,7 +49,7 @@ class BukkitCommand extends CommandManager implements CommandExecutor, TabExecut
plugin.getSenderFactory().wrap(sender),
label,
Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(Joiner.on(' ').join(args))),
Callback.empty()
null
);
return true;
}
@@ -23,7 +23,7 @@
package me.lucko.luckperms.bukkit;
import me.lucko.luckperms.bukkit.inject.Injector;
import me.lucko.luckperms.bukkit.inject.LPPermissible;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.AbstractListener;
@@ -35,6 +35,7 @@ import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginEnableEvent;
import java.util.UUID;
@@ -143,4 +144,11 @@ class BukkitListener extends AbstractListener implements Listener {
e.getPlayer().sendMessage(Message.OP_DISABLED.toString());
}
}
@EventHandler
public void onPluginEnable(PluginEnableEvent e) {
if (e.getPlugin().getName().equalsIgnoreCase("Vault")) {
plugin.tryVaultHook(true);
}
}
}
@@ -31,8 +31,8 @@ import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.bukkit.calculators.AutoOPListener;
import me.lucko.luckperms.bukkit.calculators.ChildPermissionProvider;
import me.lucko.luckperms.bukkit.calculators.DefaultsProvider;
import me.lucko.luckperms.bukkit.model.ChildPermissionProvider;
import me.lucko.luckperms.bukkit.model.DefaultsProvider;
import me.lucko.luckperms.bukkit.vault.VaultHook;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.api.ApiProvider;
@@ -47,11 +47,12 @@ import me.lucko.luckperms.common.core.UuidCache;
import me.lucko.luckperms.common.data.Importer;
import me.lucko.luckperms.common.groups.GroupManager;
import me.lucko.luckperms.common.messaging.RedisMessaging;
import me.lucko.luckperms.common.runnables.ExpireTemporaryTask;
import me.lucko.luckperms.common.runnables.UpdateTask;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.storage.StorageFactory;
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
import me.lucko.luckperms.common.tasks.UpdateTask;
import me.lucko.luckperms.common.tracks.TrackManager;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.users.UserManager;
import me.lucko.luckperms.common.utils.BufferedRequest;
import me.lucko.luckperms.common.utils.DebugHandler;
@@ -198,19 +199,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
// Provide vault support
getLog().info("Attempting to hook into Vault...");
try {
if (getServer().getPluginManager().isPluginEnabled("Vault")) {
vaultHook = new VaultHook();
vaultHook.hook(this);
getLog().info("Registered Vault permission & chat hook.");
} else {
getLog().info("Vault not found.");
}
} catch (Exception e) {
getLog().severe("Error occurred whilst hooking into Vault.");
e.printStackTrace();
}
tryVaultHook(false);
// register with the LP API
getLog().info("Registering API...");
@@ -268,6 +257,27 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
}
public void tryVaultHook(boolean force) {
if (vaultHook != null) {
return;
}
getLog().info("Attempting to hook with Vault...");
try {
if (force || getServer().getPluginManager().isPluginEnabled("Vault")) {
vaultHook = new VaultHook();
vaultHook.hook(this);
getLog().info("Registered Vault permission & chat hook.");
} else {
getLog().info("Vault not found.");
}
} catch (Exception e) {
vaultHook = null;
getLog().severe("Error occurred whilst hooking into Vault.");
e.printStackTrace();
}
}
@Override
public void doAsync(Runnable r) {
asyncExecutor.execute(r);
@@ -298,6 +308,28 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
return getDataFolder();
}
@Override
public Player getPlayer(User user) {
return getServer().getPlayer(uuidCache.getExternalUUID(user.getUuid()));
}
@Override
public Contexts getContextForUser(User user) {
Player player = getPlayer(user);
if (player == null) {
return null;
}
return new Contexts(
getContextManager().getApplicableContext(player),
getConfiguration().isIncludingGlobalPerms(),
getConfiguration().isIncludingGlobalWorldPerms(),
true,
getConfiguration().isApplyingGlobalGroups(),
getConfiguration().isApplyingGlobalWorldGroups(),
player.isOp()
);
}
@Override
public int getPlayerCount() {
return getServer().getOnlinePlayers().size();
@@ -395,6 +427,24 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
return contexts;
}
@Override
public LinkedHashMap<String, Object> getExtraInfo() {
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("Vault Enabled", vaultHook != null);
map.put("Vault Server", configuration.getVaultServer());
map.put("Bukkit Defaults count", defaultsProvider.size());
map.put("Bukkit Child Permissions count", childPermissionProvider.getPermissions().size());
map.put("World Cache size", worldCalculator.getWorldCache().size());
map.put("Vault Including Global", configuration.isVaultIncludingGlobal());
map.put("Vault Ignoring World", configuration.isVaultIgnoreWorld());
map.put("Vault Primary Group Overrides", configuration.isVaultPrimaryGroupOverrides());
map.put("Vault Debug", configuration.isVaultDebug());
map.put("OPs Enabled", configuration.isOpsEnabled());
map.put("Auto OP", configuration.isAutoOp());
map.put("Commands Allow OPs", configuration.isCommandsAllowOp());
return map;
}
@Override
public Object getPlugin(String name) {
return getServer().getPluginManager().getPlugin(name);
@@ -24,7 +24,7 @@ package me.lucko.luckperms.bukkit.calculators;
import me.lucko.luckperms.api.context.ContextListener;
import me.lucko.luckperms.bukkit.inject.Injector;
import me.lucko.luckperms.bukkit.inject.LPPermissible;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import org.bukkit.entity.Player;
import java.util.Map;
@@ -24,6 +24,7 @@ package me.lucko.luckperms.bukkit.calculators;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.bukkit.model.ChildPermissionProvider;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import java.util.Map;
@@ -24,6 +24,7 @@ package me.lucko.luckperms.bukkit.calculators;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.bukkit.model.DefaultsProvider;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import org.bukkit.Bukkit;
import org.bukkit.permissions.Permission;
@@ -23,6 +23,7 @@
package me.lucko.luckperms.bukkit.inject;
import lombok.experimental.UtilityClass;
import me.lucko.luckperms.bukkit.model.LPPermissible;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permissible;
@@ -23,33 +23,33 @@
package me.lucko.luckperms.bukkit.migration;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.tracks.Track;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
import org.tyrannyofheaven.bukkit.zPermissions.dao.PermissionService;
import org.tyrannyofheaven.bukkit.zPermissions.model.EntityMetadata;
import org.tyrannyofheaven.bukkit.zPermissions.model.Entry;
import org.tyrannyofheaven.bukkit.zPermissions.model.Inheritance;
import org.tyrannyofheaven.bukkit.zPermissions.model.PermissionEntity;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
public class MigrationZPermissions extends SubCommand<Object> {
public MigrationZPermissions() {
super("zpermissions", "Migration from zPermissions", Permission.MIGRATION, Predicates.alwaysFalse(),
Arg.list(Arg.create("world names...", false, "a list of worlds to migrate permissions from"))
);
super("zpermissions", "Migration from zPermissions", Permission.MIGRATION, Predicates.alwaysFalse(), null);
}
@Override
@@ -66,55 +66,25 @@ public class MigrationZPermissions extends SubCommand<Object> {
return CommandResult.STATE_ERROR;
}
final List<String> worlds = args.stream()
.map(String::toLowerCase)
.collect(Collectors.toList());
PermissionService internalService;
try {
Field psField = service.getClass().getDeclaredField("permissionService");
psField.setAccessible(true);
internalService = (PermissionService) psField.get(service);
} catch (Exception e) {
e.printStackTrace();
return CommandResult.FAILURE;
}
// Migrate all groups
log.info("zPermissions Migration: Starting group migration.");
for (String g : service.getAllGroups()) {
plugin.getStorage().createAndLoadGroup(g.toLowerCase()).join();
Group group = plugin.getGroupManager().get(g.toLowerCase());
try {
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(group).action("create")
.build().submit(plugin);
} catch (Exception ex) {
ex.printStackTrace();
}
for (Map.Entry<String, Boolean> e : service.getGroupPermissions(null, null, g).entrySet()) {
try {
group.setPermission(e.getKey(), e.getValue());
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(group).action("set " + e.getKey() + " " + e.getValue())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
if (worlds != null && !worlds.isEmpty()) {
for (String world : worlds) {
for (Map.Entry<String, Boolean> e : service.getGroupPermissions(world, null, g).entrySet()) {
try {
group.setPermission(e.getKey(), e.getValue(), "global", world);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(group).action("set " + e.getKey() + " true " + e.getValue() + " " + world)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
}
}
PermissionEntity entity = internalService.getEntity(g, null, true);
migrateEntity(group, entity);
plugin.getStorage().saveGroup(group);
}
@@ -124,27 +94,7 @@ public class MigrationZPermissions extends SubCommand<Object> {
for (String t : service.getAllTracks()) {
plugin.getStorage().createAndLoadTrack(t.toLowerCase()).join();
Track track = plugin.getTrackManager().get(t.toLowerCase());
try {
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(track).action("create")
.build().submit(plugin);
} catch (Exception ex) {
ex.printStackTrace();
}
track.setGroups(service.getTrackGroups(t));
for (String group : track.getGroups()) {
try {
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(track).action("append " + group)
.build().submit(plugin);
} catch (Exception ex) {
ex.printStackTrace();
}
}
plugin.getStorage().saveTrack(track);
}
@@ -154,94 +104,10 @@ public class MigrationZPermissions extends SubCommand<Object> {
plugin.getStorage().loadUser(u, "null").join();
User user = plugin.getUserManager().get(u);
for (Map.Entry<String, Boolean> e : service.getPlayerPermissions(null, null, u).entrySet()) {
try {
user.setPermission(e.getKey(), e.getValue());
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("set " + e.getKey() + " " + e.getValue())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
if (worlds != null && !worlds.isEmpty()) {
for (String world : worlds) {
for (Map.Entry<String, Boolean> e : service.getPlayerPermissions(world, null, u).entrySet()) {
try {
user.setPermission(e.getKey(), e.getValue(), "global", world);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("set " + e.getKey() + " true " + e.getValue() + " " + world)
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
}
}
for (String g : service.getPlayerAssignedGroups(u)) {
try {
user.setPermission("group." + g.toLowerCase(), true);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("addgroup " + g.toLowerCase())
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
PermissionEntity entity = internalService.getEntity(null, u, false);
migrateEntity(user, entity);
user.setPrimaryGroup(service.getPlayerPrimaryGroup(u));
try {
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("setprimarygroup " + service.getPlayerPrimaryGroup(u))
.build().submit(plugin);
} catch (Exception ex) {
ex.printStackTrace();
}
String prefix = service.getPlayerPrefix(u);
String suffix = service.getPlayerSuffix(u);
if (prefix != null && !prefix.equals("")) {
prefix = MetaUtils.escapeCharacters(prefix);
try {
user.setPermission("prefix.100." + prefix, true);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("set prefix.100." + prefix + " true")
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
if (suffix != null && !suffix.equals("")) {
suffix = MetaUtils.escapeCharacters(suffix);
try {
user.setPermission("suffix.100." + suffix, true);
LogEntry.build()
.actor(Constants.getConsoleUUID()).actorName(Constants.getConsoleName())
.acted(user).action("set suffix.100." + suffix + " true")
.build().submit(plugin);
} catch (Exception ex) {
if (!(ex instanceof ObjectAlreadyHasException)) {
ex.printStackTrace();
}
}
}
plugin.getUserManager().cleanup(user);
plugin.getStorage().saveUser(user);
@@ -250,4 +116,37 @@ public class MigrationZPermissions extends SubCommand<Object> {
log.info("zPermissions Migration: Success! Completed without any errors.");
return CommandResult.SUCCESS;
}
private void migrateEntity(PermissionHolder group, PermissionEntity entity) {
for (Entry e : entity.getPermissions()) {
if (e.getWorld() != null) {
try {
group.setPermission(e.getPermission(), true, "global", e.getWorld().getName());
} catch (ObjectAlreadyHasException ignored) {}
} else {
try {
group.setPermission(e.getPermission(), true); // TODO handle negated.
} catch (ObjectAlreadyHasException ignored) {}
}
}
for (Inheritance inheritance : entity.getInheritancesAsChild()) {
if (!inheritance.getChild().getId().equals(entity.getId())) {
new Throwable("Illegal inheritance").printStackTrace();
continue;
}
try {
group.setPermission("group." + inheritance.getParent(), true);
} catch (ObjectAlreadyHasException ignored) {}
}
for (EntityMetadata metadata : entity.getMetadata()) {
try {
group.setPermission(NodeFactory.makeMetaNode(metadata.getName(), metadata.getStringValue()).build());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit.calculators;
package me.lucko.luckperms.bukkit.model;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit.calculators;
package me.lucko.luckperms.bukkit.model;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.Tristate;
@@ -102,6 +102,10 @@ public class DefaultsProvider {
return b == null ? Tristate.UNDEFINED : Tristate.fromBoolean(b);
}
public int size() {
return op.size() + nonOp.size();
}
@AllArgsConstructor
private static class DummyPermissible implements Permissible {
private final Runnable onRefresh;
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.bukkit.inject;
package me.lucko.luckperms.bukkit.model;
import lombok.Getter;
import lombok.NonNull;
@@ -28,9 +28,11 @@ import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.caching.MetaData;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import net.milkbowl.vault.chat.Chat;
@@ -83,11 +85,8 @@ public class VaultChatHook extends Chat {
perms.log("Setting meta: '" + node + "' for " + holder.getObjectName() + " on world " + world + ", server " + perms.getServer());
perms.getScheduler().scheduleTask(() -> {
String k = escapeCharacters(node);
String v = escapeCharacters(value);
List<Node> toRemove = holder.getNodes().stream()
.filter(n -> n.isMeta() && n.getMeta().getKey().equals(k))
.filter(n -> n.isMeta() && n.getMeta().getKey().equals(node))
.collect(Collectors.toList());
toRemove.forEach(n -> {
@@ -96,7 +95,7 @@ public class VaultChatHook extends Chat {
} catch (ObjectLacksException ignored) {}
});
Node.Builder metaNode = new NodeBuilder("meta." + k + "." + v).setValue(true);
Node.Builder metaNode = NodeFactory.makeMetaNode(node, value).setValue(true);
if (!perms.getServer().equalsIgnoreCase("global")) {
metaNode.setServer(perms.getServer());
}
@@ -216,7 +215,8 @@ public class VaultChatHook extends Chat {
context.put("world", world);
}
for (Node n : group.getAllNodes(null, new Contexts(ContextSet.fromMap(context), perms.isIncludeGlobal(), true, true, true, true, false))) {
ExtractedContexts ec = ExtractedContexts.generate(new Contexts(ContextSet.fromMap(context), perms.isIncludeGlobal(), true, true, true, true, false));
for (Node n : group.getAllNodes(null, ec)) {
if (!n.getValue()) {
continue;
}
+8 -2
View File
@@ -5,7 +5,12 @@ author: Luck
website: https://github.com/lucko/LuckPerms
main: me.lucko.luckperms.bukkit.LPBukkitPlugin
softdepend: [Vault, PermissionsEx, GroupManager, PowerfulPerms, zPermissions, bPermissions] # For migration
load: STARTUP
# This means that all plugins that (soft-)depend on Vault, depend on LuckPerms too.
# It in turn fixes issues where plugins using Vault cache the provided instance when their plugin enables, or
# when they check for the presence of a service provider, before LuckPerms has enabled.
loadbefore: [Vault]
commands:
luckperms:
@@ -13,4 +18,5 @@ commands:
aliases: [perms, permissions, lp, p, perm]
# Permissions are registered programmatically instead of here.
# Permissions are registered programmatically instead of here.
# See: the last method in me.lucko.luckperms.bukkit.LPBukkitPlugin
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.14-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -25,7 +25,12 @@ package me.lucko.luckperms.bungee;
import com.google.common.collect.ImmutableList;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.common.calculators.*;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.calculators.PermissionCalculator;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import me.lucko.luckperms.common.calculators.processors.MapProcessor;
import me.lucko.luckperms.common.calculators.processors.RegexProcessor;
import me.lucko.luckperms.common.calculators.processors.WildcardProcessor;
import me.lucko.luckperms.common.users.User;
@AllArgsConstructor
@@ -24,7 +24,6 @@ package me.lucko.luckperms.bungee;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Patterns;
@@ -50,7 +49,7 @@ class BungeeCommand extends Command implements TabExecutor {
plugin.getSenderFactory().wrap(sender),
"bperms",
Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(Joiner.on(' ').join(args))),
Callback.empty()
null
);
}
@@ -26,6 +26,7 @@ import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.event.events.UserFirstLoginEvent;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.core.UuidCache;
import me.lucko.luckperms.common.defaults.Rule;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.AbstractListener;
import net.md_5.bungee.api.chat.TextComponent;
@@ -122,6 +123,19 @@ public class BungeeListener extends AbstractListener implements Listener {
if (user == null) {
plugin.getLog().warn("Failed to load user: " + c.getName());
} else {
// Setup defaults for the user
boolean save = false;
for (Rule rule : plugin.getConfiguration().getDefaultAssignments()) {
if (rule.apply(user)) {
save = true;
}
}
// If they were given a default, persist the new assignments back to the storage.
if (save) {
plugin.getStorage().force().saveUser(user).join();
}
user.setupData(false); // Pretty nasty calculation call. Sets up the caching system so data is ready when the user joins.
}
@@ -42,11 +42,12 @@ import me.lucko.luckperms.common.core.UuidCache;
import me.lucko.luckperms.common.data.Importer;
import me.lucko.luckperms.common.groups.GroupManager;
import me.lucko.luckperms.common.messaging.RedisMessaging;
import me.lucko.luckperms.common.runnables.ExpireTemporaryTask;
import me.lucko.luckperms.common.runnables.UpdateTask;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.storage.StorageFactory;
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
import me.lucko.luckperms.common.tasks.UpdateTask;
import me.lucko.luckperms.common.tracks.TrackManager;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.users.UserManager;
import me.lucko.luckperms.common.utils.BufferedRequest;
import me.lucko.luckperms.common.utils.DebugHandler;
@@ -213,6 +214,28 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
return getDataFolder();
}
@Override
public ProxiedPlayer getPlayer(User user) {
return getProxy().getPlayer(uuidCache.getExternalUUID(user.getUuid()));
}
@Override
public Contexts getContextForUser(User user) {
ProxiedPlayer player = getPlayer(user);
if (player == null) {
return null;
}
return new Contexts(
getContextManager().getApplicableContext(player),
getConfiguration().isIncludingGlobalPerms(),
getConfiguration().isIncludingGlobalWorldPerms(),
true,
getConfiguration().isApplyingGlobalGroups(),
getConfiguration().isApplyingGlobalWorldGroups(),
false
);
}
@Override
public int getPlayerCount() {
return getProxy().getOnlineCount();
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.14-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -27,6 +27,7 @@ import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.common.api.ApiProvider;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.commands.BaseCommand;
import me.lucko.luckperms.common.commands.ConsecutiveExecutor;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.config.LPConfiguration;
@@ -38,15 +39,14 @@ import me.lucko.luckperms.common.groups.GroupManager;
import me.lucko.luckperms.common.messaging.RedisMessaging;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.tracks.TrackManager;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.users.UserManager;
import me.lucko.luckperms.common.utils.BufferedRequest;
import me.lucko.luckperms.common.utils.DebugHandler;
import me.lucko.luckperms.common.utils.LocaleManager;
import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.Executor;
/**
@@ -203,6 +203,21 @@ public interface LuckPermsPlugin {
return isOnline(external) ? Message.PLAYER_ONLINE : Message.PLAYER_OFFLINE;
}
/**
* Gets a player object linked to this User. The returned object must be the same type
* as the instance used in the platforms {@link ContextManager}
* @param user the user instance
* @return a player object, or null, if one couldn't be found.
*/
Object getPlayer(User user);
/**
* Gets a calculated context instance for the user using the rules of the platform.
* @param user the user instance
* @return a contexts object, or null if one couldn't be generated
*/
Contexts getContextForUser(User user);
/**
* Gets the number of users online on the platform
* @return the number of users
@@ -247,6 +262,18 @@ public interface LuckPermsPlugin {
*/
Set<Contexts> getPreProcessContexts(boolean op);
default List<BaseCommand> getExtraCommands() {
return Collections.emptyList();
}
/**
* Gets a map of extra information to be shown in the info command
* @return a map of options, or null
*/
default LinkedHashMap<String, Object> getExtraInfo() {
return null;
}
/**
* Gets a set of players ignoring logging output
* @return a {@link Set} of {@link UUID}s
@@ -71,7 +71,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public double getApiVersion() {
return 2.14;
return 2.15;
}
@Override
@@ -159,7 +159,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public void cleanupUser(@NonNull User user) {
me.lucko.luckperms.common.api.internal.Utils.checkUser(user);
Utils.checkUser(user);
plugin.getUserManager().cleanup(((UserLink) user).getMaster());
}
@@ -221,4 +221,10 @@ public class ApiProvider implements LuckPermsApi {
public void registerContextListener(ContextListener<?> contextListener) {
plugin.getContextManager().registerListener(contextListener);
}
@Override
public Optional<Contexts> getContextForUser(User user) {
Utils.checkUser(user);
return Optional.ofNullable(plugin.getContextForUser(((UserLink) user).getMaster()));
}
}
@@ -26,6 +26,7 @@ import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.api.*;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
@@ -40,8 +41,6 @@ import static me.lucko.luckperms.common.core.PermissionHolder.exportToLegacy;
@SuppressWarnings("unused")
@AllArgsConstructor
public class PermissionHolderLink implements PermissionHolder {
@NonNull
private final me.lucko.luckperms.common.core.PermissionHolder master;
@Override
@@ -66,17 +65,17 @@ public class PermissionHolderLink implements PermissionHolder {
@Override
public Set<Node> getAllNodes() {
return Collections.unmodifiableSet(master.getAllNodes(null, Contexts.allowAll()));
return Collections.unmodifiableSet(master.getAllNodes(null, ExtractedContexts.generate(Contexts.allowAll())));
}
@Override
public SortedSet<LocalizedNode> getAllNodes(@NonNull Contexts contexts) {
return master.getAllNodes(null, contexts);
return master.getAllNodes(null, ExtractedContexts.generate(contexts));
}
@Override
public Set<LocalizedNode> getAllNodesFiltered(@NonNull Contexts contexts) {
return master.getAllNodesFiltered(contexts);
return master.getAllNodesFiltered(ExtractedContexts.generate(contexts));
}
@Override
@@ -36,6 +36,7 @@ import me.lucko.luckperms.api.caching.PermissionData;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import java.util.Set;
@@ -78,7 +79,7 @@ public class UserCache implements UserData {
@Override
public ListenableFuture<MetaCache> reload(Contexts contexts, MetaCache oldData) {
oldData.loadMeta(user.accumulateMeta(null, null, contexts));
oldData.loadMeta(user.accumulateMeta(null, null, ExtractedContexts.generate(contexts)));
return Futures.immediateFuture(oldData);
}
});
@@ -103,7 +104,7 @@ public class UserCache implements UserData {
@Override
public MetaCache calculateMeta(@NonNull Contexts contexts) {
MetaCache data = new MetaCache();
data.loadMeta(user.accumulateMeta(null, null, contexts));
data.loadMeta(user.accumulateMeta(null, null, ExtractedContexts.generate(contexts)));
return data;
}
@@ -20,9 +20,10 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.calculators;
package me.lucko.luckperms.common.calculators.processors;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import java.util.Map;
@@ -20,9 +20,10 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.calculators;
package me.lucko.luckperms.common.calculators.processors;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import me.lucko.luckperms.common.constants.Patterns;
import java.util.Map;
@@ -20,9 +20,10 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.calculators;
package me.lucko.luckperms.common.calculators.processors;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import java.util.Map;
@@ -23,9 +23,7 @@
package me.lucko.luckperms.common.commands;
import com.google.common.collect.ImmutableList;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.group.CreateGroup;
import me.lucko.luckperms.common.commands.group.DeleteGroup;
@@ -49,36 +47,43 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@AllArgsConstructor
public class CommandManager {
@Getter
private final LuckPermsPlugin plugin;
@Getter
private final List<BaseCommand> mainCommands = ImmutableList.<BaseCommand>builder()
.add(new UserMainCommand())
.add(new GroupMainCommand())
.add(new TrackMainCommand())
.add(new LogMainCommand())
.add(new SyncCommand())
.add(new NetworkSyncCommand())
.add(new InfoCommand())
.add(new DebugCommand())
.add(new VerboseCommand())
.add(new ImportCommand())
.add(new ExportCommand())
.add(new QueueCommand())
.add(new MigrationMainCommand())
.add(new UsersBulkEditMainCommand())
.add(new CreateGroup())
.add(new DeleteGroup())
.add(new ListGroups())
.add(new CreateTrack())
.add(new DeleteTrack())
.add(new ListTracks())
.build();
private final List<BaseCommand> mainCommands;
public CommandManager(LuckPermsPlugin plugin) {
this.plugin = plugin;
ImmutableList.Builder<BaseCommand> l = ImmutableList.builder();
l.add(new UserMainCommand())
.add(new GroupMainCommand())
.add(new TrackMainCommand())
.addAll(plugin.getExtraCommands())
.add(new LogMainCommand())
.add(new SyncCommand())
.add(new NetworkSyncCommand())
.add(new InfoCommand())
.add(new VerboseCommand())
.add(new ImportCommand())
.add(new ExportCommand())
.add(new QueueCommand())
.add(new MigrationMainCommand())
.add(new UsersBulkEditMainCommand())
.add(new CreateGroup())
.add(new DeleteGroup())
.add(new ListGroups())
.add(new CreateTrack())
.add(new DeleteTrack())
.add(new ListTracks());
mainCommands = l.build();
}
/**
* Generic on command method to be called from the command executor object of the platform
@@ -88,10 +93,12 @@ public class CommandManager {
* @param args the arguments provided
* @param result the callback to be called when the command has fully executed
*/
public void onCommand(Sender sender, String label, List<String> args, Callback<CommandResult> result) {
public void onCommand(Sender sender, String label, List<String> args, Consumer<CommandResult> result) {
plugin.doAsync(() -> {
CommandResult r = onCommand(sender, label, args);
plugin.doSync(() -> result.onComplete(r));
if (result != null) {
plugin.doSync(() -> result.accept(r));
}
});
}
@@ -274,6 +281,10 @@ public class CommandManager {
break;
// Provide backwards compatibility
case "setprimarygroup":
args.remove(2);
args.add(2, "switchprimarygroup");
break;
case "listnodes":
args.remove(2);
args.add(2, "permission");
@@ -344,6 +355,8 @@ public class CommandManager {
case "removetempsuffix":
args.add(2, "meta");
break;
default:
break;
}
// Provide lazy set rewrite
@@ -23,7 +23,6 @@
package me.lucko.luckperms.common.commands;
import lombok.Getter;
import lombok.NonNull;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.Util;
@@ -42,7 +41,7 @@ public abstract class MainCommand<T> extends BaseCommand<Void, T> {
private final String usage;
private final int minArgs; // equals 1 if the command doesn't take a mid argument, e.g. /lp user <USER> sub-command....
public MainCommand(String name, String description, String usage, int minArgs, @NonNull List<Command<T, ?>> children) {
public MainCommand(String name, String description, String usage, int minArgs, List<Command<T, ?>> children) {
super(name, description, null, Predicates.alwaysFalse(), null, children);
this.usage = usage;
this.minArgs = minArgs;
@@ -85,7 +84,6 @@ public abstract class MainCommand<T> extends BaseCommand<Void, T> {
T t = getTarget(name, plugin, sender);
if (t != null) {
CommandResult result;
try {
result = sub.execute(plugin, sender, t, strippedArgs, label);
} catch (CommandException e) {
@@ -50,15 +50,15 @@ public abstract class SingleCommand extends BaseCommand<Void, Void> {
@Override
public void sendUsage(Sender sender, String label) {
String usage = "";
StringBuilder sb = new StringBuilder();
if (getArgs().isPresent()) {
usage += "&3 - &7";
sb.append("&3 - &7");
for (Arg arg : getArgs().get()) {
usage += arg.asPrettyString() + " ";
sb.append(arg.asPrettyString()).append(" ");
}
}
Util.sendPluginMessage(sender, "&3> &a" + getName().toLowerCase() + usage);
Util.sendPluginMessage(sender, "&3> &a" + getName().toLowerCase() + sb.toString());
}
@Override
@@ -55,15 +55,15 @@ public abstract class SubCommand<T> extends Command<T, Void> {
*/
@Override
public void sendUsage(Sender sender, String label) {
String usage = "";
StringBuilder sb = new StringBuilder();
if (getArgs().isPresent()) {
usage += "&3 - &7";
sb.append("&3 - &7");
for (Arg arg : getArgs().get()) {
usage += arg.asPrettyString() + " ";
sb.append(arg.asPrettyString()).append(" ");
}
}
Util.sendPluginMessage(sender, "&3> &a" + getName().toLowerCase() + usage);
Util.sendPluginMessage(sender, "&3> &a" + getName().toLowerCase() + sb.toString());
}
@Override
@@ -75,15 +75,15 @@ public abstract class SharedSubCommand {
}
public void sendUsage(Sender sender) {
String usage = "";
StringBuilder sb = new StringBuilder();
if (args != null) {
usage += "&3 - &7";
sb.append("&3 - &7");
for (Arg arg : args) {
usage += arg.asPrettyString() + " ";
sb.append(arg.asPrettyString()).append(" ");
}
}
Util.sendPluginMessage(sender, "&3> &a" + getName() + usage);
Util.sendPluginMessage(sender, "&3> &a" + getName() + sb.toString());
}
public void sendDetailedUsage(Sender sender) {
@@ -23,7 +23,7 @@
package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
@@ -33,6 +33,7 @@ import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.*;
@@ -44,12 +45,12 @@ public class MetaInfo extends SharedSubCommand {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
SortedSet<Map.Entry<Integer, Node>> prefixes = new TreeSet<>(Util.META_COMPARATOR.reversed());
SortedSet<Map.Entry<Integer, Node>> suffixes = new TreeSet<>(Util.META_COMPARATOR.reversed());
Set<Node> meta = new HashSet<>();
SortedSet<Map.Entry<Integer, LocalizedNode>> prefixes = new TreeSet<>(Util.META_COMPARATOR.reversed());
SortedSet<Map.Entry<Integer, LocalizedNode>> suffixes = new TreeSet<>(Util.META_COMPARATOR.reversed());
Set<LocalizedNode> meta = new HashSet<>();
// Collect data
for (Node node : holder.getAllNodes(null, Contexts.allowAll())) {
for (LocalizedNode node : holder.getAllNodes(null, ExtractedContexts.generate(Contexts.allowAll()))) {
if (!node.isSuffix() && !node.isPrefix() && !node.isMeta()) {
continue;
}
@@ -67,12 +68,13 @@ public class MetaInfo extends SharedSubCommand {
Message.CHAT_META_PREFIX_NONE.send(sender, holder.getFriendlyName());
} else {
Message.CHAT_META_PREFIX_HEADER.send(sender, holder.getFriendlyName());
for (Map.Entry<Integer, Node> e : prefixes) {
for (Map.Entry<Integer, LocalizedNode> e : prefixes) {
String location = processLocation(e.getValue(), holder);
if (e.getValue().isServerSpecific() || e.getValue().isWorldSpecific() || !e.getValue().getContexts().isEmpty()) {
String context = Util.getNodeContextDescription(e.getValue());
Message.CHAT_META_ENTRY_WITH_CONTEXT.send(sender, e.getKey(), e.getValue().getPrefix().getValue(), context);
Message.CHAT_META_ENTRY_WITH_CONTEXT.send(sender, e.getKey(), e.getValue().getPrefix().getValue(), location, context);
} else {
Message.CHAT_META_ENTRY.send(sender, e.getKey(), e.getValue().getPrefix().getValue());
Message.CHAT_META_ENTRY.send(sender, e.getKey(), e.getValue().getPrefix().getValue(), location);
}
}
}
@@ -81,12 +83,13 @@ public class MetaInfo extends SharedSubCommand {
Message.CHAT_META_SUFFIX_NONE.send(sender, holder.getFriendlyName());
} else {
Message.CHAT_META_SUFFIX_HEADER.send(sender, holder.getFriendlyName());
for (Map.Entry<Integer, Node> e : suffixes) {
for (Map.Entry<Integer, LocalizedNode> e : suffixes) {
String location = processLocation(e.getValue(), holder);
if (e.getValue().isServerSpecific() || e.getValue().isWorldSpecific() || !e.getValue().getContexts().isEmpty()) {
String context = Util.getNodeContextDescription(e.getValue());
Message.CHAT_META_ENTRY_WITH_CONTEXT.send(sender, e.getKey(), e.getValue().getSuffix().getValue(), context);
Message.CHAT_META_ENTRY_WITH_CONTEXT.send(sender, e.getKey(), e.getValue().getSuffix().getValue(), location, context);
} else {
Message.CHAT_META_ENTRY.send(sender, e.getKey(), e.getValue().getSuffix().getValue());
Message.CHAT_META_ENTRY.send(sender, e.getKey(), e.getValue().getSuffix().getValue(), location);
}
}
}
@@ -95,16 +98,21 @@ public class MetaInfo extends SharedSubCommand {
Message.META_NONE.send(sender, holder.getFriendlyName());
} else {
Message.META_HEADER.send(sender, holder.getFriendlyName());
for (Node m : meta) {
for (LocalizedNode m : meta) {
String location = processLocation(m, holder);
if (m.isServerSpecific() || m.isWorldSpecific() || !m.getContexts().isEmpty()) {
String context = Util.getNodeContextDescription(m);
Message.META_ENTRY_WITH_CONTEXT.send(sender, m.getMeta().getKey(), m.getMeta().getValue(), context);
Message.META_ENTRY_WITH_CONTEXT.send(sender, m.getMeta().getKey(), m.getMeta().getValue(), location, context);
} else {
Message.META_ENTRY.send(sender, m.getMeta().getKey(), m.getMeta().getValue());
Message.META_ENTRY.send(sender, m.getMeta().getKey(), m.getMeta().getValue(), location);
}
}
}
return CommandResult.SUCCESS;
}
private static String processLocation(LocalizedNode node, PermissionHolder holder) {
return node.getLocation().equalsIgnoreCase(holder.getObjectName()) ? "self" : node.getLocation();
}
}
@@ -22,7 +22,6 @@
package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
@@ -34,7 +33,7 @@ import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.Predicates;
@@ -57,14 +56,13 @@ public class MetaSet extends SharedSubCommand {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
String key = MetaUtils.escapeCharacters(args.get(0));
String value = MetaUtils.escapeCharacters(args.get(1));
String key = args.get(0);
String value = args.get(1);
String node = "meta." + key + "." + value;
String server = ArgumentUtils.handleServer(2, args);
String world = ArgumentUtils.handleWorld(3, args);
Node n = new NodeBuilder(node).setServer(server).setWorld(world).build();
Node n = NodeFactory.makeMetaNode(key, value).setServer(server).setWorld(world).build();
if (holder.hasPermission(n).asBoolean()) {
Message.ALREADY_HAS_META.send(sender, holder.getFriendlyName());
@@ -22,7 +22,6 @@
package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
@@ -34,7 +33,7 @@ import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.utils.DateUtil;
@@ -59,14 +58,13 @@ public class MetaSetTemp extends SharedSubCommand {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
String key = MetaUtils.escapeCharacters(args.get(0));
String value = MetaUtils.escapeCharacters(args.get(1));
String key = args.get(0);
String value = args.get(1);
long duration = ArgumentUtils.handleDuration(2, args);
String node = "meta." + key + "." + value;
String server = ArgumentUtils.handleServer(3, args);
String world = ArgumentUtils.handleWorld(4, args);
Node n = new NodeBuilder(node).setServer(server).setWorld(world).setExpiry(duration).build();
Node n = NodeFactory.makeMetaNode(key, value).setServer(server).setWorld(world).setExpiry(duration).build();
if (holder.hasPermission(n).asBoolean()) {
Message.ALREADY_HAS_META.send(sender, holder.getFriendlyName());
@@ -22,7 +22,6 @@
package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
@@ -54,7 +53,7 @@ public class MetaUnset extends SharedSubCommand {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
String key = MetaUtils.escapeCharacters(args.get(0));
String key = args.get(0);
String server = ArgumentUtils.handleServer(1, args);
String world = ArgumentUtils.handleWorld(2, args);
@@ -22,7 +22,6 @@
package me.lucko.luckperms.common.commands.generic.meta;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
@@ -54,7 +53,7 @@ public class MetaUnsetTemp extends SharedSubCommand {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List<String> args) throws CommandException {
String key = MetaUtils.escapeCharacters(args.get(0));
String key = args.get(0);
String server = ArgumentUtils.handleServer(1, args);
String world = ArgumentUtils.handleWorld(2, args);
@@ -70,17 +70,13 @@ public class PermissionCheckInherits extends SharedSubCommand {
break;
}
String location = null;
if (result.getLocation().isPresent()) {
if (result.getLocation().get().equals(holder.getObjectName())) {
location = "self";
} else {
location = result.getLocation().get();
}
String location = result.getLocation().orElse(null);
if (location != null && location.equalsIgnoreCase(holder.getObjectName())) {
location = "self";
}
Util.sendPluginMessage(sender, "&b" + node + ": " + Util.formatTristate(result.getResult()) +
(result.getLocation().isPresent() ? " &7(inherited from &a" + location + "&7)" : ""));
(location != null ? " &7(inherited from &a" + location + "&7)" : ""));
return CommandResult.SUCCESS;
}
}
@@ -98,7 +98,7 @@ public class LogRecent extends SubCommand<Log> {
return showLog(p, uuid, sender, log);
} catch (NumberFormatException e) {
// Invalid page
return showLog(-1, null, null, null);
return showLog(-1, null, sender, log);
}
}
@@ -116,7 +116,7 @@ public class LogRecent extends SubCommand<Log> {
return showLog(p, u, sender, log);
} catch (NumberFormatException e) {
// Invalid page
return showLog(-1, null, null, null);
return showLog(-1, null, sender, log);
}
}
}
@@ -62,7 +62,7 @@ public class LogUserHistory extends SubCommand<Log> {
page = Integer.parseInt(args.get(1));
} catch (NumberFormatException e) {
// invalid page
return showLog(-1, null, null, null);
return showLog(-1, null, sender, log);
}
}
@@ -22,7 +22,6 @@
package me.lucko.luckperms.common.commands.migration;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.*;
import me.lucko.luckperms.common.commands.sender.Sender;
@@ -32,13 +31,17 @@ import me.lucko.luckperms.common.constants.Message;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class MigrationMainCommand extends MainCommand<Object> {
private List<Command<Object, ?>> commands = null;
public MigrationMainCommand() {
super("Migration", "Migration commands", "/%s migration", 1, ImmutableList.copyOf(getAvailableCommands()));
super("Migration", "Migration commands", "/%s migration", 1, null);
}
@SuppressWarnings("unchecked")
private static List<Command<Object, ?>> getAvailableCommands() {
List<SubCommand<Object>> l = new ArrayList<>();
@@ -85,6 +88,22 @@ public class MigrationMainCommand extends MainCommand<Object> {
return l.stream().collect(Collectors.toList());
}
@SuppressWarnings("deprecation")
@Deprecated
@Override
public synchronized Optional<List<Command<Object, ?>>> getChildren() {
if (commands == null) {
commands = getAvailableCommands();
}
return Optional.of(commands);
}
@SuppressWarnings("deprecation")
public List<Command<Object, ?>> getSubCommands() {
return getChildren().orElse(null);
}
@Override
public boolean isAuthorized(Sender sender) {
return sender.getUuid().equals(Constants.getConsoleUUID());
@@ -106,8 +125,8 @@ public class MigrationMainCommand extends MainCommand<Object> {
}
@Override
protected Void getTarget(String target, LuckPermsPlugin plugin, Sender sender) {
return null;
protected Object getTarget(String target, LuckPermsPlugin plugin, Sender sender) {
return new Object();
}
@Override
@@ -26,12 +26,15 @@ import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SingleCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.config.LPConfiguration;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static me.lucko.luckperms.common.commands.utils.Util.formatBoolean;
@@ -49,16 +52,49 @@ public class InfoCommand extends SingleCommand {
plugin.getStorage().getName(),
c.getServer(),
c.getSyncTime(),
plugin.getPlayerCount(),
plugin.getUserManager().getAll().size(),
plugin.getGroupManager().getAll().size(),
plugin.getTrackManager().getAll().size(),
plugin.getStorage().getLog().join().getContent().size(),
plugin.getUuidCache().getSize(),
plugin.getLocaleManager().getSize(),
plugin.getPreProcessContexts(false).size(),
plugin.getContextManager().getCalculatorsSize(),
formatBoolean(c.isOnlineMode()),
formatBoolean(c.isRedisEnabled()),
formatBoolean(c.isIncludingGlobalPerms()),
formatBoolean(c.isIncludingGlobalWorldPerms()),
formatBoolean(c.isApplyingGlobalGroups()),
formatBoolean(c.isApplyingGlobalWorldGroups()),
formatBoolean(c.isOnlineMode()),
formatBoolean(c.isApplyingWildcards()),
formatBoolean(c.isApplyingRegex()),
formatBoolean(c.isApplyingShorthand())
);
LinkedHashMap<String, Object> platformInfo = plugin.getExtraInfo();
if (platformInfo == null || platformInfo.isEmpty()) {
return CommandResult.SUCCESS;
}
Message.EMPTY.send(sender, "&f- &bPlatform Info:");
for (Map.Entry<String, Object> e : platformInfo.entrySet()) {
Message.EMPTY.send(sender, "&f- &3" + e.getKey() + ": " + formatValue(e.getValue().toString()));
}
return CommandResult.SUCCESS;
}
private static String formatValue(String value) {
if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
return Util.formatBoolean(Boolean.parseBoolean(value));
}
try {
int i = Integer.parseInt(value);
return "&a" + i;
} catch (NumberFormatException ignored) {}
return "&f" + value;
}
}
@@ -22,35 +22,93 @@
package me.lucko.luckperms.common.commands.user;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.caching.MetaData;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class UserInfo extends SubCommand<User> {
public UserInfo() {
super("info", "Shows info about the user", Permission.USER_INFO, Predicates.alwaysFalse(), null);
}
@SuppressWarnings("unchecked")
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) throws CommandException {
Message.USER_INFO.send(sender,
Message.USER_INFO_GENERAL.send(sender,
user.getName(),
user.getUuid(),
plugin.getPlayerStatus(user.getUuid()),
user.getPrimaryGroup(),
user.getPermanentNodes().size(),
user.getTemporaryNodes().size(),
label,
user.getName()
user.getPrefixNodes().size(),
user.getSuffixNodes().size(),
user.getMetaNodes().size()
);
Set<Node> parents = user.getPermissions(false).stream()
.filter(Node::isGroupNode)
.filter(Node::isPermanent)
.collect(Collectors.toSet());
Set<Node> tempParents = user.getPermissions(false).stream()
.filter(Node::isGroupNode)
.filter(Node::isTemporary)
.collect(Collectors.toSet());
if (!parents.isEmpty()) {
Message.USER_INFO_PARENT_HEADER.send(sender);
for (Node node : parents) {
Message.EMPTY.send(sender, "&f- &3> &f" + node.getGroupName() + Util.getNodeContextDescription(node));
}
}
if (!tempParents.isEmpty()) {
Message.USER_INFO_TEMP_PARENT_HEADER.send(sender);
for (Node node : tempParents) {
Message.EMPTY.send(sender, "&f- &3> &f" + node.getGroupName() + Util.getNodeContextDescription(node));
Message.EMPTY.send(sender, "&f- &2- expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()));
}
}
UserData data = user.getUserData();
String context = "&bNone";
String prefix = "&bNone";
String suffix = "&bNone";
if (data != null) {
Contexts contexts = plugin.getContextForUser(user);
if (contexts != null) {
context = contexts.getContexts().toSet().stream()
.map(e -> Util.contextToString(e.getKey(), e.getValue()))
.collect(Collectors.joining(" "));
MetaData meta = data.getMetaData(contexts);
if (meta.getPrefix() != null) {
prefix = "&f\"" + meta.getPrefix() + "&f\"";
}
if (meta.getSuffix() != null) {
suffix = "&f\"" + meta.getSuffix() + "&f\"";
}
}
}
Message.USER_INFO_DATA.send(sender, Util.formatBoolean(data != null), context, prefix, suffix);
return CommandResult.SUCCESS;
}
}
@@ -47,7 +47,7 @@ public class UserMainCommand extends MainCommand<User> {
.add(new CommandParent<>(true))
.add(new CommandMeta<>(true))
.add(new UserGetUUID())
.add(new UserSetPrimaryGroup())
.add(new UserSwitchPrimaryGroup())
.add(new UserPromote())
.add(new UserDemote())
.add(new HolderShowTracks<>(true))
@@ -38,10 +38,10 @@ import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import java.util.List;
public class UserSetPrimaryGroup extends SubCommand<User> {
public UserSetPrimaryGroup() {
super("setprimarygroup", "Sets the user's primary group", Permission.USER_SETPRIMARYGROUP, Predicates.not(1),
Arg.list(Arg.create("group", true, "the group to set as the primary group"))
public class UserSwitchPrimaryGroup extends SubCommand<User> {
public UserSwitchPrimaryGroup() {
super("switchprimarygroup", "Switches the user's primary group", Permission.USER_SWITCHPRIMARYGROUP, Predicates.not(1),
Arg.list(Arg.create("group", true, "the group to switch to"))
);
}
@@ -24,6 +24,8 @@ package me.lucko.luckperms.common.commands.utils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.utils.ArgumentChecker;
import me.lucko.luckperms.common.utils.DateUtil;
@@ -112,6 +114,33 @@ public class ArgumentUtils {
}
}
public static ContextSet handleContexts(int fromIndex, List<String> args) {
if (args.size() <= fromIndex) {
return ContextSet.empty();
}
MutableContextSet contextSet = new MutableContextSet();
List<String> toQuery = args.subList(fromIndex, args.size());
for (String s : toQuery) {
int index = s.indexOf('=');
if (index != -1) {
String key = s.substring(0, index);
if (key.equals("")) {
continue;
}
String value = s.substring(index + 1);
if (value.equals("")) {
continue;
}
contextSet.add(key, value);
}
}
return contextSet.makeImmutable();
}
public static abstract class ArgumentException extends CommandException {}
public static class DetailedUsageException extends ArgumentException {}
public static class UseInheritException extends ArgumentException {}
@@ -240,10 +240,10 @@ public class Util {
}
public static final MetaComparator META_COMPARATOR = new MetaComparator();
public class MetaComparator implements Comparator<Map.Entry<Integer, Node>> {
public class MetaComparator implements Comparator<Map.Entry<Integer, ? extends Node>> {
@Override
public int compare(Map.Entry<Integer, Node> o1, Map.Entry<Integer, Node> o2) {
public int compare(Map.Entry<Integer, ? extends Node> o1, Map.Entry<Integer, ? extends Node> o2) {
int result = Integer.compare(o1.getKey(), o2.getKey());
return result != 0 ? result : 1;
}
@@ -122,26 +122,30 @@ public enum Message {
"{PREFIX}&f- &3Platform: &f{1}" + "\n" +
"{PREFIX}&f- &3Storage Method: &f{2}" + "\n" +
"{PREFIX}&f- &3Server Name: &f{3}" + "\n" +
"{PREFIX}&f- &3Sync Interval: &f{4} minutes" + "\n" +
"{PREFIX}&f- &3Include Global: &f{5}" + "\n" +
"{PREFIX}&f- &3Include Global World: &f{6}" + "\n" +
"{PREFIX}&f- &3Apply Global Groups: &f{7}" + "\n" +
"{PREFIX}&f- &3Apply Global World Groups: &f{8}" + "\n" +
"{PREFIX}&f- &3Online Mode: &f{9}" + "\n" +
"{PREFIX}&f- &3Apply Wildcards: &f{10}" + "\n" +
"{PREFIX}&f- &3Apply Regex: &f{11}" + "\n" +
"{PREFIX}&f- &3Apply Shorthand: &f{12}",
"{PREFIX}&f- &3Sync Interval: &a{4} &fminutes" + "\n" +
"{PREFIX}&f- &bCounts:" + "\n" +
"{PREFIX}&f- &3Online Players: &a{5}" + "\n" +
"{PREFIX}&f- &3Loaded Users: &a{6}" + "\n" +
"{PREFIX}&f- &3Loaded Groups: &a{7}" + "\n" +
"{PREFIX}&f- &3Loaded Tracks: &a{8}" + "\n" +
"{PREFIX}&f- &3Log size: &a{9}" + "\n" +
"{PREFIX}&f- &3UUID Cache size: &a{10}" + "\n" +
"{PREFIX}&f- &3Translations loaded: &a{11}" + "\n" +
"{PREFIX}&f- &3Pre-process contexts: &a{12}" + "\n" +
"{PREFIX}&f- &3Context Calculators: &a{13}" + "\n" +
"{PREFIX}&f- &bConfiguration:" + "\n" +
"{PREFIX}&f- &3Online Mode: {14}" + "\n" +
"{PREFIX}&f- &3Redis Enabled: {15}" + "\n" +
"{PREFIX}&f- &bPermission Calculation:" + "\n" +
"{PREFIX}&f- &3Including Global: {16}" + "\n" +
"{PREFIX}&f- &3Including Global World: {17}" + "\n" +
"{PREFIX}&f- &3Applying Global Groups: {18}" + "\n" +
"{PREFIX}&f- &3Applying Global World Groups: {19}" + "\n" +
"{PREFIX}&f- &3Applying Wildcards: {20}" + "\n" +
"{PREFIX}&f- &3Applying Regex: {21}" + "\n" +
"{PREFIX}&f- &3Applying Shorthand: {22}",
false
),
DEBUG(
"{PREFIX}&d&l> &dDebug Info" + "\n" +
"{PREFIX}&f> &3Online Players: &f{0}" + "\n" +
"{PREFIX}&f> &3Loaded Users: &f{1}" + "\n" +
"{PREFIX}&f> &3Loaded Groups: &f{2}" + "\n" +
"{PREFIX}&f> &3Loaded Tracks: &f{3}",
false
),
CREATE_GROUP_ERROR("There was an error whilst creating the group.", true),
DELETE_GROUP_ERROR("There was an error whilst deleting the group.", true),
DELETE_GROUP_ERROR_DEFAULT("You cannot delete the default group.", true),
@@ -199,10 +203,10 @@ public enum Message {
CHAT_META_PREFIX_HEADER("&b{0}'s Prefixes", true),
CHAT_META_SUFFIX_HEADER("&b{0}'s Suffixes", true),
META_HEADER("&b{0}'s Meta", true),
CHAT_META_ENTRY("&b-> {0} &f- &f\"{1}&f\"", true),
CHAT_META_ENTRY_WITH_CONTEXT("&b-> {0} &f- &f\"{1}&f\"{2}", true),
META_ENTRY("&b-> &a{0} &f= &f\"{1}&f\"", true),
META_ENTRY_WITH_CONTEXT("&b-> &a{0} &f= &f\"{1}&f\"{2}", true),
CHAT_META_ENTRY("&b-> {0} &f- &f\"{1}&f\" &8(&7inherited from &a{2}&8)", true),
CHAT_META_ENTRY_WITH_CONTEXT("&b-> {0} &f- &f\"{1}&f\" &8(&7inherited from &a{2}&8){3}", true),
META_ENTRY("&b-> &a{0} &f= &f\"{1}&f\" &8(&7inherited from &a{2}&8)", true),
META_ENTRY_WITH_CONTEXT("&b-> &a{0} &f= &f\"{1}&f\" &8(&7inherited from &a{2}&8){3}", true),
CHAT_META_PREFIX_NONE("&b{0} has no prefixes.", true),
CHAT_META_SUFFIX_NONE("&b{0} has no suffixes.", true),
META_NONE("&b{0} has no meta.", true),
@@ -260,16 +264,31 @@ public enum Message {
BULK_CHANGE_TYPE_ERROR("Invalid type. Was expecting 'server' or 'world'.", true),
BULK_CHANGE_SUCCESS("&aApplied bulk change successfully. {0} records were changed.", true),
USER_INFO(
USER_INFO_GENERAL(
"{PREFIX}&b&l> &bUser Info: &f{0}" + "\n" +
"{PREFIX}&f- &3UUID: &f{1}" + "\n" +
"{PREFIX}&f- &3Status: {2}" + "\n" +
"{PREFIX}&f- &3Primary Group: &f{3}" + "\n" +
"{PREFIX}&f- &3Permissions: &f{4}" + "\n" +
"{PREFIX}&f- &3Temporary Permissions: &f{5}" + "\n" +
"{PREFIX}&f- &3Use &b/{6} user {7} permission info &3to see all permissions.",
"{PREFIX}&f- &aCounts:" + "\n" +
"{PREFIX}&f- &3Permissions: &a{4}" + "\n" +
"{PREFIX}&f- &3Temporary Permissions: &a{5}" + "\n" +
"{PREFIX}&f- &3Prefixes: &a{6}" + "\n" +
"{PREFIX}&f- &3Suffixes: &a{7}" + "\n" +
"{PREFIX}&f- &3Meta: &a{8}",
false
),
USER_INFO_DATA(
"{PREFIX}&f- &aCached Data:" + "\n" +
"{PREFIX}&f- &3Is Loaded: {0}" + "\n" +
"{PREFIX}&f- &3Current Contexts: {1}" + "\n" +
"{PREFIX}&f- &3Current Prefix: {2}" + "\n" +
"{PREFIX}&f- &3Current Suffix: {3}",
false
),
USER_INFO_PARENT_HEADER("&f- &aParent Groups:", true),
USER_INFO_TEMP_PARENT_HEADER("&f- &aTemporary Parent Groups:", true),
USER_GETUUID("&bThe UUID of &b{0}&b is &b{1}&b.", true),
USER_REMOVEGROUP_ERROR_PRIMARY("You cannot remove a user from their primary group.", true),
USER_PRIMARYGROUP_SUCCESS("&b{0}&a's primary group was set to &b{1}&a.", true),
@@ -36,7 +36,6 @@ public enum Permission {
SYNC(set("sync"), Type.NONE),
INFO(set("info"), Type.NONE),
DEBUG(set("debug"), Type.NONE),
VERBOSE(set("verbose"), Type.NONE),
IMPORT(set("import"), Type.NONE),
@@ -77,7 +76,7 @@ public enum Permission {
USER_META_REMOVETEMP_SUFFIX(set("meta.removetempsuffix", "removetempsuffix"), Type.USER),
USER_META_CLEAR(set("meta.clear", "clearmeta"), Type.USER),
USER_GETUUID(set("getuuid"), Type.USER),
USER_SETPRIMARYGROUP(set("setprimarygroup"), Type.USER),
USER_SWITCHPRIMARYGROUP(set("switchprimarygroup", "setprimarygroup"), Type.USER),
USER_SHOWTRACKS(set("showtracks"), Type.USER),
USER_PROMOTE(set("promote"), Type.USER),
USER_DEMOTE(set("demote"), Type.USER),
@@ -134,6 +133,18 @@ public enum Permission {
LOG_NOTIFY(set("notify"), Type.LOG),
LOG_EXPORT(set("export"), Type.LOG),
SPONGE_PERMISSION_INFO(set("permission.info"), Type.SPONGE),
SPONGE_PERMISSION_SET(set("permission.set"), Type.SPONGE),
SPONGE_PERMISSION_CLEAR(set("permission.clear"), Type.SPONGE),
SPONGE_PARENT_INFO(set("parent.info"), Type.SPONGE),
SPONGE_PARENT_ADD(set("parent.add"), Type.SPONGE),
SPONGE_PARENT_REMOVE(set("parent.remove"), Type.SPONGE),
SPONGE_PARENT_CLEAR(set("parent.clear"), Type.SPONGE),
SPONGE_OPTION_INFO(set("option.info"), Type.SPONGE),
SPONGE_OPTION_SET(set("option.set"), Type.SPONGE),
SPONGE_OPTION_UNSET(set("option.unset"), Type.SPONGE),
SPONGE_OPTION_CLEAR(set("option.clear"), Type.SPONGE),
MIGRATION(set("migration"), Type.NONE);
private static final String IDENTIFIER = "luckperms.";
@@ -167,7 +178,8 @@ public enum Permission {
USER("user"),
GROUP("group"),
TRACK("track"),
LOG("log");
LOG("log"),
SPONGE("sponge");
private final String tag;
@@ -71,4 +71,8 @@ public class ContextManager<T> {
listeners.add(listener);
}
public int getCalculatorsSize() {
return calculators.size();
}
}
@@ -29,14 +29,16 @@ import com.google.common.collect.Maps;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.constants.Patterns;
import me.lucko.luckperms.common.utils.ShorthandParser;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* An immutable permission node
@@ -44,7 +46,7 @@ import java.util.stream.IntStream;
@SuppressWarnings("OptionalGetWithoutIsPresent")
@ToString(of = {"permission", "value", "override", "server", "world", "expireAt", "contexts"})
@EqualsAndHashCode(of = {"permission", "value", "override", "server", "world", "expireAt", "contexts"})
public class Node implements me.lucko.luckperms.api.Node {
public class ImmutableNode implements Node {
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 META_PATTERN = Pattern.compile("meta\\..*\\..*");
@@ -95,7 +97,7 @@ public class Node implements me.lucko.luckperms.api.Node {
* @param world the world this node applies on
* @param contexts any additional contexts applying to this node
*/
public Node(String permission, boolean value, boolean override, long expireAt, String server, String world, ContextSet contexts) {
public ImmutableNode(String permission, boolean value, boolean override, long expireAt, String server, String world, ContextSet contexts) {
if (permission == null || permission.equals("")) {
throw new IllegalArgumentException("Empty permission");
}
@@ -132,24 +134,24 @@ public class Node implements me.lucko.luckperms.api.Node {
isMeta = META_PATTERN.matcher(permission).matches();
if (isMeta) {
List<String> metaPart = Splitter.on('.').limit(2).splitToList(getPermission().substring("meta.".length()));
meta = Maps.immutableEntry(metaPart.get(0), metaPart.get(1));
meta = Maps.immutableEntry(MetaUtils.unescapeCharacters(metaPart.get(0)), MetaUtils.unescapeCharacters(metaPart.get(1)));
}
isPrefix = PREFIX_PATTERN.matcher(permission).matches();
if (isPrefix) {
List<String> prefixPart = Splitter.on('.').limit(2).splitToList(getPermission().substring("prefix.".length()));
Integer i = Integer.parseInt(prefixPart.get(0));
prefix = Maps.immutableEntry(i, prefixPart.get(1));
prefix = Maps.immutableEntry(i, MetaUtils.unescapeCharacters(prefixPart.get(1)));
}
isSuffix = SUFFIX_PATTERN.matcher(permission).matches();
if (isSuffix) {
List<String> suffixPart = Splitter.on('.').limit(2).splitToList(getPermission().substring("suffix.".length()));
Integer i = Integer.parseInt(suffixPart.get(0));
suffix = Maps.immutableEntry(i, suffixPart.get(1));
suffix = Maps.immutableEntry(i, MetaUtils.unescapeCharacters(suffixPart.get(1)));
}
resolvedShorthand = calculateShorthand();
resolvedShorthand = ImmutableList.copyOf(ShorthandParser.parseShorthand(getPermission()));
serializedNode = calculateSerializedNode();
}
@@ -412,60 +414,6 @@ public class Node implements me.lucko.luckperms.api.Node {
return serializedNode;
}
private List<String> calculateShorthand() {
if (!Patterns.SHORTHAND_NODE.matcher(getPermission()).find()) {
return ImmutableList.of();
}
if (!getPermission().contains(".")) {
return ImmutableList.of();
}
Iterable<String> parts = Splitter.on('.').split(getPermission());
List<Set<String>> nodeParts = new ArrayList<>();
for (String s : parts) {
if ((!s.startsWith("(") || !s.endsWith(")")) || (!s.contains("|") && !s.contains("-"))) {
nodeParts.add(Collections.singleton(s));
continue;
}
final String bits = s.substring(1, s.length() - 1);
if (s.contains("|")) {
nodeParts.add(new HashSet<>(Splitter.on('|').splitToList(bits)));
} else {
List<String> range = Splitter.on('-').limit(2).splitToList(bits);
if (isChar(range.get(0), range.get(1))) {
nodeParts.add(getCharRange(range.get(0).charAt(0), range.get(1).charAt(0)));
} else if (isInt(range.get(0), range.get(1))) {
nodeParts.add(IntStream.rangeClosed(Integer.parseInt(range.get(0)), Integer.parseInt(range.get(1))).boxed()
.map(i -> "" + i)
.collect(Collectors.toSet())
);
} else {
// Fallback
nodeParts.add(Collections.singleton(s));
}
}
}
Set<String> nodes = new HashSet<>();
for (Set<String> set : nodeParts) {
final Set<String> newNodes = new HashSet<>();
if (nodes.isEmpty()) {
newNodes.addAll(set);
} else {
nodes.forEach(str -> newNodes.addAll(set.stream()
.map(add -> str + "." + add)
.collect(Collectors.toList()))
);
}
nodes = newNodes;
}
return ImmutableList.copyOf(nodes);
}
private String calculateSerializedNode() {
StringBuilder builder = new StringBuilder();
@@ -502,7 +450,7 @@ public class Node implements me.lucko.luckperms.api.Node {
}
@Override
public boolean equalsIgnoringValue(me.lucko.luckperms.api.Node other) {
public boolean equalsIgnoringValue(Node other) {
if (!other.getPermission().equalsIgnoreCase(this.getPermission())) {
return false;
}
@@ -545,7 +493,7 @@ public class Node implements me.lucko.luckperms.api.Node {
}
@Override
public boolean almostEquals(me.lucko.luckperms.api.Node other) {
public boolean almostEquals(Node other) {
if (!other.getPermission().equalsIgnoreCase(this.getPermission())) {
return false;
}
@@ -582,7 +530,7 @@ public class Node implements me.lucko.luckperms.api.Node {
}
@Override
public boolean equalsIgnoringValueOrTemp(me.lucko.luckperms.api.Node other) {
public boolean equalsIgnoringValueOrTemp(Node other) {
if (!other.getPermission().equalsIgnoreCase(this.getPermission())) {
return false;
}
@@ -25,6 +25,7 @@ package me.lucko.luckperms.common.core;
import com.google.common.base.Splitter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.common.constants.Patterns;
@@ -38,7 +39,7 @@ import java.util.Set;
* Builds Nodes
*/
@RequiredArgsConstructor
public class NodeBuilder implements me.lucko.luckperms.api.Node.Builder {
public class NodeBuilder implements Node.Builder {
private final String permission;
private Boolean value = true;
private boolean override = false;
@@ -67,7 +68,7 @@ public class NodeBuilder implements me.lucko.luckperms.api.Node.Builder {
}
}
NodeBuilder(me.lucko.luckperms.api.Node other) {
NodeBuilder(Node other) {
this.permission = other.getPermission();
this.value = other.getValue();
this.override = other.isOverride();
@@ -78,37 +79,37 @@ public class NodeBuilder implements me.lucko.luckperms.api.Node.Builder {
}
@Override
public me.lucko.luckperms.api.Node.Builder setNegated(boolean negated) {
public Node.Builder setNegated(boolean negated) {
value = !negated;
return this;
}
@Override
public me.lucko.luckperms.api.Node.Builder setValue(boolean value) {
public Node.Builder setValue(boolean value) {
this.value = value;
return this;
}
@Override
public me.lucko.luckperms.api.Node.Builder setOverride(boolean override) {
public Node.Builder setOverride(boolean override) {
this.override = override;
return this;
}
@Override
public me.lucko.luckperms.api.Node.Builder setExpiry(long expireAt) {
public Node.Builder setExpiry(long expireAt) {
this.expireAt = expireAt;
return this;
}
@Override
public me.lucko.luckperms.api.Node.Builder setWorld(String world) {
public Node.Builder setWorld(String world) {
this.world = world;
return this;
}
@Override
public me.lucko.luckperms.api.Node.Builder setServer(String server) {
public Node.Builder setServer(String server) {
if (server != null && ArgumentChecker.checkServer(server)) {
throw new IllegalArgumentException("Server name invalid.");
}
@@ -117,13 +118,13 @@ public class NodeBuilder implements me.lucko.luckperms.api.Node.Builder {
return this;
}
public me.lucko.luckperms.api.Node.Builder setServerRaw(String server) {
public Node.Builder setServerRaw(String server) {
this.server = server;
return this;
}
@Override
public me.lucko.luckperms.api.Node.Builder withExtraContext(@NonNull String key, @NonNull String value) {
public Node.Builder withExtraContext(@NonNull String key, @NonNull String value) {
switch (key.toLowerCase()) {
case "server":
setServer(value);
@@ -140,31 +141,31 @@ public class NodeBuilder implements me.lucko.luckperms.api.Node.Builder {
}
@Override
public me.lucko.luckperms.api.Node.Builder withExtraContext(Map.Entry<String, String> entry) {
public Node.Builder withExtraContext(Map.Entry<String, String> entry) {
withExtraContext(entry.getKey(), entry.getValue());
return this;
}
@Override
public me.lucko.luckperms.api.Node.Builder withExtraContext(Map<String, String> map) {
public Node.Builder withExtraContext(Map<String, String> map) {
withExtraContext(ContextSet.fromMap(map));
return this;
}
@Override
public me.lucko.luckperms.api.Node.Builder withExtraContext(Set<Map.Entry<String, String>> context) {
public Node.Builder withExtraContext(Set<Map.Entry<String, String>> context) {
withExtraContext(ContextSet.fromEntries(context));
return this;
}
@Override
public me.lucko.luckperms.api.Node.Builder withExtraContext(ContextSet set) {
public Node.Builder withExtraContext(ContextSet set) {
set.toSet().forEach(this::withExtraContext);
return this;
}
@Override
public me.lucko.luckperms.api.Node build() {
return new Node(permission, value, override, expireAt, server, world, extraContexts);
public Node build() {
return new ImmutableNode(permission, value, override, expireAt, server, world, extraContexts);
}
}
@@ -26,10 +26,13 @@ import com.google.common.base.Splitter;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import lombok.experimental.UtilityClass;
import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Node;
import java.util.List;
import java.util.concurrent.ExecutionException;
/**
* Utility class to make Node(Builder) instances from serialised strings or existing Nodes
@@ -39,7 +42,7 @@ public class NodeFactory {
private static final LoadingCache<String, Node> CACHE = CacheBuilder.newBuilder()
.build(new CacheLoader<String, Node>() {
@Override
public Node load(String s) {
public Node load(String s) throws Exception {
return builderFromSerialisedNode(s, true).build();
}
});
@@ -47,13 +50,17 @@ public class NodeFactory {
private static final LoadingCache<String, Node> CACHE_NEGATED = CacheBuilder.newBuilder()
.build(new CacheLoader<String, Node>() {
@Override
public Node load(String s) {
public Node load(String s) throws Exception {
return builderFromSerialisedNode(s, false).build();
}
});
public static Node fromSerialisedNode(String s, Boolean b) {
return b ? CACHE.getUnchecked(s) : CACHE_NEGATED.getUnchecked(s);
try {
return b ? CACHE.get(s) : CACHE_NEGATED.get(s);
} catch (UncheckedExecutionException | ExecutionException e) {
throw new IllegalArgumentException(e);
}
}
public static Node.Builder newBuilder(String s) {
@@ -101,4 +108,23 @@ public class NodeFactory {
public static Node.Builder builderFromExisting(Node other) {
return new NodeBuilder(other);
}
public static NodeBuilder makeMetaNode(String key, String value) {
if (key.equalsIgnoreCase("prefix")) {
return makePrefixNode(100, value);
}
if (key.equalsIgnoreCase("suffix")) {
return makeSuffixNode(100, value);
}
return new NodeBuilder("meta." + MetaUtils.escapeCharacters(key) + "." + MetaUtils.escapeCharacters(value));
}
public static NodeBuilder makePrefixNode(int priority, String prefix) {
return new NodeBuilder("prefix." + priority + "." + MetaUtils.escapeCharacters(prefix));
}
public static NodeBuilder makeSuffixNode(int priority, String suffix) {
return new NodeBuilder("suffix." + priority + "." + MetaUtils.escapeCharacters(suffix));
}
}
@@ -33,7 +33,6 @@ import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.api.event.events.*;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.api.internal.GroupLink;
@@ -42,6 +41,8 @@ import me.lucko.luckperms.common.caching.MetaHolder;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.utils.Cache;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import me.lucko.luckperms.common.utils.ImmutableLocalizedNode;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
@@ -241,10 +242,10 @@ public abstract class PermissionHolder {
/**
* Resolves inherited nodes and returns them
* @param excludedGroups a list of groups to exclude
* @param context context to decide if groups should be applied
* @param contexts context to decide if groups should be applied
* @return a set of nodes
*/
public SortedSet<LocalizedNode> getAllNodes(List<String> excludedGroups, Contexts context) {
public SortedSet<LocalizedNode> getAllNodes(List<String> excludedGroups, ExtractedContexts contexts) {
SortedSet<LocalizedNode> all = new TreeSet<>((SortedSet<LocalizedNode>) getPermissions(true));
if (excludedGroups == null) {
@@ -259,16 +260,14 @@ public abstract class PermissionHolder {
.filter(Node::isGroupNode)
.collect(Collectors.toSet());
MutableContextSet contexts = MutableContextSet.fromSet(context.getContexts());
String server = contexts.getValues("server").stream().findAny().orElse(null);
String world = contexts.getValues("world").stream().findAny().orElse(null);
contexts.removeAll("server");
contexts.removeAll("world");
Contexts context = contexts.getContexts();
String server = contexts.getServer();
String world = contexts.getWorld();
parents.removeIf(node ->
!node.shouldApplyOnServer(server, context.isApplyGlobalGroups(), plugin.getConfiguration().isApplyingRegex()) ||
!node.shouldApplyOnWorld(world, context.isApplyGlobalWorldGroups(), plugin.getConfiguration().isApplyingRegex()) ||
!node.shouldApplyWithContext(contexts, false)
!node.shouldApplyWithContext(contexts.getContextSet(), false)
);
TreeSet<Map.Entry<Integer, Node>> sortedParents = new TreeSet<>(Util.META_COMPARATOR.reversed());
@@ -293,7 +292,7 @@ public abstract class PermissionHolder {
}
inherited:
for (LocalizedNode inherited : group.getAllNodes(excludedGroups, context)) {
for (LocalizedNode inherited : group.getAllNodes(excludedGroups, contexts)) {
for (LocalizedNode existing : all) {
if (existing.getNode().almostEquals(inherited.getNode())) {
continue inherited;
@@ -307,7 +306,7 @@ public abstract class PermissionHolder {
return all;
}
public MetaHolder accumulateMeta(MetaHolder holder, List<String> excludedGroups, Contexts context) {
public MetaHolder accumulateMeta(MetaHolder holder, List<String> excludedGroups, ExtractedContexts contexts) {
if (holder == null) {
holder = new MetaHolder();
}
@@ -318,11 +317,9 @@ public abstract class PermissionHolder {
excludedGroups.add(getObjectName().toLowerCase());
MutableContextSet contexts = MutableContextSet.fromSet(context.getContexts());
String server = contexts.getValues("server").stream().findAny().orElse(null);
String world = contexts.getValues("world").stream().findAny().orElse(null);
contexts.removeAll("server");
contexts.removeAll("world");
Contexts context = contexts.getContexts();
String server = contexts.getServer();
String world = contexts.getWorld();
SortedSet<LocalizedNode> all = new TreeSet<>((SortedSet<LocalizedNode>) getPermissions(true));
for (LocalizedNode ln : all) {
@@ -332,7 +329,7 @@ public abstract class PermissionHolder {
if (!n.isMeta() && !n.isPrefix() && !n.isSuffix()) continue;
if (!n.shouldApplyOnServer(server, context.isIncludeGlobal(), false)) continue;
if (!n.shouldApplyOnWorld(world, context.isIncludeGlobalWorld(), false)) continue;
if (!n.shouldApplyWithContext(contexts, false)) continue;
if (!n.shouldApplyWithContext(contexts.getContextSet(), false)) continue;
holder.accumulateNode(n);
}
@@ -346,7 +343,7 @@ public abstract class PermissionHolder {
parents.removeIf(node ->
!node.shouldApplyOnServer(server, context.isApplyGlobalGroups(), plugin.getConfiguration().isApplyingRegex()) ||
!node.shouldApplyOnWorld(world, context.isApplyGlobalWorldGroups(), plugin.getConfiguration().isApplyingRegex()) ||
!node.shouldApplyWithContext(contexts, false)
!node.shouldApplyWithContext(contexts.getContextSet(), false)
);
TreeSet<Map.Entry<Integer, Node>> sortedParents = new TreeSet<>(Util.META_COMPARATOR.reversed());
@@ -370,7 +367,7 @@ public abstract class PermissionHolder {
continue;
}
group.accumulateMeta(holder, excludedGroups, context);
group.accumulateMeta(holder, excludedGroups, contexts);
}
return holder;
@@ -378,28 +375,26 @@ public abstract class PermissionHolder {
/**
* Gets all of the nodes that this holder has (and inherits), given the context
* @param context the context for this request
* @param contexts the context for this request
* @return a map of permissions
*/
public Set<LocalizedNode> getAllNodesFiltered(Contexts context) {
public Set<LocalizedNode> getAllNodesFiltered(ExtractedContexts contexts) {
SortedSet<LocalizedNode> allNodes;
Contexts context = contexts.getContexts();
String server = contexts.getServer();
String world = contexts.getWorld();
if (context.isApplyGroups()) {
allNodes = getAllNodes(null, context);
allNodes = getAllNodes(null, contexts);
} else {
allNodes = new TreeSet<>((SortedSet<LocalizedNode>) getPermissions(true));
}
MutableContextSet contexts = MutableContextSet.fromSet(context.getContexts());
String server = contexts.getValues("server").stream().findAny().orElse(null);
String world = contexts.getValues("world").stream().findAny().orElse(null);
contexts.removeAll("server");
contexts.removeAll("world");
allNodes.removeIf(node ->
!node.shouldApplyOnServer(server, context.isIncludeGlobal(), plugin.getConfiguration().isApplyingRegex()) ||
!node.shouldApplyOnWorld(world, context.isIncludeGlobalWorld(), plugin.getConfiguration().isApplyingRegex()) ||
!node.shouldApplyWithContext(contexts, false)
!node.shouldApplyWithContext(contexts.getContextSet(), false)
);
Set<LocalizedNode> perms = ConcurrentHashMap.newKeySet();
@@ -420,14 +415,14 @@ public abstract class PermissionHolder {
}
/**
* Converts the output of {@link #getAllNodesFiltered(Contexts)}, and expands shorthand perms
* Converts the output of {@link #getAllNodesFiltered(ExtractedContexts)}, and expands shorthand perms
* @param context the context for this request
* @return a map of permissions
*/
public Map<String, Boolean> exportNodes(Contexts context, boolean lowerCase) {
Map<String, Boolean> perms = new HashMap<>();
for (LocalizedNode ln : getAllNodesFiltered(context)) {
for (LocalizedNode ln : getAllNodesFiltered(ExtractedContexts.generate(context))) {
Node node = ln.getNode();
perms.put(lowerCase ? node.getPermission().toLowerCase() : node.getPermission(), node.getValue());
@@ -469,7 +464,6 @@ public abstract class PermissionHolder {
invalidateCache(false);
}
@Deprecated
public void setNodes(Map<String, Boolean> nodes) {
Set<Node> set = nodes.entrySet().stream()
.map(e -> makeNode(e.getKey(), e.getValue()))
@@ -478,15 +472,6 @@ public abstract class PermissionHolder {
setNodes(set);
}
public void addNodeUnchecked(Node node) {
synchronized (nodes) {
if (!nodes.add(node)) {
return;
}
}
invalidateCache(true);
}
/**
* Check if the holder has a permission node
* @param node the node to check
@@ -537,7 +522,7 @@ public abstract class PermissionHolder {
* @return the result of the lookup
*/
public InheritanceInfo inheritsPermissionInfo(Node node) {
for (LocalizedNode n : getAllNodes(null, Contexts.allowAll())) {
for (LocalizedNode n : getAllNodes(null, ExtractedContexts.generate(Contexts.allowAll()))) {
if (n.getNode().almostEquals(node)) {
return InheritanceInfo.of(n);
}
@@ -932,6 +917,18 @@ public abstract class PermissionHolder {
return getPermissions(false).stream().filter(Node::isPermanent).collect(Collectors.toSet());
}
public Set<Node> getPrefixNodes() {
return getPermissions(false).stream().filter(Node::isPrefix).collect(Collectors.toSet());
}
public Set<Node> getSuffixNodes() {
return getPermissions(false).stream().filter(Node::isSuffix).collect(Collectors.toSet());
}
public Set<Node> getMetaNodes() {
return getPermissions(false).stream().filter(Node::isMeta).collect(Collectors.toSet());
}
/**
* Get a {@link List} of all of the groups the holder inherits, on all servers
* @return a {@link List} of group names
@@ -992,8 +989,8 @@ public abstract class PermissionHolder {
return new NodeBuilder(permission);
}
private static me.lucko.luckperms.common.utils.LocalizedNode makeLocal(Node node, String location) {
return me.lucko.luckperms.common.utils.LocalizedNode.of(node, location);
private static ImmutableLocalizedNode makeLocal(Node node, String location) {
return ImmutableLocalizedNode.of(node, location);
}
private static Node makeNode(String s, Boolean b) {
@@ -66,4 +66,8 @@ public class UuidCache {
cache.remove(external);
}
public int getSize() {
return onlineMode ? 0 : cache.size();
}
}
@@ -30,6 +30,8 @@ import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.data.Log;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.storage.backing.AbstractBacking;
import me.lucko.luckperms.common.storage.wrappings.BufferedOutputStorage;
import me.lucko.luckperms.common.storage.wrappings.TolerantStorage;
import me.lucko.luckperms.common.tracks.Track;
import me.lucko.luckperms.common.users.User;
@@ -26,7 +26,6 @@ import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import lombok.Cleanup;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.groups.GroupManager;
import me.lucko.luckperms.common.tracks.Track;
@@ -44,7 +43,7 @@ import static me.lucko.luckperms.common.core.PermissionHolder.exportToLegacy;
@SuppressWarnings("ResultOfMethodCallIgnored")
public class JSONBacking extends FlatfileBacking {
public JSONBacking(LuckPermsPlugin plugin, File pluginDir) {
super(plugin, "Flatfile - JSON", pluginDir);
super(plugin, "JSON", pluginDir);
}
private boolean doWrite(File file, WriteOperation writeOperation) {
@@ -93,11 +92,13 @@ public class JSONBacking extends FlatfileBacking {
user.setPrimaryGroup(reader.nextString()); // primaryGroup
reader.nextName(); // perms
reader.beginObject();
Map<String, Boolean> map = new HashMap<>();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
user.addNodeUnchecked(NodeFactory.fromSerialisedNode(node, b));
map.put(node, b);
}
user.setNodes(map);
reader.endObject();
reader.endObject();
@@ -255,11 +256,13 @@ public class JSONBacking extends FlatfileBacking {
reader.nextString(); // name
reader.nextName(); //perms
reader.beginObject();
Map<String, Boolean> map = new HashMap<>();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
group.addNodeUnchecked(NodeFactory.fromSerialisedNode(node, b));
map.put(node, b);
}
group.setNodes(map);
reader.endObject();
reader.endObject();
@@ -305,11 +308,13 @@ public class JSONBacking extends FlatfileBacking {
reader.nextString(); // name
reader.nextName(); // perms
reader.beginObject();
Map<String, Boolean> map = new HashMap<>();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
group.addNodeUnchecked(NodeFactory.fromSerialisedNode(node, b));
map.put(node, b);
}
group.setNodes(map);
reader.endObject();
reader.endObject();
return true;
@@ -24,7 +24,6 @@ package me.lucko.luckperms.common.storage.backing;
import lombok.Cleanup;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.groups.GroupManager;
import me.lucko.luckperms.common.tracks.Track;
@@ -44,7 +43,7 @@ import static me.lucko.luckperms.common.core.PermissionHolder.exportToLegacy;
@SuppressWarnings({"unchecked", "ResultOfMethodCallIgnored"})
public class YAMLBacking extends FlatfileBacking {
public YAMLBacking(LuckPermsPlugin plugin, File pluginDir) {
super(plugin, "Flatfile - YAML", pluginDir);
super(plugin, "YAML", pluginDir);
}
private static Yaml getYaml() {
@@ -91,9 +90,7 @@ public class YAMLBacking extends FlatfileBacking {
String name = (String) values.get("name");
user.setPrimaryGroup((String) values.get("primary-group"));
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) {
user.addNodeUnchecked(NodeFactory.fromSerialisedNode(e.getKey(), e.getValue()));
}
user.setNodes(perms);
boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
@@ -214,9 +211,7 @@ public class YAMLBacking extends FlatfileBacking {
if (groupFile.exists()) {
return doRead(groupFile, values -> {
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) {
group.addNodeUnchecked(NodeFactory.fromSerialisedNode(e.getKey(), e.getValue()));
}
group.setNodes(perms);
return true;
});
} else {
@@ -247,9 +242,7 @@ public class YAMLBacking extends FlatfileBacking {
File groupFile = new File(groupsDir, name + ".yml");
return groupFile.exists() && doRead(groupFile, values -> {
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) {
group.addNodeUnchecked(NodeFactory.fromSerialisedNode(e.getKey(), e.getValue()));
}
group.setNodes(perms);
return true;
});
@@ -20,13 +20,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.storage;
package me.lucko.luckperms.common.storage.wrappings;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Delegate;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.tracks.Track;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.users.UserIdentifier;
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.storage;
package me.lucko.luckperms.common.storage.wrappings;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
@@ -28,6 +28,7 @@ import lombok.experimental.Delegate;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.common.data.Log;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.tracks.Track;
import me.lucko.luckperms.common.users.User;
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.runnables;
package me.lucko.luckperms.common.tasks;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.common.LuckPermsPlugin;
@@ -49,5 +49,9 @@ public class ExpireTemporaryTask implements Runnable {
}
}
}
if (groupChanges) {
plugin.getUpdateTaskBuffer().request();
}
}
}
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.runnables;
package me.lucko.luckperms.common.tasks;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.event.events.PostSyncEvent;
@@ -134,8 +134,6 @@ public class UserManager extends AbstractManager<UserIdentifier, User> {
for (UUID uuid : players) {
UUID internal = plugin.getUuidCache().getUUID(uuid);
plugin.getStorage().loadUser(internal, "null").join();
User user = get(internal);
user.getRefreshBuffer().request();
}
});
});
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.common.utils;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
@Getter
@ToString
public class ExtractedContexts {
public static ExtractedContexts generate(Contexts contexts) {
return new ExtractedContexts(contexts);
}
public static ExtractedContexts generate(ContextSet contexts) {
return new ExtractedContexts(contexts);
}
private Contexts contexts;
private ContextSet contextSet;
private String server;
private String world;
private ExtractedContexts(Contexts context) {
this.contexts = context;
setup(context.getContexts());
}
private ExtractedContexts(ContextSet contexts) {
setup(contexts);
}
private void setup(ContextSet contexts) {
MutableContextSet contextSet = MutableContextSet.fromSet(contexts);
server = contextSet.getValues("server").stream().findAny().orElse(null);
world = contextSet.getValues("world").stream().findAny().orElse(null);
contextSet.removeAll("server");
contextSet.removeAll("world");
this.contextSet = contextSet.makeImmutable();
}
}
@@ -24,6 +24,7 @@ package me.lucko.luckperms.common.utils;
import lombok.*;
import lombok.experimental.Delegate;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
/**
@@ -32,9 +33,9 @@ import me.lucko.luckperms.api.Node;
@Getter
@ToString
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class LocalizedNode implements me.lucko.luckperms.api.LocalizedNode {
public static LocalizedNode of(@NonNull Node node, @NonNull String location) {
return new LocalizedNode(node, location);
public class ImmutableLocalizedNode implements LocalizedNode {
public static ImmutableLocalizedNode of(@NonNull Node node, @NonNull String location) {
return new ImmutableLocalizedNode(node, location);
}
@Delegate
@@ -44,6 +44,10 @@ public class LocaleManager {
translations = ImmutableMap.copyOf((Map<String, String>) new Yaml().load(fileReader));
}
public int getSize() {
return translations == null ? 0 : translations.size();
}
public String getTranslation(Message key) {
if (translations == null) {
return null;
@@ -0,0 +1,171 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.common.utils;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import lombok.experimental.UtilityClass;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@UtilityClass
public class ShorthandParser {
private static final List<Function<String, List<String>>> PARSERS = ImmutableList.<Function<String, List<String>>>builder()
.add(new ListParser())
.add(new CharacterRangeParser())
.add(new NumericRangeParser())
.build();
public static Set<String> parseShorthand(String s) {
Set<String> results = new HashSet<>();
results.add(s);
while (true) {
Set<String> working = new HashSet<>();
int beforeSize = results.size();
for (String str : results) {
Set<String> ret = captureResults(str);
if (ret != null) {
working.addAll(ret);
} else {
working.add(str);
}
}
if (working.size() != beforeSize) {
results = working;
continue;
}
break;
}
results.remove(s);
return results;
}
private static Set<String> captureResults(String s) {
s = s.replace('(', '{').replace(')', '}');
int openingIndex = s.indexOf('{');
if (openingIndex == -1) {
return null;
}
int closingIndex = s.indexOf('}');
if (closingIndex < openingIndex) {
return null;
}
String before = s.substring(0, openingIndex);
String after = s.substring(closingIndex + 1);
String between = s.substring(openingIndex + 1, closingIndex);
Set<String> results = new HashSet<>();
for (Function<String, List<String>> parser : PARSERS) {
List<String> res = parser.apply(between);
if (res != null) {
for (String r : res) {
results.add(before + r + after);
}
}
}
return results;
}
private static class ListParser implements Function<String, List<String>> {
@Override
public List<String> apply(String s) {
s = s.replace('|', ',');
if (!s.contains(",")) {
return null;
}
return Splitter.on(',').splitToList(s);
}
}
private static class NumericRangeParser implements Function<String, List<String>> {
@Override
public List<String> apply(String s) {
int index = s.indexOf("-");
if (index == -1) {
return null;
}
String before = s.substring(0, index);
String after = s.substring(index + 1);
if (isInt(before) && isInt(after)) {
return IntStream.rangeClosed(Integer.parseInt(before), Integer.parseInt(after))
.boxed().map(i -> "" + i).collect(Collectors.toList());
}
return null;
}
private static boolean isInt(String a) {
try {
Integer.parseInt(a);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}
private static class CharacterRangeParser implements Function<String, List<String>> {
@Override
public List<String> apply(String s) {
int index = s.indexOf("-");
if (index == -1) {
return null;
}
String before = s.substring(0, index);
String after = s.substring(index + 1);
if (before.length() == 1 && after.length() == 1) {
return getCharRange(before.charAt(0), after.charAt(0));
}
return null;
}
private static List<String> getCharRange(char a, char b) {
List<String> s = new ArrayList<>();
for (char c = a; c <= b; c++) {
s.add(Character.toString(c));
}
return s;
}
}
}
+41 -24
View File
@@ -83,22 +83,28 @@ info: >
{PREFIX}&f- &3Platform: &f{1}\n
{PREFIX}&f- &3Storage Method: &f{2}\n
{PREFIX}&f- &3Server Name: &f{3}\n
{PREFIX}&f- &3Sync Interval: &f{4} minutes\n
{PREFIX}&f- &3Include Global: &f{5}\n
{PREFIX}&f- &3Include Global World: &f{6}\n
{PREFIX}&f- &3Apply Global Groups: &f{7}\n
{PREFIX}&f- &3Apply Global World Groups: &f{8}\n
{PREFIX}&f- &3Online Mode: &f{9}\n
{PREFIX}&f- &3Apply Wildcards: &f{10}\n
{PREFIX}&f- &3Apply Regex: &f{11}\n
{PREFIX}&f- &3Apply Shorthand: &f{12}
debug: >
{PREFIX}&d&l> &dDebug Info\n
{PREFIX}&f> &3Online Players: &f{0}\n
{PREFIX}&f> &3Loaded Users: &f{1}\n
{PREFIX}&f> &3Loaded Groups: &f{2}\n
{PREFIX}&f> &3Loaded Tracks: &f{3}
{PREFIX}&f- &3Sync Interval: &a{4} &fminutes\n
{PREFIX}&f- &bCounts:\n
{PREFIX}&f- &3Online Players: &a{5}\n
{PREFIX}&f- &3Loaded Users: &a{6}\n
{PREFIX}&f- &3Loaded Groups: &a{7}\n
{PREFIX}&f- &3Loaded Tracks: &a{8}\n
{PREFIX}&f- &3Log size: &a{9}\n
{PREFIX}&f- &3UUID Cache size: &a{10}\n
{PREFIX}&f- &3Translations loaded: &a{11}\n
{PREFIX}&f- &3Pre-process contexts: &a{12}\n
{PREFIX}&f- &3Context Calculators: &a{13}\n
{PREFIX}&f- &bConfiguration:\n
{PREFIX}&f- &3Online Mode: {14}\n
{PREFIX}&f- &3Redis Enabled: {15}\n
{PREFIX}&f- &bPermission Calculation:\n
{PREFIX}&f- &3Including Global: {16}\n
{PREFIX}&f- &3Including Global World: {17}\n
{PREFIX}&f- &3Applying Global Groups: {18}\n
{PREFIX}&f- &3Applying Global World Groups: {19}\n
{PREFIX}&f- &3Applying Wildcards: {20}\n
{PREFIX}&f- &3Applying Regex: {21}\n
{PREFIX}&f- &3Applying Shorthand: {22}"
create-group-error: "There was an error whilst creating the group."
delete-group-error: "There was an error whilst deleting the group."
delete-group-error-default: "You cannot delete the default group."
@@ -154,10 +160,10 @@ past-date-error: "You cannot set a date in the past!"
chat-meta-prefix-header: "&b{0}'s Prefixes"
chat-meta-suffix-header: "&b{0}'s Suffixes"
meta-header: "&b{0}'s Meta"
chat-meta-entry: "&b-> {0} &f- &f\"{1}&f\""
chat-meta-entry-with-context: "&b-> {0} &f- &f\"{1}&f\"{2}"
meta-entry: "&b-> &a{0} &f= &f\"{1}&f\""
meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\"{2}"
chat-meta-entry: "&b-> {0} &f- &f\"{1}&f\" &8(&7inherited from &a{2}&8)"
chat-meta-entry-with-context: "&b-> {0} &f- &f\"{1}&f\" &8(&7inherited from &a{2}&8){3}"
meta-entry: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7inherited from &a{2}&8)"
meta-entry-with-context: "&b-> &a{0} &f= &f\"{1}&f\" &8(&7inherited from &a{2}&8){3}"
chat-meta-prefix-none: "&b{0} has no prefixes."
chat-meta-suffix-none: "&b{0} has no suffixes."
meta-none: "&b{0} has no meta."
@@ -214,14 +220,25 @@ unset-meta-temp-server-world-success: "&aUnset temporary meta value with key &f\
bulk-change-type-error: "Invalid type. Was expecting 'server' or 'world'."
bulk-change-success: "&aApplied bulk change successfully. {0} records were changed."
user-info: >
user-info-general: >
{PREFIX}&b&l> &bUser Info: &f{0}\n
{PREFIX}&f- &3UUID: &f{1}\n
{PREFIX}&f- &3Status: {2}\n
{PREFIX}&f- &3Primary Group: &f{3}\n
{PREFIX}&f- &3Permissions: &f{4}\n
{PREFIX}&f- &3Temporary Permissions: &f{5}\n
{PREFIX}&f- &3Use &b/{6} user {7} permission info &3to see all permissions.
{PREFIX}&f- &aCounts:\n
{PREFIX}&f- &3Permissions: &a{4}\n
{PREFIX}&f- &3Temporary Permissions: &a{5}\n
{PREFIX}&f- &3Prefixes: &a{6}\n
{PREFIX}&f- &3Suffixes: &a{7}\n
{PREFIX}&f- &3Meta: &a{8}
user-info-data: >
{PREFIX}&f- &aCached Data:\n
{PREFIX}&f- &3Is Loaded: {0}\n
{PREFIX}&f- &3Current Contexts: {1}\n
{PREFIX}&f- &3Current Prefix: {2}\n
{PREFIX}&f- &3Current Suffix: {3}
user-info-parent-header: "&f- &aParent Groups:"
user-info-temp-parent-header: "&f- &aTemporary Parent Groups:"
user-getuuid: "&bThe UUID of &b{0}&b is &b{1}&b."
user-removegroup-error-primary: "You cannot remove a user from their primary group."
user-primarygroup-success: "&b{0}&a's primary group was set to &b{1}&a."
+2 -2
View File
@@ -6,7 +6,7 @@
<groupId>me.lucko.luckperms</groupId>
<artifactId>luckperms</artifactId>
<version>2.14-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
<modules>
<module>common</module>
<module>api</module>
@@ -38,7 +38,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<release.version>2.14</release.version>
<release.version>2.15</release.version>
</properties>
<distributionManagement>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.14-SNAPSHOT</version>
<version>2.15-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -31,6 +31,7 @@ import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.api.ApiProvider;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.commands.BaseCommand;
import me.lucko.luckperms.common.commands.ConsecutiveExecutor;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.config.LPConfiguration;
@@ -41,16 +42,18 @@ import me.lucko.luckperms.common.core.UuidCache;
import me.lucko.luckperms.common.data.Importer;
import me.lucko.luckperms.common.groups.GroupManager;
import me.lucko.luckperms.common.messaging.RedisMessaging;
import me.lucko.luckperms.common.runnables.ExpireTemporaryTask;
import me.lucko.luckperms.common.runnables.UpdateTask;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.storage.StorageFactory;
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
import me.lucko.luckperms.common.tasks.UpdateTask;
import me.lucko.luckperms.common.tracks.TrackManager;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.common.users.UserManager;
import me.lucko.luckperms.common.utils.BufferedRequest;
import me.lucko.luckperms.common.utils.DebugHandler;
import me.lucko.luckperms.common.utils.LocaleManager;
import me.lucko.luckperms.common.utils.LogFactory;
import me.lucko.luckperms.sponge.commands.SpongeMainCommand;
import me.lucko.luckperms.sponge.contexts.WorldCalculator;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import me.lucko.luckperms.sponge.timings.LPTimings;
@@ -67,19 +70,24 @@ import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
import org.spongepowered.api.plugin.Dependency;
import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.scheduler.AsynchronousExecutor;
import org.spongepowered.api.scheduler.Scheduler;
import org.spongepowered.api.scheduler.SpongeExecutorService;
import org.spongepowered.api.scheduler.SynchronousExecutor;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.text.Text;
import java.io.File;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@Getter
@Plugin(id = "luckperms",
@@ -106,8 +114,15 @@ public class LPSpongePlugin implements LuckPermsPlugin {
private Path configDir;
private Scheduler scheduler = Sponge.getScheduler();
private Executor syncExecutor = Sponge.getScheduler().createSyncExecutor(this);
private Executor asyncExecutor = Sponge.getScheduler().createAsyncExecutor(this);
@Inject
@SynchronousExecutor
private SpongeExecutorService syncExecutor;
@Inject
@AsynchronousExecutor
private SpongeExecutorService asyncExecutor;
private LPTimings timings;
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
@@ -280,6 +295,28 @@ public class LPSpongePlugin implements LuckPermsPlugin {
return getMainDir();
}
@Override
public Player getPlayer(User user) {
return game.getServer().getPlayer(uuidCache.getExternalUUID(user.getUuid())).orElse(null);
}
@Override
public Contexts getContextForUser(User user) {
Player player = getPlayer(user);
if (player == null) {
return null;
}
return new Contexts(
getContextManager().getApplicableContext(player),
getConfiguration().isIncludingGlobalPerms(),
getConfiguration().isIncludingGlobalWorldPerms(),
true,
getConfiguration().isApplyingGlobalGroups(),
getConfiguration().isApplyingGlobalWorldGroups(),
false
);
}
@Override
public String getVersion() {
return VersionData.VERSION;
@@ -329,7 +366,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
@Override
public Object getPlugin(String name) {
return game.getPluginManager().getPlugin(name).get().getInstance().get();
return game.getPluginManager().getPlugin(name).map(PluginContainer::getInstance).orElse(null);
}
@Override
@@ -339,11 +376,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
@Override
public UUID getUUID(String playerName) {
try {
return game.getServer().getPlayer(playerName).get().getUniqueId();
} catch (Exception e) {
return null;
}
return game.getServer().getPlayer(playerName).map(Player::getUniqueId).orElse(null);
}
@Override
@@ -366,6 +399,25 @@ public class LPSpongePlugin implements LuckPermsPlugin {
scheduler.createTaskBuilder().async().intervalTicks(interval).execute(r).submit(this);
}
@Override
public List<BaseCommand> getExtraCommands() {
return Collections.singletonList(new SpongeMainCommand(this));
}
@Override
public LinkedHashMap<String, Object> getExtraInfo() {
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("SubjectCollection count", service.getKnownSubjects().size());
map.put("Subject count",
service.getKnownSubjects().values().stream()
.map(SubjectCollection::getAllSubjects)
.flatMap(subjects -> StreamSupport.stream(subjects.spliterator(), false))
.count()
);
map.put("PermissionDescription count", service.getDescriptions().size());
return map;
}
private void registerPermission(PermissionService p, String node) {
Optional<PermissionDescription.Builder> builder = p.newDescriptionBuilder(this);
if (!builder.isPresent()) return;
@@ -25,7 +25,12 @@ package me.lucko.luckperms.sponge;
import com.google.common.collect.ImmutableList;
import lombok.AllArgsConstructor;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.common.calculators.*;
import me.lucko.luckperms.common.calculators.CalculatorFactory;
import me.lucko.luckperms.common.calculators.PermissionCalculator;
import me.lucko.luckperms.common.calculators.PermissionProcessor;
import me.lucko.luckperms.common.calculators.processors.MapProcessor;
import me.lucko.luckperms.common.calculators.processors.RegexProcessor;
import me.lucko.luckperms.common.calculators.processors.WildcardProcessor;
import me.lucko.luckperms.common.users.User;
import me.lucko.luckperms.sponge.calculators.DefaultsProcessor;
import me.lucko.luckperms.sponge.calculators.SpongeWildcardProcessor;
@@ -24,7 +24,6 @@ package me.lucko.luckperms.sponge;
import co.aikar.timings.Timing;
import com.google.common.base.Splitter;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.common.commands.CommandManager;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Patterns;
@@ -57,7 +56,7 @@ class SpongeCommand extends CommandManager implements CommandCallable {
plugin.getSenderFactory().wrap(source),
"perms",
Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(s)),
Callback.empty()
null
);
return CommandResult.success();
}
@@ -43,7 +43,7 @@ public class SpongeWildcardProcessor implements PermissionProcessor {
node = node.substring(0, endIndex);
if (!node.isEmpty()) {
Boolean b = map.get(node);
if (b != null) {
if (b != null) {
return Tristate.fromBoolean(b);
}
}
@@ -20,32 +20,42 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.commands.misc;
package me.lucko.luckperms.sponge.commands;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SingleCommand;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.List;
public class DebugCommand extends SingleCommand {
public DebugCommand() {
super("Debug", "Print debugging output", "/%s debug", Permission.DEBUG, Predicates.alwaysFalse(), null);
public class OptionClear extends SubCommand<SubjectData> {
public OptionClear() {
super("clear", "Clears the Subjects options", Permission.SPONGE_OPTION_CLEAR, Predicates.alwaysFalse(),
Arg.list(
Arg.create("contexts...", false, "the contexts to clear options in")
)
);
}
@Override
public 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(),
plugin.getGroupManager().getAll().size(),
plugin.getTrackManager().getAll().size()
);
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, SubjectData subjectData, List<String> args, String label) throws CommandException {
ContextSet contextSet = ArgumentUtils.handleContexts(0, args);
if (contextSet.isEmpty()) {
subjectData.clearOptions();
Util.sendPluginMessage(sender, "&aCleared options matching contexts &bANY&a.");
} else {
subjectData.clearOptions(SpongeUtils.convertContexts(contextSet));
Util.sendPluginMessage(sender, "&aCleared options matching contexts &b" + SpongeUtils.contextToString(contextSet));
}
return CommandResult.SUCCESS;
}
}
@@ -0,0 +1,79 @@
/*
* 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.sponge.commands;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class OptionInfo extends SubCommand<SubjectData> {
public OptionInfo() {
super("info", "Shows info about the subject's options", Permission.SPONGE_OPTION_INFO, Predicates.alwaysFalse(),
Arg.list(Arg.create("contexts...", false, "the contexts to filter by"))
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, SubjectData subjectData, List<String> args, String label) throws CommandException {
ContextSet contextSet = ArgumentUtils.handleContexts(0, args);
if (contextSet.isEmpty()) {
Util.sendPluginMessage(sender, "&aShowing options matching contexts &bANY&a.");
Map<Set<Context>, Map<String, String>> options = subjectData.getAllOptions();
if (options.isEmpty()) {
Util.sendPluginMessage(sender, "That subject does not have any options defined.");
return CommandResult.SUCCESS;
}
for (Map.Entry<Set<Context>, Map<String, String>> e : options.entrySet()) {
ContextSet set = SpongeUtils.convertContexts(e.getKey());
Util.sendPluginMessage(sender, "&3>> &bContext: " + SpongeUtils.contextToString(set) + "\n" + SpongeUtils.optionsToString(e.getValue()));
}
} else {
Map<String, String> options = subjectData.getOptions(SpongeUtils.convertContexts(contextSet));
if (options.isEmpty()) {
Util.sendPluginMessage(sender, "That subject does not have any options defined in those contexts.");
return CommandResult.SUCCESS;
}
Util.sendPluginMessage(sender, "&aShowing options matching contexts &b" +
SpongeUtils.contextToString(contextSet) + "&a.\n" + SpongeUtils.optionsToString(options));
}
return CommandResult.SUCCESS;
}
}
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.sponge.commands;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.List;
public class OptionSet extends SubCommand<SubjectData> {
public OptionSet() {
super("set", "Sets an option for the Subject", Permission.SPONGE_OPTION_SET, Predicates.inRange(0, 1),
Arg.list(
Arg.create("key", true, "the key to set"),
Arg.create("value", true, "the value to set the key to"),
Arg.create("contexts...", false, "the contexts to set the option in")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, SubjectData subjectData, List<String> args, String label) throws CommandException {
String key = args.get(0);
String value = args.get(1);
ContextSet contextSet = ArgumentUtils.handleContexts(2, args);
if (subjectData.setOption(SpongeUtils.convertContexts(contextSet), key, value)) {
Util.sendPluginMessage(sender, "&aSet &f\"" + key + "&f\"&a to &f\"" + value + "&f\"&a in context " + SpongeUtils.contextToString(contextSet));
} else {
Util.sendPluginMessage(sender, "Unable to set option. Does the Subject already have it set?");
}
return CommandResult.SUCCESS;
}
}
@@ -0,0 +1,62 @@
/*
* 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.sponge.commands;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.List;
public class OptionUnset extends SubCommand<SubjectData> {
public OptionUnset() {
super("unset", "Unsets an option for the Subject", Permission.SPONGE_OPTION_UNSET, Predicates.is(0),
Arg.list(
Arg.create("key", true, "the key to unset"),
Arg.create("contexts...", false, "the contexts to unset the key in")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, SubjectData subjectData, List<String> args, String label) throws CommandException {
String key = args.get(0);
ContextSet contextSet = ArgumentUtils.handleContexts(1, args);
if (subjectData.setOption(SpongeUtils.convertContexts(contextSet), key, null)) {
Util.sendPluginMessage(sender, "&aUnset &f\"" + key + "&f\"&a in context " + SpongeUtils.contextToString(contextSet));
} else {
Util.sendPluginMessage(sender, "Unable to unset option. Are you sure the Subject has it set?");
}
return CommandResult.SUCCESS;
}
}
@@ -0,0 +1,81 @@
/*
* 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.sponge.commands;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.List;
public class ParentAdd extends SubCommand<SubjectData> {
public ParentAdd() {
super("add", "Adds a parent to the Subject", Permission.SPONGE_PARENT_ADD, Predicates.inRange(0, 1),
Arg.list(
Arg.create("collection", true, "the subject collection where the parent Subject is"),
Arg.create("subject", true, "the name of the parent Subject"),
Arg.create("contexts...", false, "the contexts to add the parent in")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, SubjectData subjectData, List<String> args, String label) throws CommandException {
String collection = args.get(0);
String name = args.get(1);
ContextSet contextSet = ArgumentUtils.handleContexts(2, args);
PermissionService service = Sponge.getServiceManager().provideUnchecked(PermissionService.class);
if (service.getKnownSubjects().keySet().stream().map(String::toLowerCase).noneMatch(s -> s.equalsIgnoreCase(collection))) {
Util.sendPluginMessage(sender, "Warning: SubjectCollection '&4" + collection + "&c' doesn't already exist.");
}
SubjectCollection c = service.getSubjects(collection);
if (!c.hasRegistered(name)) {
Util.sendPluginMessage(sender, "Warning: Subject '&4" + name + "&c' doesn't already exist.");
}
Subject subject = c.get(name);
if (subjectData.addParent(SpongeUtils.convertContexts(contextSet), subject)) {
Util.sendPluginMessage(sender, "&aAdded parent &b" + subject.getContainingCollection().getIdentifier() +
"&a/&b" + subject.getIdentifier() + "&a in context " + SpongeUtils.contextToString(contextSet));
} else {
Util.sendPluginMessage(sender, "Unable to add parent. Does the Subject already have it added?");
}
return CommandResult.SUCCESS;
}
}
@@ -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.sponge.commands;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.List;
public class ParentClear extends SubCommand<SubjectData> {
public ParentClear() {
super("clear", "Clears the Subjects parents", Permission.SPONGE_PARENT_CLEAR, Predicates.alwaysFalse(),
Arg.list(
Arg.create("contexts...", false, "the contexts to clear parents in")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, SubjectData subjectData, List<String> args, String label) throws CommandException {
ContextSet contextSet = ArgumentUtils.handleContexts(0, args);
if (contextSet.isEmpty()) {
subjectData.clearParents();
Util.sendPluginMessage(sender, "&aCleared parents matching contexts &bANY&a.");
} else {
subjectData.clearParents(SpongeUtils.convertContexts(contextSet));
Util.sendPluginMessage(sender, "&aCleared parents matching contexts &b" + SpongeUtils.contextToString(contextSet));
}
return CommandResult.SUCCESS;
}
}
@@ -0,0 +1,80 @@
/*
* 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.sponge.commands;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class ParentInfo extends SubCommand<SubjectData> {
public ParentInfo() {
super("info", "Shows info about the subject's parents", Permission.SPONGE_PARENT_INFO, Predicates.alwaysFalse(),
Arg.list(Arg.create("contexts...", false, "the contexts to filter by"))
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, SubjectData subjectData, List<String> args, String label) throws CommandException {
ContextSet contextSet = ArgumentUtils.handleContexts(0, args);
if (contextSet.isEmpty()) {
Util.sendPluginMessage(sender, "&aShowing parents matching contexts &bANY&a.");
Map<Set<Context>, List<Subject>> parents = subjectData.getAllParents();
if (parents.isEmpty()) {
Util.sendPluginMessage(sender, "That subject does not have any parents defined.");
return CommandResult.SUCCESS;
}
for (Map.Entry<Set<Context>, List<Subject>> e : parents.entrySet()) {
ContextSet set = SpongeUtils.convertContexts(e.getKey());
Util.sendPluginMessage(sender, "&3>> &bContext: " + SpongeUtils.contextToString(set) + "\n" + SpongeUtils.parentsToString(e.getValue()));
}
} else {
List<Subject> parents = subjectData.getParents(SpongeUtils.convertContexts(contextSet));
if (parents.isEmpty()) {
Util.sendPluginMessage(sender, "That subject does not have any parents defined in those contexts.");
return CommandResult.SUCCESS;
}
Util.sendPluginMessage(sender, "&aShowing parents matching contexts &b" +
SpongeUtils.contextToString(contextSet) + "&a.\n" + SpongeUtils.parentsToString(parents));
}
return CommandResult.SUCCESS;
}
}
@@ -0,0 +1,81 @@
/*
* 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.sponge.commands;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.List;
public class ParentRemove extends SubCommand<SubjectData> {
public ParentRemove() {
super("remove", "Removes a parent from the Subject", Permission.SPONGE_PARENT_REMOVE, Predicates.inRange(0, 1),
Arg.list(
Arg.create("collection", true, "the subject collection where the parent Subject is"),
Arg.create("subject", true, "the name of the parent Subject"),
Arg.create("contexts...", false, "the contexts to remove the parent in")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, SubjectData subjectData, List<String> args, String label) throws CommandException {
String collection = args.get(0);
String name = args.get(1);
ContextSet contextSet = ArgumentUtils.handleContexts(2, args);
PermissionService service = Sponge.getServiceManager().provideUnchecked(PermissionService.class);
if (service.getKnownSubjects().keySet().stream().map(String::toLowerCase).noneMatch(s -> s.equalsIgnoreCase(collection))) {
Util.sendPluginMessage(sender, "Warning: SubjectCollection '&4" + collection + "&c' doesn't exist.");
}
SubjectCollection c = service.getSubjects(collection);
if (!c.hasRegistered(name)) {
Util.sendPluginMessage(sender, "Warning: Subject '&4" + name + "&c' doesn't exist.");
}
Subject subject = c.get(name);
if (subjectData.removeParent(SpongeUtils.convertContexts(contextSet), subject)) {
Util.sendPluginMessage(sender, "&aRemoved parent &b" + subject.getContainingCollection().getIdentifier() +
"&a/&b" + subject.getIdentifier() + "&a in context " + SpongeUtils.contextToString(contextSet));
} else {
Util.sendPluginMessage(sender, "Unable to remove parent. Are you sure the Subject has it added?");
}
return CommandResult.SUCCESS;
}
}
@@ -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.sponge.commands;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.List;
public class PermissionClear extends SubCommand<SubjectData> {
public PermissionClear() {
super("clear", "Clears the Subjects permissions", Permission.SPONGE_PERMISSION_CLEAR, Predicates.alwaysFalse(),
Arg.list(
Arg.create("contexts...", false, "the contexts to clear permissions in")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, SubjectData subjectData, List<String> args, String label) throws CommandException {
ContextSet contextSet = ArgumentUtils.handleContexts(0, args);
if (contextSet.isEmpty()) {
subjectData.clearPermissions();
Util.sendPluginMessage(sender, "&aCleared permissions matching contexts &bANY&a.");
} else {
subjectData.clearPermissions(SpongeUtils.convertContexts(contextSet));
Util.sendPluginMessage(sender, "&aCleared permissions matching contexts &b" + SpongeUtils.contextToString(contextSet));
}
return CommandResult.SUCCESS;
}
}
@@ -0,0 +1,79 @@
/*
* 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.sponge.commands;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class PermissionInfo extends SubCommand<SubjectData> {
public PermissionInfo() {
super("info", "Shows info about the subject's permissions", Permission.SPONGE_PERMISSION_INFO, Predicates.alwaysFalse(),
Arg.list(Arg.create("contexts...", false, "the contexts to filter by"))
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, SubjectData subjectData, List<String> args, String label) throws CommandException {
ContextSet contextSet = ArgumentUtils.handleContexts(0, args);
if (contextSet.isEmpty()) {
Util.sendPluginMessage(sender, "&aShowing permissions matching contexts &bANY&a.");
Map<Set<Context>, Map<String, Boolean>> permissions = subjectData.getAllPermissions();
if (permissions.isEmpty()) {
Util.sendPluginMessage(sender, "That subject does not have any permissions defined.");
return CommandResult.SUCCESS;
}
for (Map.Entry<Set<Context>, Map<String, Boolean>> e : permissions.entrySet()) {
ContextSet set = SpongeUtils.convertContexts(e.getKey());
Util.sendPluginMessage(sender, "&3>> &bContext: " + SpongeUtils.contextToString(set) + "\n" + SpongeUtils.nodesToString(e.getValue()));
}
} else {
Map<String, Boolean> permissions = subjectData.getPermissions(SpongeUtils.convertContexts(contextSet));
if (permissions.isEmpty()) {
Util.sendPluginMessage(sender, "That subject does not have any permissions defined in those contexts.");
return CommandResult.SUCCESS;
}
Util.sendPluginMessage(sender, "&aShowing permissions matching contexts &b" +
SpongeUtils.contextToString(contextSet) + "&a.\n" + SpongeUtils.nodesToString(permissions));
}
return CommandResult.SUCCESS;
}
}
@@ -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.sponge.commands;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.utils.Predicates;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.util.Tristate;
import java.util.List;
public class PermissionSet extends SubCommand<SubjectData> {
public PermissionSet() {
super("set", "Sets a permission for the Subject", Permission.SPONGE_PERMISSION_SET, Predicates.inRange(0, 1),
Arg.list(
Arg.create("node", true, "the permission node to set"),
Arg.create("tristate", true, "the value to set the permission to"),
Arg.create("contexts...", false, "the contexts to set the permission in")
)
);
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, SubjectData subjectData, List<String> args, String label) throws CommandException {
String node = args.get(0);
Tristate tristate = SpongeUtils.parseTristate(1, args);
ContextSet contextSet = ArgumentUtils.handleContexts(2, args);
if (subjectData.setPermission(SpongeUtils.convertContexts(contextSet), node, tristate)) {
Util.sendPluginMessage(sender, "&aSet &b" + node + "&a to &b" + tristate.toString().toLowerCase() + "&a in context " + SpongeUtils.contextToString(contextSet));
} else {
Util.sendPluginMessage(sender, "Unable to set permission. Does the Subject already have it set?");
}
return CommandResult.SUCCESS;
}
}
@@ -0,0 +1,232 @@
/*
* 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.sponge.commands;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.commands.*;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.Util;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.sponge.LPSpongePlugin;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
public class SpongeMainCommand extends BaseCommand<Void, SubjectData> {
private final LPSpongePlugin plugin;
private final Map<String, List<Command<SubjectData, ?>>> subCommands = ImmutableMap.<String, List<Command<SubjectData, ?>>>builder()
.put("permission", ImmutableList.<Command<SubjectData, ?>>builder()
.add(new PermissionInfo())
.add(new PermissionSet())
.add(new PermissionClear())
.build()
)
.put("parent", ImmutableList.<Command<SubjectData, ?>>builder()
.add(new ParentInfo())
.add(new ParentAdd())
.add(new ParentRemove())
.add(new ParentClear())
.build()
)
.put("option", ImmutableList.<Command<SubjectData, ?>>builder()
.add(new OptionInfo())
.add(new OptionSet())
.add(new OptionUnset())
.add(new OptionClear())
.build()
)
.build();
public SpongeMainCommand(LPSpongePlugin plugin) {
super(
"Sponge",
"Edit extra Sponge data",
null,
Predicates.alwaysFalse(),
Arg.list(
Arg.create("collection", true, "the collection to query"),
Arg.create("subject", true, "the subject to modify")
),
null
);
this.plugin = plugin;
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Void v, List<String> args, String label) throws CommandException {
LuckPermsService service = this.plugin.getService();
if (args.size() < 1) {
Util.sendPluginMessage(sender, "&aCurrent Subject Collections:\n" +
Util.listToCommaSep(service.getKnownSubjects().keySet().stream()
.filter(s -> !s.equalsIgnoreCase("user") && !s.equalsIgnoreCase("group"))
.collect(Collectors.toList())
)
);
return CommandResult.SUCCESS;
}
String subjectCollection = args.get(0);
if (subjectCollection.equalsIgnoreCase("user") || subjectCollection.equalsIgnoreCase("group")) {
Util.sendPluginMessage(sender, "Please use the main LuckPerms commands to edit users and groups.");
return CommandResult.STATE_ERROR;
}
if (service.getKnownSubjects().keySet().stream().map(String::toLowerCase).noneMatch(s -> s.equalsIgnoreCase(subjectCollection))) {
Util.sendPluginMessage(sender, "Warning: SubjectCollection '&4" + subjectCollection + "&c' doesn't already exist. Creating it now.");
}
SubjectCollection collection = service.getSubjects(subjectCollection);
if (args.size() < 2) {
List<String> subjects = StreamSupport.stream(collection.getAllSubjects().spliterator(), false)
.map(Subject::getIdentifier)
.collect(Collectors.toList());
if (subjects.size() > 50) {
List<String> extra = subjects.subList(50, subjects.size());
int overflow = extra.size();
extra.clear();
Util.sendPluginMessage(sender, "&aCurrent Subjects:\n" + Util.listToCommaSep(subjects) + "&b ... and &a" + overflow + " &bmore.");
} else {
Util.sendPluginMessage(sender, "&aCurrent Subjects:\n" + Util.listToCommaSep(subjects));
}
return CommandResult.SUCCESS;
}
if (args.size() < 4) {
sendDetailedUsage(sender, label);
return CommandResult.SUCCESS;
}
boolean persistent = true;
if (args.get(2).toLowerCase().startsWith("-t")) {
persistent = false;
args.remove(2);
}
String type = args.get(2).toLowerCase();
if (!type.equals("permission") && !type.equals("parent") && !type.equals("option")) {
sendDetailedUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
String cmd = args.get(3);
Optional<Command<SubjectData, ?>> o = subCommands.get(type).stream()
.filter(s -> s.getName().equalsIgnoreCase(cmd))
.findAny();
if (!o.isPresent()) {
sendDetailedUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
final Command<SubjectData, ?> sub = o.get();
if (!sub.isAuthorized(sender)) {
Message.COMMAND_NO_PERMISSION.send(sender);
return CommandResult.NO_PERMISSION;
}
List<String> strippedArgs = new ArrayList<>();
if (args.size() > 4) {
strippedArgs.addAll(args.subList(4, args.size()));
}
if (sub.getArgumentCheck().test(strippedArgs.size())) {
sub.sendDetailedUsage(sender, label);
return CommandResult.INVALID_ARGS;
}
String subjectId = args.get(1);
if (!collection.hasRegistered(subjectId)) {
Util.sendPluginMessage(sender, "Warning: Subject '&4" + subjectId + "&c' doesn't already exist. Creating it now.");
}
Subject subject = collection.get(subjectId);
SubjectData subjectData = persistent ? subject.getSubjectData() : subject.getTransientSubjectData();
CommandResult result;
try {
result = sub.execute(plugin, sender, subjectData, strippedArgs, label);
} catch (CommandException e) {
result = CommandManager.handleException(e, sender, label, sub);
}
return result;
}
// TODO tab completion
@Override
public void sendUsage(Sender sender, String label) {
Util.sendPluginMessage(sender, "&3> &a" + String.format(getUsage(), label));
}
@Override
public void sendDetailedUsage(Sender sender, String label) {
Util.sendPluginMessage(sender, "&b" + getName() + " Sub Commands: &7(" + String.format("/%s sponge <collection> <subject> [-transient]", label) + " ...)");
for (String s : Arrays.asList("Permission", "Parent", "Option")) {
List<Command> subs = subCommands.get(s.toLowerCase()).stream()
.filter(sub -> sub.isAuthorized(sender))
.collect(Collectors.toList());
if (!subs.isEmpty()) {
Util.sendPluginMessage(sender, "&3>> &b" + s);
for (Command sub : subs) {
sub.sendUsage(sender, label);
}
}
}
}
@Override
public boolean isAuthorized(Sender sender) {
return getSubCommands().stream().filter(sc -> sc.isAuthorized(sender)).count() != 0;
}
@Override
public String getUsage() {
return "/%s sponge <collection> <subject>";
}
public List<Command<SubjectData, ?>> getSubCommands() {
return subCommands.values().stream().flatMap(List::stream).collect(ImmutableCollectors.toImmutableList());
}
@Override
public Optional<List<Command<SubjectData, ?>>> getChildren() {
return Optional.of(getSubCommands());
}
}
@@ -0,0 +1,110 @@
/*
* 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.sponge.commands;
import com.google.common.collect.Maps;
import lombok.experimental.UtilityClass;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.util.Tristate;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@UtilityClass
public class SpongeUtils {
public static Tristate parseTristate(int index, List<String> args) throws ArgumentUtils.ArgumentException {
String s = args.get(index).toLowerCase();
if (s.equals("1") || s.equals("true") || s.equals("t")) {
return Tristate.TRUE;
}
if (s.equals("0") || s.equals("null") || s.equals("none") || s.equals("undefined") || s.equals("undef")) {
return Tristate.UNDEFINED;
}
if (s.equals("-1") || s.equals("false") || s.equals("f")) {
return Tristate.FALSE;
}
throw new ArgumentUtils.DetailedUsageException();
}
public static String nodesToString(Map<String, Boolean> nodes) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Boolean> e : nodes.entrySet()) {
sb.append("&3> ")
.append(e.getValue() ? "&a" : "&c")
.append(e.getKey())
.append("\n");
}
return sb.toString();
}
public static String optionsToString(Map<String, String> options) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> e : options.entrySet()) {
sb.append("&3> &a")
.append(e.getKey())
.append(" &f= \"")
.append(e.getKey())
.append("&f\"\n");
}
return sb.toString();
}
public static String parentsToString(List<Subject> parents) {
StringBuilder sb = new StringBuilder();
for (Subject s : parents) {
sb.append("&3> &a")
.append(s.getIdentifier())
.append(" &bfrom collection &a")
.append(s.getContainingCollection().getIdentifier())
.append("&b.\n");
}
return sb.toString();
}
public static String contextToString(ContextSet set) {
if (set.isEmpty()) {
return "&bGLOBAL";
}
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> e : set.toSet()) {
sb.append("&f").append(e.getKey()).append("&7=&f").append(e.getValue()).append("&7, ");
}
return sb.delete(sb.length() - 2, sb.length()).toString();
}
public static ContextSet convertContexts(Set<Context> contexts) {
return ContextSet.fromEntries(contexts.stream().map(c -> Maps.immutableEntry(c.getKey(), c.getValue())).collect(Collectors.toSet()));
}
public static Set<Context> convertContexts(ContextSet contexts) {
return contexts.toSet().stream().map(e -> new Context(e.getKey(), e.getValue())).collect(Collectors.toSet());
}
}
@@ -24,9 +24,10 @@ package me.lucko.luckperms.sponge.migration;
import lombok.experimental.UtilityClass;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.sponge.service.LuckPermsService;
import org.spongepowered.api.service.context.Context;
@@ -46,11 +47,10 @@ public class MigrationUtils {
for (Map.Entry<Set<Context>, Map<String, Boolean>> e : perms.entrySet()) {
ContextSet context = LuckPermsService.convertContexts(e.getKey());
MutableContextSet contexts = MutableContextSet.fromSet(context);
String server = contexts.getValues("server").stream().findAny().orElse(null);
String world = contexts.getValues("world").stream().findAny().orElse(null);
contexts.removeAll("server");
contexts.removeAll("world");
ExtractedContexts extractedContexts = ExtractedContexts.generate(context);
ContextSet contexts = extractedContexts.getContextSet();
String server = extractedContexts.getServer();
String world = extractedContexts.getWorld();
for (Map.Entry<String, Boolean> perm : e.getValue().entrySet()) {
try {
@@ -65,20 +65,23 @@ public class MigrationUtils {
for (Map.Entry<Set<Context>, Map<String, String>> e : opts.entrySet()) {
ContextSet context = LuckPermsService.convertContexts(e.getKey());
MutableContextSet contexts = MutableContextSet.fromSet(context);
String server = contexts.getValues("server").stream().findAny().orElse(null);
String world = contexts.getValues("world").stream().findAny().orElse(null);
contexts.removeAll("server");
contexts.removeAll("world");
ExtractedContexts extractedContexts = ExtractedContexts.generate(context);
ContextSet contexts = extractedContexts.getContextSet();
String server = extractedContexts.getServer();
String world = extractedContexts.getWorld();
for (Map.Entry<String, String> opt : e.getValue().entrySet()) {
if (opt.getKey().equalsIgnoreCase("prefix") || opt.getKey().equalsIgnoreCase("suffix")) {
if (opt.getKey().equalsIgnoreCase("prefix")) {
try {
holder.setPermission(new NodeBuilder(opt.getKey().toLowerCase() + ".100." + opt.getValue()).setServerRaw(server).setWorld(world).withExtraContext(contexts).setValue(true).build());
holder.setPermission(NodeFactory.makePrefixNode(100, opt.getValue()).setServerRaw(server).setWorld(world).withExtraContext(contexts).setValue(true).build());
} catch (ObjectAlreadyHasException ignored) {}
} else if (opt.getKey().equalsIgnoreCase("suffix")) {
try {
holder.setPermission(NodeFactory.makeSuffixNode(100, opt.getValue()).setServerRaw(server).setWorld(world).withExtraContext(contexts).setValue(true).build());
} catch (ObjectAlreadyHasException ignored) {}
} else {
try {
holder.setPermission(new NodeBuilder("meta." + opt.getKey() + "." + opt.getValue()).setServerRaw(server).setWorld(world).withExtraContext(contexts).setValue(true).build());
holder.setPermission(NodeFactory.makeMetaNode(opt.getKey(), opt.getValue()).setServerRaw(server).setWorld(world).withExtraContext(contexts).setValue(true).build());
} catch (ObjectAlreadyHasException ignored) {}
}
}
@@ -93,11 +96,10 @@ public class MigrationUtils {
for (Map.Entry<Set<Context>, List<Subject>> e : parents.entrySet()) {
ContextSet context = LuckPermsService.convertContexts(e.getKey());
MutableContextSet contexts = MutableContextSet.fromSet(context);
String server = contexts.getValues("server").stream().findAny().orElse(null);
String world = contexts.getValues("world").stream().findAny().orElse(null);
contexts.removeAll("server");
contexts.removeAll("world");
ExtractedContexts extractedContexts = ExtractedContexts.generate(context);
ContextSet contexts = extractedContexts.getContextSet();
String server = extractedContexts.getServer();
String world = extractedContexts.getWorld();
for (Subject s : e.getValue()) {
if (!s.getContainingCollection().getIdentifier().equalsIgnoreCase(PermissionService.SUBJECTS_GROUP)) {
@@ -31,6 +31,7 @@ import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.utils.ExtractedContexts;
import me.lucko.luckperms.sponge.timings.LPTiming;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.permission.NodeTree;
@@ -84,7 +85,7 @@ public class LuckPermsGroupSubject extends LuckPermsSubject {
@Override
public Tristate getPermissionValue(ContextSet contexts, String permission) {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.GROUP_GET_PERMISSION_VALUE)) {
Map<String, Boolean> permissions = group.getAllNodesFiltered(service.calculateContexts(contexts)).stream()
Map<String, Boolean> permissions = group.getAllNodesFiltered(ExtractedContexts.generate(service.calculateContexts(contexts))).stream()
.map(LocalizedNode::getNode)
.collect(Collectors.toMap(Node::getPermission, Node::getValue));
@@ -113,7 +114,7 @@ public class LuckPermsGroupSubject extends LuckPermsSubject {
@Override
public List<Subject> getParents(ContextSet contexts) {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.GROUP_GET_PARENTS)) {
List<Subject> subjects = group.getAllNodesFiltered(service.calculateContexts(contexts)).stream()
List<Subject> subjects = group.getAllNodesFiltered(ExtractedContexts.generate(service.calculateContexts(contexts))).stream()
.map(LocalizedNode::getNode)
.filter(Node::isGroupNode)
.map(Node::getGroupName)
@@ -165,7 +166,7 @@ public class LuckPermsGroupSubject extends LuckPermsSubject {
int priority = Integer.MIN_VALUE;
String meta = null;
for (Node n : group.getAllNodesFiltered(service.calculateContexts(contexts))) {
for (Node n : group.getAllNodesFiltered(ExtractedContexts.generate(service.calculateContexts(contexts)))) {
if (!n.getValue()) {
continue;
}
@@ -185,7 +186,7 @@ public class LuckPermsGroupSubject extends LuckPermsSubject {
}
private Optional<String> getMeta(ContextSet contexts, String key) {
for (Node n : group.getAllNodesFiltered(service.calculateContexts(contexts))) {
for (Node n : group.getAllNodesFiltered(ExtractedContexts.generate(service.calculateContexts(contexts)))) {
if (!n.getValue()) {
continue;
}
@@ -32,6 +32,7 @@ import lombok.NonNull;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.PermissionHolder;
import me.lucko.luckperms.common.groups.Group;
import me.lucko.luckperms.common.users.User;
@@ -46,8 +47,6 @@ import org.spongepowered.api.util.Tristate;
import java.util.*;
import java.util.stream.Collectors;
import static me.lucko.luckperms.api.MetaUtils.escapeCharacters;
@SuppressWarnings({"OptionalGetWithoutIsPresent", "unused"})
@AllArgsConstructor
public class LuckPermsSubjectData implements SubjectData {
@@ -364,16 +363,15 @@ public class LuckPermsSubjectData implements SubjectData {
public Map<Set<Context>, Map<String, String>> getAllOptions() {
try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_GET_OPTIONS)) {
Map<Set<Context>, Map<String, String>> options = new HashMap<>();
int prefixPriority = Integer.MIN_VALUE;
int suffixPriority = Integer.MIN_VALUE;
Map<Set<Context>, Integer> minPrefixPriority = new HashMap<>();
Map<Set<Context>, Integer> minSuffixPriority = new HashMap<>();
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
if (!n.getValue()) {
continue;
}
if (!n.isMeta() || !n.isPrefix() || n.isSuffix()) {
if (!n.isMeta() && !n.isPrefix() && !n.isSuffix()) {
continue;
}
@@ -389,22 +387,24 @@ public class LuckPermsSubjectData implements SubjectData {
if (!options.containsKey(contexts)) {
options.put(contexts, new HashMap<>());
minPrefixPriority.put(contexts, Integer.MIN_VALUE);
minSuffixPriority.put(contexts, Integer.MIN_VALUE);
}
if (n.isPrefix()) {
Map.Entry<Integer, String> value = n.getPrefix();
if (value.getKey() > prefixPriority) {
if (value.getKey() > minPrefixPriority.get(contexts)) {
options.get(contexts).put("prefix", value.getValue());
prefixPriority = value.getKey();
minPrefixPriority.put(contexts, value.getKey());
}
continue;
}
if (n.isSuffix()) {
Map.Entry<Integer, String> value = n.getSuffix();
if (value.getKey() > suffixPriority) {
if (value.getKey() > minSuffixPriority.get(contexts)) {
options.get(contexts).put("suffix", value.getValue());
suffixPriority = value.getKey();
minSuffixPriority.put(contexts, value.getKey());
}
continue;
}
@@ -433,20 +433,21 @@ public class LuckPermsSubjectData implements SubjectData {
try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_SET_OPTION)) {
ContextSet context = LuckPermsService.convertContexts(set);
key = escapeCharacters(key);
value = escapeCharacters(value);
List<Node> toRemove = holder.getNodes().stream()
.filter(n -> n.isMeta() && n.getMeta().getKey().equals(key))
.collect(Collectors.toList());
toRemove.forEach(n -> {
try {
holder.unsetPermission(n);
} catch (ObjectLacksException ignored) {}
});
try {
if (enduring) {
holder.setPermission(new NodeBuilder("meta." + key + "." + value)
.withExtraContext(context)
.build()
);
holder.setPermission(NodeFactory.makeMetaNode(key, value).withExtraContext(context).build());
} else {
holder.setTransientPermission(new NodeBuilder("meta." + key + "." + value)
.withExtraContext(context)
.build()
);
holder.setTransientPermission(NodeFactory.makeMetaNode(key, value).withExtraContext(context).build());
}
} catch (ObjectAlreadyHasException ignored) {}
objectSave(holder);
@@ -110,6 +110,10 @@ public class UserCollection implements SubjectCollection {
service.getPlugin().getLog().warn("User Subject '" + u + "' was requested, but is not loaded in memory. Loading them from storage now.");
long startTime = System.currentTimeMillis();
service.getPlugin().getStorage().loadUser(u, "null").join();
User user = service.getPlugin().getUserManager().get(u);
if (user != null) {
user.setupData(false);
}
service.getPlugin().getLog().warn("Loading '" + u + "' took " + (System.currentTimeMillis() - startTime) + " ms.");
}