Rebuild default and child permission lookup maps live instead of only once when the plugin first enables
This commit is contained in:
parent
fd937e3209
commit
173286d404
@ -129,6 +129,14 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- caffeine -->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>2.6.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Spigot -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
|
@ -34,14 +34,15 @@ import me.lucko.luckperms.bukkit.contexts.WorldCalculator;
|
||||
import me.lucko.luckperms.bukkit.listeners.BukkitConnectionListener;
|
||||
import me.lucko.luckperms.bukkit.listeners.BukkitPlatformListener;
|
||||
import me.lucko.luckperms.bukkit.messaging.BukkitMessagingFactory;
|
||||
import me.lucko.luckperms.bukkit.model.PermissionMapInjector;
|
||||
import me.lucko.luckperms.bukkit.model.SubscriptionMapInjector;
|
||||
import me.lucko.luckperms.bukkit.model.permissible.LPPermissible;
|
||||
import me.lucko.luckperms.bukkit.model.permissible.PermissibleInjector;
|
||||
import me.lucko.luckperms.bukkit.model.permissible.PermissibleMonitoringInjector;
|
||||
import me.lucko.luckperms.bukkit.processors.BukkitProcessorsSetupTask;
|
||||
import me.lucko.luckperms.bukkit.processors.ChildPermissionProvider;
|
||||
import me.lucko.luckperms.bukkit.processors.DefaultsProvider;
|
||||
import me.lucko.luckperms.bukkit.model.server.InjectorDefaultsMap;
|
||||
import me.lucko.luckperms.bukkit.model.server.InjectorPermissionMap;
|
||||
import me.lucko.luckperms.bukkit.model.server.InjectorSubscriptionMap;
|
||||
import me.lucko.luckperms.bukkit.model.server.LPDefaultsMap;
|
||||
import me.lucko.luckperms.bukkit.model.server.LPPermissionMap;
|
||||
import me.lucko.luckperms.bukkit.model.server.LPSubscriptionMap;
|
||||
import me.lucko.luckperms.bukkit.vault.VaultHookManager;
|
||||
import me.lucko.luckperms.common.actionlog.LogDispatcher;
|
||||
import me.lucko.luckperms.common.api.ApiRegistrationUtil;
|
||||
@ -86,6 +87,7 @@ import me.lucko.luckperms.common.verbose.VerboseHandler;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
@ -123,8 +125,9 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private LuckPermsApiProvider apiProvider;
|
||||
private EventFactory eventFactory;
|
||||
private Logger log;
|
||||
private DefaultsProvider defaultsProvider;
|
||||
private ChildPermissionProvider childPermissionProvider;
|
||||
private LPSubscriptionMap subscriptionMap;
|
||||
private LPPermissionMap permissionMap;
|
||||
private LPDefaultsMap defaultPermissionMap;
|
||||
private LocaleManager localeManager;
|
||||
private PluginClassLoader pluginClassLoader;
|
||||
private DependencyManager dependencyManager;
|
||||
@ -197,10 +200,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
Set<StorageType> storageTypes = storageFactory.getRequiredTypes(StorageType.H2);
|
||||
this.dependencyManager.loadStorageDependencies(storageTypes);
|
||||
|
||||
// init the Bukkit model providers
|
||||
this.defaultsProvider = new DefaultsProvider();
|
||||
this.childPermissionProvider = new ChildPermissionProvider();
|
||||
|
||||
// register events
|
||||
BukkitConnectionListener connectionListener = new BukkitConnectionListener(this);
|
||||
getServer().getPluginManager().registerEvents(connectionListener, this);
|
||||
@ -246,21 +245,19 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
this.contextManager.registerStaticCalculator(new LuckPermsCalculator(getConfiguration()));
|
||||
|
||||
// inject our own custom permission maps
|
||||
SubscriptionMapInjector subscriptionMapInjector = new SubscriptionMapInjector(this);
|
||||
subscriptionMapInjector.run();
|
||||
Runnable[] injectors = new Runnable[]{
|
||||
new InjectorSubscriptionMap(this),
|
||||
new InjectorPermissionMap(this),
|
||||
new InjectorDefaultsMap(this)
|
||||
};
|
||||
|
||||
PermissionMapInjector permissionMapInjector = new PermissionMapInjector(this);
|
||||
permissionMapInjector.run();
|
||||
for (Runnable injector : injectors) {
|
||||
injector.run();
|
||||
|
||||
// setup the bukkit processors
|
||||
BukkitProcessorsSetupTask bukkitProcessorsSetupTask = new BukkitProcessorsSetupTask(this);
|
||||
bukkitProcessorsSetupTask.run();
|
||||
|
||||
// schedule another injection after all plugins have loaded - the entire pluginmanager instance
|
||||
// is replaced by some plugins :(
|
||||
this.scheduler.asyncLater(subscriptionMapInjector, 1L);
|
||||
this.scheduler.asyncLater(permissionMapInjector, 1L);
|
||||
this.scheduler.syncLater(bukkitProcessorsSetupTask, 1L);
|
||||
// schedule another injection after all plugins have loaded
|
||||
// the entire pluginmanager instance is replaced by some plugins :(
|
||||
this.scheduler.asyncLater(injector, 1L);
|
||||
}
|
||||
|
||||
// inject verbose handlers into internal bukkit objects
|
||||
new PermissibleMonitoringInjector(this).run();
|
||||
@ -305,7 +302,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
PermissionDefault permDefault = getConfiguration().get(ConfigKeys.COMMANDS_ALLOW_OP) ? PermissionDefault.OP : PermissionDefault.FALSE;
|
||||
|
||||
for (CommandPermission p : CommandPermission.values()) {
|
||||
pm.addPermission(new org.bukkit.permissions.Permission(p.getPermission(), permDefault));
|
||||
pm.addPermission(new Permission(p.getPermission(), permDefault));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// this throws an exception if the plugin is /reloaded, grr
|
||||
@ -351,7 +348,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
// Switch back to the fallback executor, the bukkit one won't allow new tasks
|
||||
this.scheduler.setUseFallback(true);
|
||||
|
||||
this.defaultsProvider.close();
|
||||
this.permissionVault.shutdown();
|
||||
this.verboseHandler.shutdown();
|
||||
|
||||
@ -375,8 +371,9 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
}
|
||||
|
||||
// uninject custom maps
|
||||
SubscriptionMapInjector.uninject();
|
||||
PermissionMapInjector.uninject();
|
||||
InjectorSubscriptionMap.uninject();
|
||||
InjectorPermissionMap.uninject();
|
||||
InjectorDefaultsMap.uninject();
|
||||
|
||||
getLog().info("Closing storage...");
|
||||
this.storage.shutdown();
|
||||
@ -447,6 +444,30 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
return configFile;
|
||||
}
|
||||
|
||||
public LPSubscriptionMap getSubscriptionMap() {
|
||||
return this.subscriptionMap;
|
||||
}
|
||||
|
||||
public void setSubscriptionMap(LPSubscriptionMap subscriptionMap) {
|
||||
this.subscriptionMap = subscriptionMap;
|
||||
}
|
||||
|
||||
public LPPermissionMap getPermissionMap() {
|
||||
return this.permissionMap;
|
||||
}
|
||||
|
||||
public void setPermissionMap(LPPermissionMap permissionMap) {
|
||||
this.permissionMap = permissionMap;
|
||||
}
|
||||
|
||||
public LPDefaultsMap getDefaultPermissionMap() {
|
||||
return this.defaultPermissionMap;
|
||||
}
|
||||
|
||||
public void setDefaultPermissionMap(LPDefaultsMap defaultPermissionMap) {
|
||||
this.defaultPermissionMap = defaultPermissionMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InternalMessagingService> getMessagingService() {
|
||||
return Optional.ofNullable(this.messagingService);
|
||||
@ -627,14 +648,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
return this.log;
|
||||
}
|
||||
|
||||
public DefaultsProvider getDefaultsProvider() {
|
||||
return this.defaultsProvider;
|
||||
}
|
||||
|
||||
public ChildPermissionProvider getChildPermissionProvider() {
|
||||
return this.childPermissionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocaleManager getLocaleManager() {
|
||||
return this.localeManager;
|
||||
|
@ -55,7 +55,7 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
processors.add(new MapProcessor());
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_CHILD_PERMISSIONS)) {
|
||||
processors.add(new ChildProcessor(this.plugin.getChildPermissionProvider()));
|
||||
processors.add(new ChildProcessor(this.plugin));
|
||||
}
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) {
|
||||
@ -67,7 +67,7 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
}
|
||||
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS) && metadata.getHolderType() == HolderType.USER) {
|
||||
processors.add(new DefaultsProcessor(contexts.isOp(), this.plugin.getDefaultsProvider()));
|
||||
processors.add(new DefaultsProcessor(this.plugin, contexts.isOp()));
|
||||
}
|
||||
|
||||
return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build()));
|
||||
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.treeview.PermissionVault;
|
||||
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A replacement map for the 'permissions' instance in Bukkit's SimplePluginManager.
|
||||
*
|
||||
* This instance allows LuckPerms to intercept calls to
|
||||
* {@link PluginManager#addPermission(Permission)} and record permissions in the
|
||||
* {@link PermissionVault}.
|
||||
*
|
||||
* Injected by {@link PermissionMapInjector}.
|
||||
*/
|
||||
public class LPPermissionMap extends HashMap<String, Permission> {
|
||||
final LuckPermsPlugin plugin;
|
||||
|
||||
public LPPermissionMap(LuckPermsPlugin plugin, Map<String, Permission> existingData) {
|
||||
this.plugin = plugin;
|
||||
putAll(existingData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission put(String key, Permission value) {
|
||||
this.plugin.getPermissionVault().offer(key);
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends Permission> m) {
|
||||
this.plugin.getPermissionVault().offerAll(m.keySet());
|
||||
super.putAll(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission putIfAbsent(String key, Permission value) {
|
||||
this.plugin.getPermissionVault().offer(key);
|
||||
return super.putIfAbsent(key, value);
|
||||
}
|
||||
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model.dummy;
|
||||
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class DummyPermissible implements Permissible {
|
||||
private final Runnable onRefresh;
|
||||
|
||||
public DummyPermissible(Runnable onRefresh) {
|
||||
this.onRefresh = onRefresh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recalculatePermissions() {
|
||||
this.onRefresh.run();
|
||||
}
|
||||
|
||||
@Override public Set<PermissionAttachmentInfo> getEffectivePermissions() { return Collections.emptySet(); }
|
||||
@Override public boolean isPermissionSet(String name) { return false; }
|
||||
@Override public boolean isPermissionSet(Permission perm) { return false; }
|
||||
@Override public boolean hasPermission(String name) { return false; }
|
||||
@Override public boolean hasPermission(Permission perm) { return false; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, int ticks) { return null; }
|
||||
@Override public void removeAttachment(PermissionAttachment attachment) {}
|
||||
@Override public boolean isOp() { return false; }
|
||||
@Override public void setOp(boolean value) {}
|
||||
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model.server;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Injects a {@link LPDefaultsMap} info the {@link PluginManager}.
|
||||
*/
|
||||
public class InjectorDefaultsMap implements Runnable {
|
||||
private static final Field DEFAULT_PERMISSIONS_FIELD;
|
||||
|
||||
static {
|
||||
Field permissionsField = null;
|
||||
try {
|
||||
permissionsField = SimplePluginManager.class.getDeclaredField("defaultPerms");
|
||||
permissionsField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
DEFAULT_PERMISSIONS_FIELD = permissionsField;
|
||||
}
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public InjectorDefaultsMap(LPBukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
LPDefaultsMap ret = inject();
|
||||
if (ret != null) {
|
||||
this.plugin.setDefaultPermissionMap(ret);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.plugin.getLog().severe("Exception occurred whilst injecting LuckPerms Default Permission map.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private LPDefaultsMap inject() throws Exception {
|
||||
Objects.requireNonNull(DEFAULT_PERMISSIONS_FIELD, "DEFAULT_PERMISSIONS_FIELD");
|
||||
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
|
||||
|
||||
if (!(pluginManager instanceof SimplePluginManager)) {
|
||||
this.plugin.getLog().severe("PluginManager instance is not a 'SimplePluginManager', instead: " + pluginManager.getClass());
|
||||
this.plugin.getLog().severe("Unable to inject LuckPerms Default Permission map.");
|
||||
return null;
|
||||
}
|
||||
|
||||
Object map = DEFAULT_PERMISSIONS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPDefaultsMap && ((LPDefaultsMap) map).plugin == this.plugin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
Map<Boolean, Set<Permission>> castedMap = (Map<Boolean, Set<Permission>>) map;
|
||||
|
||||
// make a new map & inject it
|
||||
LPDefaultsMap newMap = new LPDefaultsMap(this.plugin, castedMap);
|
||||
DEFAULT_PERMISSIONS_FIELD.set(pluginManager, newMap);
|
||||
return newMap;
|
||||
}
|
||||
|
||||
public static void uninject() {
|
||||
try {
|
||||
Objects.requireNonNull(DEFAULT_PERMISSIONS_FIELD, "DEFAULT_PERMISSIONS_FIELD");
|
||||
|
||||
PluginManager pluginManager = Bukkit.getServer().getPluginManager();
|
||||
if (!(pluginManager instanceof SimplePluginManager)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object map = DEFAULT_PERMISSIONS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPDefaultsMap) {
|
||||
LPDefaultsMap lpMap = (LPDefaultsMap) map;
|
||||
DEFAULT_PERMISSIONS_FIELD.set(pluginManager, new HashMap<>(lpMap));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model;
|
||||
package me.lucko.luckperms.bukkit.model.server;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
|
||||
@ -40,7 +40,7 @@ import java.util.Objects;
|
||||
/**
|
||||
* Injects a {@link LPPermissionMap} into the {@link PluginManager}.
|
||||
*/
|
||||
public class PermissionMapInjector implements Runnable {
|
||||
public class InjectorPermissionMap implements Runnable {
|
||||
private static final Field PERMISSIONS_FIELD;
|
||||
|
||||
static {
|
||||
@ -56,43 +56,45 @@ public class PermissionMapInjector implements Runnable {
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public PermissionMapInjector(LPBukkitPlugin plugin) {
|
||||
public InjectorPermissionMap(LPBukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
inject();
|
||||
LPPermissionMap ret = inject();
|
||||
if (ret != null) {
|
||||
this.plugin.setPermissionMap(ret);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.plugin.getLog().severe("Exception occurred whilst injecting LuckPerms Permission map.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void inject() throws Exception {
|
||||
private LPPermissionMap inject() throws Exception {
|
||||
Objects.requireNonNull(PERMISSIONS_FIELD, "PERMISSIONS_FIELD");
|
||||
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
|
||||
|
||||
if (!(pluginManager instanceof SimplePluginManager)) {
|
||||
this.plugin.getLog().severe("PluginManager instance is not a 'SimplePluginManager', instead: " + pluginManager.getClass());
|
||||
this.plugin.getLog().severe("Unable to inject LuckPerms Permission map.");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
Object map = PERMISSIONS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPPermissionMap && ((LPPermissionMap) map).plugin == this.plugin) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
Map<String, Permission> castedMap = (Map<String, Permission>) map;
|
||||
|
||||
// make a new map
|
||||
// make a new map & inject it
|
||||
LPPermissionMap newMap = new LPPermissionMap(this.plugin, castedMap);
|
||||
|
||||
// inject it
|
||||
PERMISSIONS_FIELD.set(pluginManager, newMap);
|
||||
return newMap;
|
||||
}
|
||||
|
||||
public static void uninject() {
|
@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model;
|
||||
package me.lucko.luckperms.bukkit.model.server;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
|
||||
@ -39,7 +39,7 @@ import java.util.Objects;
|
||||
/**
|
||||
* Injects a {@link LPSubscriptionMap} into the {@link PluginManager}.
|
||||
*/
|
||||
public class SubscriptionMapInjector implements Runnable {
|
||||
public class InjectorSubscriptionMap implements Runnable {
|
||||
private static final Field PERM_SUBS_FIELD;
|
||||
|
||||
static {
|
||||
@ -55,34 +55,37 @@ public class SubscriptionMapInjector implements Runnable {
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public SubscriptionMapInjector(LPBukkitPlugin plugin) {
|
||||
public InjectorSubscriptionMap(LPBukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
inject();
|
||||
LPSubscriptionMap ret = inject();
|
||||
if (ret != null) {
|
||||
this.plugin.setSubscriptionMap(ret);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.plugin.getLog().severe("Exception occurred whilst injecting LuckPerms Permission Subscription map.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void inject() throws Exception {
|
||||
private LPSubscriptionMap inject() throws Exception {
|
||||
Objects.requireNonNull(PERM_SUBS_FIELD, "PERM_SUBS_FIELD");
|
||||
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
|
||||
|
||||
if (!(pluginManager instanceof SimplePluginManager)) {
|
||||
this.plugin.getLog().severe("PluginManager instance is not a 'SimplePluginManager', instead: " + pluginManager.getClass());
|
||||
this.plugin.getLog().severe("Unable to inject LuckPerms Permission Subscription map.");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
Object map = PERM_SUBS_FIELD.get(pluginManager);
|
||||
if (map instanceof LPSubscriptionMap) {
|
||||
if (((LPSubscriptionMap) map).plugin == this.plugin) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
map = ((LPSubscriptionMap) map).detach();
|
||||
@ -91,11 +94,10 @@ public class SubscriptionMapInjector implements Runnable {
|
||||
//noinspection unchecked
|
||||
Map<String, Map<Permissible, Boolean>> castedMap = (Map<String, Map<Permissible, Boolean>>) map;
|
||||
|
||||
// make a new subscription map
|
||||
// make a new subscription map & inject it
|
||||
LPSubscriptionMap newMap = new LPSubscriptionMap(this.plugin, castedMap);
|
||||
|
||||
// inject it
|
||||
PERM_SUBS_FIELD.set(pluginManager, newMap);
|
||||
return newMap;
|
||||
}
|
||||
|
||||
public static void uninject() {
|
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model.server;
|
||||
|
||||
import com.google.common.collect.ForwardingSet;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* A replacement map for the 'defaultPerms' instance in Bukkit's SimplePluginManager.
|
||||
*
|
||||
* This instance allows LuckPerms to intercept calls to
|
||||
* {@link PluginManager#addPermission(Permission)}, specifically regarding
|
||||
* the default nature of the permission.
|
||||
*
|
||||
* Injected by {@link InjectorDefaultsMap}.
|
||||
*/
|
||||
public class LPDefaultsMap implements Map<Boolean, Set<Permission>> {
|
||||
// keyset for all instances
|
||||
private static final Set<Boolean> KEY_SET = ImmutableSet.of(Boolean.TRUE, Boolean.FALSE);
|
||||
|
||||
// the plugin
|
||||
final LPBukkitPlugin plugin;
|
||||
|
||||
// the two values in the map
|
||||
private final Set<Permission> opSet = new DefaultPermissionSet(true);
|
||||
private final Set<Permission> nonOpSet = new DefaultPermissionSet(false);
|
||||
|
||||
// fully resolved defaults (accounts for child permissions too)
|
||||
private Map<String, Boolean> resolvedOpDefaults = ImmutableMap.of();
|
||||
private Map<String, Boolean> resolvedNonOpDefaults = ImmutableMap.of();
|
||||
|
||||
// #values and #entrySet results - both immutable
|
||||
private final Collection<Set<Permission>> values = ImmutableList.of(this.opSet, this.nonOpSet);
|
||||
private final Set<Entry<Boolean, Set<Permission>>> entrySet = ImmutableSet.of(
|
||||
Maps.immutableEntry(Boolean.TRUE, this.opSet),
|
||||
Maps.immutableEntry(Boolean.FALSE, this.nonOpSet)
|
||||
);
|
||||
|
||||
public LPDefaultsMap(LPBukkitPlugin plugin, Map<Boolean, Set<Permission>> existingData) {
|
||||
this.plugin = plugin;
|
||||
this.opSet.addAll(existingData.getOrDefault(Boolean.TRUE, Collections.emptySet()));
|
||||
this.nonOpSet.addAll(existingData.getOrDefault(Boolean.FALSE, Collections.emptySet()));
|
||||
refreshOp();
|
||||
refreshNonOp();
|
||||
}
|
||||
|
||||
public Set<Permission> getOpPermissions() {
|
||||
return this.opSet;
|
||||
}
|
||||
|
||||
public Set<Permission> getNonOpPermissions() {
|
||||
return this.nonOpSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries whether a given permission should be granted by default.
|
||||
*
|
||||
* @param permission the permission to query
|
||||
* @param isOp if the player is op
|
||||
* @return a tristate result
|
||||
*/
|
||||
public Tristate lookupDefaultPermission(String permission, boolean isOp) {
|
||||
Map<String, Boolean> map = isOp ? this.resolvedOpDefaults : this.resolvedNonOpDefaults;
|
||||
return Tristate.fromNullableBoolean(map.get(permission));
|
||||
}
|
||||
|
||||
private void refresh(boolean op) {
|
||||
if (op) {
|
||||
refreshOp();
|
||||
} else {
|
||||
refreshNonOp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the op data in this provider.
|
||||
*/
|
||||
private void refreshOp() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : getOpPermissions()) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
}
|
||||
}
|
||||
this.resolvedOpDefaults = ImmutableMap.copyOf(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the non op data in this provider.
|
||||
*/
|
||||
private void refreshNonOp() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : getNonOpPermissions()) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
}
|
||||
}
|
||||
this.resolvedNonOpDefaults = ImmutableMap.copyOf(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Permission> get(Object key) {
|
||||
boolean b = (boolean) key;
|
||||
return b ? this.opSet : this.nonOpSet;
|
||||
}
|
||||
|
||||
// return wrappers around this map impl
|
||||
@Nonnull @Override public Collection<Set<Permission>> values() { return this.values; }
|
||||
@Nonnull @Override public Set<Entry<Boolean, Set<Permission>>> entrySet() { return this.entrySet; }
|
||||
@Nonnull @Override public Set<Boolean> keySet() { return KEY_SET; }
|
||||
|
||||
// return accurate results for the Map spec
|
||||
@Override public int size() { return 2; }
|
||||
@Override public boolean isEmpty() { return false; }
|
||||
@Override public boolean containsKey(Object key) { return key instanceof Boolean; }
|
||||
@Override public boolean containsValue(Object value) { return value == this.opSet || value == this.nonOpSet; }
|
||||
|
||||
// throw unsupported operation exceptions
|
||||
@Override public Set<Permission> put(Boolean key, Set<Permission> value) { throw new UnsupportedOperationException(); }
|
||||
@Override public Set<Permission> remove(Object key) { throw new UnsupportedOperationException(); }
|
||||
@Override public void putAll(@Nonnull Map<? extends Boolean, ? extends Set<Permission>> m) { throw new UnsupportedOperationException(); }
|
||||
@Override public void clear() { throw new UnsupportedOperationException(); }
|
||||
|
||||
private final class DefaultPermissionSet extends ForwardingSet<Permission> {
|
||||
private final Set<Permission> delegate = ConcurrentHashMap.newKeySet();
|
||||
private final boolean op;
|
||||
|
||||
private DefaultPermissionSet(boolean op) {
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<Permission> delegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(@Nonnull Permission element) {
|
||||
boolean ret = super.add(element);
|
||||
refresh(this.op);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(@Nonnull Collection<? extends Permission> collection) {
|
||||
boolean ret = super.addAll(collection);
|
||||
refresh(this.op);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model.server;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.treeview.PermissionVault;
|
||||
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.annotation.CheckForNull;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* A replacement map for the 'permissions' instance in Bukkit's SimplePluginManager.
|
||||
*
|
||||
* This instance allows LuckPerms to intercept calls to
|
||||
* {@link PluginManager#addPermission(Permission)} and record permissions in the
|
||||
* {@link PermissionVault}.
|
||||
*
|
||||
* It also allows us to pre-determine child permission relationships.
|
||||
*
|
||||
* Injected by {@link InjectorPermissionMap}.
|
||||
*/
|
||||
public class LPPermissionMap extends ForwardingMap<String, Permission> {
|
||||
|
||||
// Uses perm.getName().toLowerCase(java.util.Locale.ENGLISH); to determine the key
|
||||
private final Map<String, Permission> delegate = new ConcurrentHashMap<>();
|
||||
|
||||
// cache from permission --> children
|
||||
private final LoadingCache<String, Map<String, Boolean>> trueChildPermissions = Caffeine.newBuilder()
|
||||
.build(new ChildPermissionResolver(true));
|
||||
|
||||
private final LoadingCache<String, Map<String, Boolean>> falseChildPermissions = Caffeine.newBuilder()
|
||||
.build(new ChildPermissionResolver(false));
|
||||
|
||||
/**
|
||||
* The plugin instance
|
||||
*/
|
||||
final LuckPermsPlugin plugin;
|
||||
|
||||
public LPPermissionMap(LuckPermsPlugin plugin, Map<String, Permission> existingData) {
|
||||
this.plugin = plugin;
|
||||
putAll(existingData);
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getChildPermissions(String permission, boolean value) {
|
||||
return value ? this.trueChildPermissions.get(permission) : this.falseChildPermissions.get(permission);
|
||||
}
|
||||
|
||||
private void update() {
|
||||
this.trueChildPermissions.invalidateAll();
|
||||
this.falseChildPermissions.invalidateAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Permission> delegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission put(@Nonnull String key, @Nonnull Permission value) {
|
||||
this.plugin.getPermissionVault().offer(key);
|
||||
Permission ret = super.put(key, value);
|
||||
update();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@Nonnull Map<? extends String, ? extends Permission> m) {
|
||||
this.plugin.getPermissionVault().offerAll(m.keySet());
|
||||
super.putAll(m);
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission putIfAbsent(String key, Permission value) {
|
||||
this.plugin.getPermissionVault().offer(key);
|
||||
Permission ret = super.putIfAbsent(key, value);
|
||||
update();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private final class ChildPermissionResolver implements CacheLoader<String, Map<String, Boolean>> {
|
||||
private final boolean value;
|
||||
|
||||
private ChildPermissionResolver(boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@CheckForNull
|
||||
@Override
|
||||
public Map<String, Boolean> load(@Nonnull String key) {
|
||||
Map<String, Boolean> children = new HashMap<>();
|
||||
resolveChildren(children, Collections.singletonMap(key, this.value), false);
|
||||
children.remove(key, this.value);
|
||||
return ImmutableMap.copyOf(children);
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveChildren(Map<String, Boolean> accumulator, Map<String, Boolean> children, boolean invert) {
|
||||
// iterate through the current known children.
|
||||
// the first time this method is called for a given permission, the children map will contain only the permission itself.
|
||||
for (Map.Entry<String, Boolean> e : children.entrySet()) {
|
||||
if (accumulator.containsKey(e.getKey())) {
|
||||
continue; // Prevent infinite loops
|
||||
}
|
||||
|
||||
// xor the value using the parent (bukkit logic, not mine)
|
||||
boolean value = e.getValue() ^ invert;
|
||||
accumulator.put(e.getKey().toLowerCase(), value);
|
||||
|
||||
// lookup any deeper children & resolve if present
|
||||
Permission perm = this.delegate.get(e.getKey());
|
||||
if (perm != null) {
|
||||
resolveChildren(accumulator, perm.getChildren(), !value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model;
|
||||
package me.lucko.luckperms.bukkit.model.server;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
@ -66,7 +66,7 @@ import javax.annotation.Nonnull;
|
||||
*
|
||||
* This class implements option 2 above. It is preferred because it is faster & uses less memory
|
||||
*
|
||||
* Injected by {@link SubscriptionMapInjector}.
|
||||
* Injected by {@link InjectorSubscriptionMap}.
|
||||
*/
|
||||
public class LPSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>> {
|
||||
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.processors;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
|
||||
/**
|
||||
* Performs the initial setup for Bukkit permission processors
|
||||
*/
|
||||
public class BukkitProcessorsSetupTask implements Runnable {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public BukkitProcessorsSetupTask(LPBukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.plugin.getDefaultsProvider().refresh();
|
||||
this.plugin.getChildPermissionProvider().setup();
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.processors;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds child permissions registered on the platform.
|
||||
*
|
||||
* The data stored in this class is pulled from the data in {@link PluginManager#getPermissions()}.
|
||||
*
|
||||
* The former method is not thread safe, so we populate this class when the server starts to get all of the data
|
||||
* in a form which is easily queryable & thread safe.
|
||||
*
|
||||
* The data is resolved early, so the represented child permissions are a "deep" lookup of permissions.
|
||||
*/
|
||||
public class ChildPermissionProvider {
|
||||
|
||||
// in the format: permission+value ===> children (a map of child permissions)
|
||||
private ImmutableMap<Map.Entry<String, Boolean>, ImmutableMap<String, Boolean>> permissions = ImmutableMap.of();
|
||||
|
||||
public void setup() {
|
||||
ImmutableMap.Builder<Map.Entry<String, Boolean>, ImmutableMap<String, Boolean>> permissions = ImmutableMap.builder();
|
||||
|
||||
// iterate all permissions registered on the platform & resolve.
|
||||
for (Permission permission : Bukkit.getServer().getPluginManager().getPermissions()) {
|
||||
resolve(permissions, permission, true);
|
||||
resolve(permissions, permission, false);
|
||||
}
|
||||
|
||||
this.permissions = permissions.build();
|
||||
}
|
||||
|
||||
private static void resolve(ImmutableMap.Builder<Map.Entry<String, Boolean>, ImmutableMap<String, Boolean>> accumulator, Permission permission, boolean value) {
|
||||
|
||||
// accumulator for the child permissions being looked up
|
||||
Map<String, Boolean> children = new HashMap<>();
|
||||
|
||||
// resolve children for the permission, so pass a map containing just the permission being looked up.
|
||||
resolveChildren(children, Collections.singletonMap(permission.getName(), value), false);
|
||||
|
||||
// remove self
|
||||
children.remove(permission.getName(), value);
|
||||
|
||||
// only register the children if there are any.
|
||||
if (!children.isEmpty()) {
|
||||
accumulator.put(Maps.immutableEntry(permission.getName().toLowerCase(), value), ImmutableMap.copyOf(children));
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveChildren(Map<String, Boolean> accumulator, Map<String, Boolean> children, boolean invert) {
|
||||
// iterate through the current known children.
|
||||
// the first time this method is called for a given permission, the children map will contain only the permission itself.
|
||||
for (Map.Entry<String, Boolean> e : children.entrySet()) {
|
||||
if (accumulator.containsKey(e.getKey())) {
|
||||
continue; // Prevent infinite loops
|
||||
}
|
||||
|
||||
// xor the value using the parent (bukkit logic, not mine)
|
||||
boolean value = e.getValue() ^ invert;
|
||||
accumulator.put(e.getKey().toLowerCase(), value);
|
||||
|
||||
// lookup any deeper children & resolve if present
|
||||
Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey());
|
||||
if (perm != null) {
|
||||
resolveChildren(accumulator, perm.getChildren(), !value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ImmutableMap<Map.Entry<String, Boolean>, ImmutableMap<String, Boolean>> getPermissions() {
|
||||
return this.permissions;
|
||||
}
|
||||
|
||||
}
|
@ -25,9 +25,8 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.processors;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.processors.AbstractPermissionProcessor;
|
||||
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||
|
||||
@ -39,11 +38,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* Permission Processor for Bukkits "child" permission system.
|
||||
*/
|
||||
public class ChildProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
|
||||
private final ChildPermissionProvider provider;
|
||||
private final LPBukkitPlugin plugin;
|
||||
private Map<String, Boolean> childPermissions = Collections.emptyMap();
|
||||
|
||||
public ChildProcessor(ChildPermissionProvider provider) {
|
||||
this.provider = provider;
|
||||
public ChildProcessor(LPBukkitPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -55,7 +54,7 @@ public class ChildProcessor extends AbstractPermissionProcessor implements Permi
|
||||
public void refresh() {
|
||||
Map<String, Boolean> builder = new ConcurrentHashMap<>();
|
||||
for (Map.Entry<String, Boolean> e : this.sourceMap.entrySet()) {
|
||||
Map<String, Boolean> children = this.provider.getPermissions().get(Maps.immutableEntry(e.getKey(), e.getValue()));
|
||||
Map<String, Boolean> children = this.plugin.getPermissionMap().getChildPermissions(e.getKey(), e.getValue());
|
||||
if (children != null) {
|
||||
builder.putAll(children);
|
||||
}
|
||||
|
@ -26,31 +26,31 @@
|
||||
package me.lucko.luckperms.bukkit.processors;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permission;
|
||||
|
||||
/**
|
||||
* Permission Processor for Bukkits "default" permission system.
|
||||
*/
|
||||
public class DefaultsProcessor implements PermissionProcessor {
|
||||
private final LPBukkitPlugin plugin;
|
||||
private final boolean isOp;
|
||||
private final DefaultsProvider defaultsProvider;
|
||||
|
||||
public DefaultsProcessor(boolean isOp, DefaultsProvider defaultsProvider) {
|
||||
public DefaultsProcessor(LPBukkitPlugin plugin, boolean isOp) {
|
||||
this.plugin = plugin;
|
||||
this.isOp = isOp;
|
||||
this.defaultsProvider = defaultsProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate hasPermission(String permission) {
|
||||
Tristate t = this.defaultsProvider.lookup(permission, this.isOp);
|
||||
Tristate t = this.plugin.getDefaultPermissionMap().lookupDefaultPermission(permission, this.isOp);
|
||||
if (t != Tristate.UNDEFINED) {
|
||||
return t;
|
||||
}
|
||||
|
||||
Permission defPerm = Bukkit.getServer().getPluginManager().getPermission(permission);
|
||||
Permission defPerm = this.plugin.getPermissionMap().get(permission);
|
||||
return defPerm == null ? Tristate.UNDEFINED : Tristate.fromBoolean(defPerm.getDefault().getValue(this.isOp));
|
||||
}
|
||||
}
|
||||
|
@ -1,169 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.processors;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.bukkit.model.dummy.DummyPermissible;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Holds default permissions registered on the platform.
|
||||
*
|
||||
* The data stored in this class is pulled from the data in {@link PluginManager#getDefaultPermissions(boolean)}.
|
||||
*
|
||||
* The former method is not thread safe, so we populate this class when the server starts to get all of the data
|
||||
* in a form which is easily queryable & thread safe.
|
||||
*
|
||||
* The {@link DummyPermissible}s are registered with Bukkit, so we can listen for any
|
||||
* changes to default permissions.
|
||||
*/
|
||||
public class DefaultsProvider {
|
||||
|
||||
// defaults for opped players
|
||||
private Map<String, Boolean> opDefaults = ImmutableMap.of();
|
||||
private final DummyPermissible opDummy = new DummyPermissible(this::refreshOp);
|
||||
|
||||
// defaults for non-opped players
|
||||
private Map<String, Boolean> nonOpDefaults = ImmutableMap.of();
|
||||
private final DummyPermissible nonOpDummy = new DummyPermissible(this::refreshNonOp);
|
||||
|
||||
/**
|
||||
* Refreshes the data in this provider.
|
||||
*/
|
||||
public void refresh() {
|
||||
refreshOp();
|
||||
refreshNonOp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries whether a given permission should be granted by default.
|
||||
*
|
||||
* @param permission the permission to query
|
||||
* @param isOp if the player is op
|
||||
* @return a tristate result
|
||||
*/
|
||||
public Tristate lookup(String permission, boolean isOp) {
|
||||
Map<String, Boolean> map = isOp ? this.opDefaults : this.nonOpDefaults;
|
||||
return Tristate.fromNullableBoolean(map.get(permission));
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the op data in this provider.
|
||||
*/
|
||||
private void refreshOp() {
|
||||
unregisterDefaults(this.opDefaults, this.opDummy, true);
|
||||
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
calculateDefaults(builder, this.opDummy, true);
|
||||
|
||||
this.opDefaults = ImmutableMap.copyOf(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the non op data in this provider.
|
||||
*/
|
||||
private void refreshNonOp() {
|
||||
unregisterDefaults(this.nonOpDefaults, this.nonOpDummy, false);
|
||||
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
calculateDefaults(builder, this.nonOpDummy, false);
|
||||
|
||||
this.nonOpDefaults = ImmutableMap.copyOf(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the dummy permissibles with Bukkit.
|
||||
*/
|
||||
public void close() {
|
||||
unregisterDefaults(this.opDefaults, this.opDummy, true);
|
||||
unregisterDefaults(this.nonOpDefaults, this.nonOpDummy, false);
|
||||
}
|
||||
|
||||
private static PluginManager pm() {
|
||||
return Bukkit.getServer().getPluginManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters defaults for a given permissible.
|
||||
*
|
||||
* @param map the map of current defaults
|
||||
* @param p the permissible
|
||||
*/
|
||||
private static void unregisterDefaults(Map<String, Boolean> map, DummyPermissible p, boolean op) {
|
||||
Set<String> perms = map.keySet();
|
||||
|
||||
for (String name : perms) {
|
||||
pm().unsubscribeFromPermission(name, p);
|
||||
}
|
||||
|
||||
pm().unsubscribeFromDefaultPerms(op, p);
|
||||
}
|
||||
|
||||
private static void calculateDefaults(Map<String, Boolean> map, DummyPermissible p, boolean op) {
|
||||
pm().subscribeToDefaultPerms(op, p);
|
||||
|
||||
Set<Permission> defaults = pm().getDefaultPermissions(op);
|
||||
for (Permission perm : defaults) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
|
||||
map.put(name, true);
|
||||
pm().subscribeToPermission(name, p);
|
||||
|
||||
// register defaults for any children too
|
||||
calculateChildPermissions(map, p, perm.getChildren(), false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculateChildPermissions(Map<String, Boolean> accumulator, DummyPermissible p, Map<String, Boolean> children, boolean invert) {
|
||||
for (Map.Entry<String, Boolean> e : children.entrySet()) {
|
||||
if (accumulator.containsKey(e.getKey())) {
|
||||
continue; // Prevent infinite loops
|
||||
}
|
||||
|
||||
// xor the value using the parent (bukkit logic, not mine)
|
||||
boolean value = e.getValue() ^ invert;
|
||||
|
||||
accumulator.put(e.getKey().toLowerCase(), value);
|
||||
pm().subscribeToPermission(e.getKey(), p);
|
||||
|
||||
// lookup any deeper children & resolve if present
|
||||
Permission perm = pm().getPermission(e.getKey());
|
||||
if (perm != null) {
|
||||
calculateChildPermissions(accumulator, p, perm.getChildren(), !value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -8,16 +8,15 @@ main: me.lucko.luckperms.bukkit.LPBukkitPlugin
|
||||
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.
|
||||
# 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]
|
||||
|
||||
# Soft depend on LilyPad for messaging service impl
|
||||
softdepend: [LilyPad-Connect]
|
||||
|
||||
commands:
|
||||
luckperms:
|
||||
description: Manage permissions
|
||||
aliases: [lp, perm, perms, permission, permissions]
|
||||
|
||||
|
||||
# Permissions are registered programmatically instead of here.
|
||||
# See the last method in me.lucko.luckperms.bukkit.LPBukkitPlugin
|
||||
|
Loading…
Reference in New Issue
Block a user