diff --git a/bukkit/pom.xml b/bukkit/pom.xml index e210de9a..cca49154 100644 --- a/bukkit/pom.xml +++ b/bukkit/pom.xml @@ -129,6 +129,14 @@ provided + + + com.github.ben-manes.caffeine + caffeine + 2.6.1 + provided + + org.spigotmc diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java index 06220678..168ea852 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -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 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 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; diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java index 4f1704d7..2728c650 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java @@ -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())); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPPermissionMap.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPPermissionMap.java deleted file mode 100644 index 71df573d..00000000 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPPermissionMap.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of LuckPerms, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * 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 { - final LuckPermsPlugin plugin; - - public LPPermissionMap(LuckPermsPlugin plugin, Map 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 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); - } - -} diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/dummy/DummyPermissible.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/dummy/DummyPermissible.java deleted file mode 100644 index 8135b607..00000000 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/dummy/DummyPermissible.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file is part of LuckPerms, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * 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 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) {} - -} diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/InjectorDefaultsMap.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/InjectorDefaultsMap.java new file mode 100644 index 00000000..ad29c7c6 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/InjectorDefaultsMap.java @@ -0,0 +1,119 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * 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> castedMap = (Map>) 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(); + } + } +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/PermissionMapInjector.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/InjectorPermissionMap.java similarity index 89% rename from bukkit/src/main/java/me/lucko/luckperms/bukkit/model/PermissionMapInjector.java rename to bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/InjectorPermissionMap.java index 505611f0..7b1959de 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/PermissionMapInjector.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/InjectorPermissionMap.java @@ -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 castedMap = (Map) 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() { diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionMapInjector.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/InjectorSubscriptionMap.java similarity index 88% rename from bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionMapInjector.java rename to bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/InjectorSubscriptionMap.java index dde49971..5493ffc2 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionMapInjector.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/InjectorSubscriptionMap.java @@ -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> castedMap = (Map>) 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() { diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPDefaultsMap.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPDefaultsMap.java new file mode 100644 index 00000000..c434bb12 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPDefaultsMap.java @@ -0,0 +1,197 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * 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> { + // keyset for all instances + private static final Set KEY_SET = ImmutableSet.of(Boolean.TRUE, Boolean.FALSE); + + // the plugin + final LPBukkitPlugin plugin; + + // the two values in the map + private final Set opSet = new DefaultPermissionSet(true); + private final Set nonOpSet = new DefaultPermissionSet(false); + + // fully resolved defaults (accounts for child permissions too) + private Map resolvedOpDefaults = ImmutableMap.of(); + private Map resolvedNonOpDefaults = ImmutableMap.of(); + + // #values and #entrySet results - both immutable + private final Collection> values = ImmutableList.of(this.opSet, this.nonOpSet); + private final Set>> entrySet = ImmutableSet.of( + Maps.immutableEntry(Boolean.TRUE, this.opSet), + Maps.immutableEntry(Boolean.FALSE, this.nonOpSet) + ); + + public LPDefaultsMap(LPBukkitPlugin plugin, Map> 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 getOpPermissions() { + return this.opSet; + } + + public Set 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 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 builder = new HashMap<>(); + for (Permission perm : getOpPermissions()) { + String name = perm.getName().toLowerCase(); + builder.put(name, true); + for (Map.Entry 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 builder = new HashMap<>(); + for (Permission perm : getNonOpPermissions()) { + String name = perm.getName().toLowerCase(); + builder.put(name, true); + for (Map.Entry child : this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) { + builder.putIfAbsent(child.getKey(), child.getValue()); + } + } + this.resolvedNonOpDefaults = ImmutableMap.copyOf(builder); + } + + @Override + public Set get(Object key) { + boolean b = (boolean) key; + return b ? this.opSet : this.nonOpSet; + } + + // return wrappers around this map impl + @Nonnull @Override public Collection> values() { return this.values; } + @Nonnull @Override public Set>> entrySet() { return this.entrySet; } + @Nonnull @Override public Set 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 put(Boolean key, Set value) { throw new UnsupportedOperationException(); } + @Override public Set remove(Object key) { throw new UnsupportedOperationException(); } + @Override public void putAll(@Nonnull Map> m) { throw new UnsupportedOperationException(); } + @Override public void clear() { throw new UnsupportedOperationException(); } + + private final class DefaultPermissionSet extends ForwardingSet { + private final Set delegate = ConcurrentHashMap.newKeySet(); + private final boolean op; + + private DefaultPermissionSet(boolean op) { + this.op = op; + } + + @Override + protected Set 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 collection) { + boolean ret = super.addAll(collection); + refresh(this.op); + return ret; + } + } + +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPPermissionMap.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPPermissionMap.java new file mode 100644 index 00000000..3998c94f --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPPermissionMap.java @@ -0,0 +1,155 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * 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 { + + // Uses perm.getName().toLowerCase(java.util.Locale.ENGLISH); to determine the key + private final Map delegate = new ConcurrentHashMap<>(); + + // cache from permission --> children + private final LoadingCache> trueChildPermissions = Caffeine.newBuilder() + .build(new ChildPermissionResolver(true)); + + private final LoadingCache> falseChildPermissions = Caffeine.newBuilder() + .build(new ChildPermissionResolver(false)); + + /** + * The plugin instance + */ + final LuckPermsPlugin plugin; + + public LPPermissionMap(LuckPermsPlugin plugin, Map existingData) { + this.plugin = plugin; + putAll(existingData); + } + + public Map 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 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 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> { + private final boolean value; + + private ChildPermissionResolver(boolean value) { + this.value = value; + } + + @CheckForNull + @Override + public Map load(@Nonnull String key) { + Map children = new HashMap<>(); + resolveChildren(children, Collections.singletonMap(key, this.value), false); + children.remove(key, this.value); + return ImmutableMap.copyOf(children); + } + } + + private void resolveChildren(Map accumulator, Map 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 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); + } + } + } + +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPSubscriptionMap.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPSubscriptionMap.java similarity index 99% rename from bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPSubscriptionMap.java rename to bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPSubscriptionMap.java index 1a86993e..64366f16 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPSubscriptionMap.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/server/LPSubscriptionMap.java @@ -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> { diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/BukkitProcessorsSetupTask.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/BukkitProcessorsSetupTask.java deleted file mode 100644 index 3292be1e..00000000 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/BukkitProcessorsSetupTask.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of LuckPerms, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * 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(); - } -} diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/ChildPermissionProvider.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/ChildPermissionProvider.java deleted file mode 100644 index 53916154..00000000 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/ChildPermissionProvider.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is part of LuckPerms, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * 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, ImmutableMap> permissions = ImmutableMap.of(); - - public void setup() { - ImmutableMap.Builder, ImmutableMap> 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, ImmutableMap> accumulator, Permission permission, boolean value) { - - // accumulator for the child permissions being looked up - Map 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 accumulator, Map 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 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, ImmutableMap> getPermissions() { - return this.permissions; - } - -} diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/ChildProcessor.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/ChildProcessor.java index 7a29d356..147e3312 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/ChildProcessor.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/ChildProcessor.java @@ -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 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 builder = new ConcurrentHashMap<>(); for (Map.Entry e : this.sourceMap.entrySet()) { - Map children = this.provider.getPermissions().get(Maps.immutableEntry(e.getKey(), e.getValue())); + Map children = this.plugin.getPermissionMap().getChildPermissions(e.getKey(), e.getValue()); if (children != null) { builder.putAll(children); } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/DefaultsProcessor.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/DefaultsProcessor.java index 818d13c5..49fee5d1 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/DefaultsProcessor.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/DefaultsProcessor.java @@ -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)); } } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/DefaultsProvider.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/DefaultsProvider.java deleted file mode 100644 index 722bdc5a..00000000 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/DefaultsProvider.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * This file is part of LuckPerms, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * 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 opDefaults = ImmutableMap.of(); - private final DummyPermissible opDummy = new DummyPermissible(this::refreshOp); - - // defaults for non-opped players - private Map 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 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 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 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 map, DummyPermissible p, boolean op) { - Set perms = map.keySet(); - - for (String name : perms) { - pm().unsubscribeFromPermission(name, p); - } - - pm().unsubscribeFromDefaultPerms(op, p); - } - - private static void calculateDefaults(Map map, DummyPermissible p, boolean op) { - pm().subscribeToDefaultPerms(op, p); - - Set 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 accumulator, DummyPermissible p, Map children, boolean invert) { - for (Map.Entry 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); - } - } - } - -} diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml index 3d34d2f1..e83bb4ce 100644 --- a/bukkit/src/main/resources/plugin.yml +++ b/bukkit/src/main/resources/plugin.yml @@ -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