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 fee6febaa..3ce53a18e 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -39,6 +39,7 @@ import me.lucko.luckperms.bukkit.listeners.BukkitPlatformListener; import me.lucko.luckperms.bukkit.messaging.BukkitMessagingFactory; import me.lucko.luckperms.bukkit.model.Injector; import me.lucko.luckperms.bukkit.model.LPPermissible; +import me.lucko.luckperms.bukkit.model.SubscriptionMapInjector; import me.lucko.luckperms.bukkit.processors.BukkitProcessorsSetupTask; import me.lucko.luckperms.bukkit.processors.ChildPermissionProvider; import me.lucko.luckperms.bukkit.processors.DefaultsProvider; @@ -244,6 +245,13 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { contextManager.registerCalculator(new WorldCalculator(this)); contextManager.registerCalculator(new LuckPermsCalculator<>(getConfiguration()), true); + // inject our own subscription map + new SubscriptionMapInjector(this).run(); + + // schedule another injection after all plugins have loaded - the entire pluginmanager instance + // is replaced by some plugins :( + scheduler.asyncLater(new SubscriptionMapInjector(this), 2L); + // Provide vault support tryVaultHook(false); @@ -324,9 +332,10 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { permissionVault.shutdown(); verboseHandler.shutdown(); + // uninject from players for (Player player : getServer().getOnlinePlayers()) { try { - Injector.unInject(player, false, false); + Injector.unInject(player, false); } catch (Exception e) { e.printStackTrace(); } @@ -342,6 +351,9 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { } } + // uninject subscription map + SubscriptionMapInjector.uninject(); + getLog().info("Closing storage..."); storage.shutdown(); @@ -388,14 +400,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { } } - @Override - public void onUserRefresh(User user) { - LPPermissible lpp = Injector.getPermissible(uuidCache.getExternalUUID(user.getUuid())); - if (lpp != null) { - lpp.updateSubscriptions(); - } - } - public void refreshAutoOp(User user, Player player) { if (user == null) { return; diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitConnectionListener.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitConnectionListener.java index ce5fde58e..bf49251b1 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitConnectionListener.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitConnectionListener.java @@ -209,7 +209,7 @@ public class BukkitConnectionListener implements Listener { // Remove the custom permissible try { - Injector.unInject(player, true, true); + Injector.unInject(player, true); } catch (Exception ex) { ex.printStackTrace(); } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/Injector.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/Injector.java index ff4da4994..ff5b5ffe1 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/Injector.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/Injector.java @@ -35,9 +35,6 @@ import org.bukkit.permissions.PermissionAttachment; import java.lang.reflect.Field; import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; /** * Injects a {@link LPPermissible} into a {@link Player}. @@ -47,7 +44,6 @@ import java.util.concurrent.ConcurrentHashMap; */ @UtilityClass public class Injector { - private static final Map INJECTED_PERMISSIBLES = new ConcurrentHashMap<>(); /** * All permission checks made on standard Bukkit objects are effectively proxied to a @@ -123,13 +119,9 @@ public class Injector { // Setup the new permissible newPermissible.getActive().set(true); newPermissible.setOldPermissible(oldPermissible); - newPermissible.updateSubscriptionsAsync(); // inject the new instance HUMAN_ENTITY_PERMISSIBLE_FIELD.set(player, newPermissible); - - // register the injection with the map - INJECTED_PERMISSIBLES.put(player.getUniqueId(), newPermissible); } /** @@ -137,10 +129,9 @@ public class Injector { * * @param player the player to uninject from * @param dummy if the replacement permissible should be a dummy. - * @param unsubscribe if the extracted permissible should unsubscribe itself. see {@link SubscriptionManager}. * @throws Exception propagates any exceptions which were thrown during uninjection */ - public static void unInject(Player player, boolean dummy, boolean unsubscribe) throws Exception { + public static void unInject(Player player, boolean dummy) throws Exception { // gets the players current permissible. PermissibleBase permissible = (PermissibleBase) HUMAN_ENTITY_PERMISSIBLE_FIELD.get(player); @@ -152,11 +143,6 @@ public class Injector { // clear all permissions lpPermissible.clearPermissions(); - // try to unsubscribe - if (unsubscribe) { - lpPermissible.unsubscribeFromAllAsync(); - } - // set to inactive lpPermissible.getActive().set(false); @@ -174,12 +160,6 @@ public class Injector { HUMAN_ENTITY_PERMISSIBLE_FIELD.set(player, newPb); } } - - INJECTED_PERMISSIBLES.remove(player.getUniqueId()); - } - - public static LPPermissible getPermissible(UUID uuid) { - return INJECTED_PERMISSIBLES.get(uuid); } } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPPermissible.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPPermissible.java index 8a4fb44fe..112c6bd81 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPPermissible.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPPermissible.java @@ -32,7 +32,6 @@ import lombok.Setter; import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.api.Tristate; import me.lucko.luckperms.bukkit.LPBukkitPlugin; -import me.lucko.luckperms.common.caching.UserCache; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.verbose.CheckOrigin; @@ -45,7 +44,6 @@ import org.bukkit.permissions.PermissionAttachmentInfo; import org.bukkit.plugin.Plugin; import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -78,9 +76,6 @@ public class LPPermissible extends PermissibleBase { // the luckperms plugin instance private final LPBukkitPlugin plugin; - // the subscription manager, handling the players permission subscriptions. - private final SubscriptionManager subscriptions; - // the players previous permissible. (the one they had before this one was injected) @Setter private PermissibleBase oldPermissible = null; @@ -97,7 +92,6 @@ public class LPPermissible extends PermissibleBase { this.user = user; this.player = player; this.plugin = plugin; - this.subscriptions = new SubscriptionManager(this); } @Override @@ -140,56 +134,6 @@ public class LPPermissible extends PermissibleBase { } } - /** - * Updates the players subscriptions asynchronously - */ - public void updateSubscriptionsAsync() { - if (!active.get()) { - return; - } - - plugin.getScheduler().doAsync(this::updateSubscriptions); - } - - /** - * Updates the players subscriptions - */ - public void updateSubscriptions() { - if (!active.get()) { - return; - } - - UserCache cache = user.getUserData(); - - // calculate their "active" permissions - Set ent = new HashSet<>(cache.getPermissionData(calculateContexts()).getImmutableBacking().keySet()); - - // include defaults, if enabled. - if (plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS)) { - if (player.isOp()) { - ent.addAll(plugin.getDefaultsProvider().getOpDefaults().keySet()); - } else { - ent.addAll(plugin.getDefaultsProvider().getNonOpDefaults().keySet()); - } - } - - subscriptions.subscribe(ent); - } - - /** - * Unsubscribes from all permissions asynchronously - */ - public void unsubscribeFromAllAsync() { - plugin.getScheduler().doAsync(this::unsubscribeFromAll); - } - - /** - * Unsubscribes from all permissions - */ - public void unsubscribeFromAll() { - subscriptions.subscribe(Collections.emptySet()); - } - /** * Adds attachments to this permissible. * diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPSubscriptionMap.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPSubscriptionMap.java new file mode 100644 index 000000000..c8a917b58 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPSubscriptionMap.java @@ -0,0 +1,270 @@ +/* + * 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 com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import me.lucko.luckperms.bukkit.LPBukkitPlugin; +import me.lucko.luckperms.common.utils.ImmutableCollectors; + +import org.bukkit.entity.Player; +import org.bukkit.permissions.Permissible; +import org.bukkit.permissions.Permission; +import org.bukkit.plugin.PluginManager; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.stream.Collectors; + +/** + * A replacement map for the 'permSubs' instance in Bukkit's SimplePluginManager. + * + * This instance allows LuckPerms to intercept calls to + * {@link PluginManager#subscribeToPermission(String, Permissible)}, + * {@link PluginManager#unsubscribeFromPermission(String, Permissible)} and + * {@link PluginManager#getPermissionSubscriptions(String)}. + * + * Bukkit for some reason sometimes uses subscription status to determine whether + * a permissible has a given node, instead of checking directly with + * {@link Permissible#hasPermission(Permission)}. + * + * {@link org.bukkit.Server#broadcast(String, String)} is a good example of this. + * + * In order to implement predicable Bukkit behaviour, LP has two options: + * 1) register subscriptions for all players as normal, or + * 2) inject it's own map instance to proxy calls to {@link PluginManager#getPermissionSubscriptions(String)} back to LuckPerms. + * + * This class implements option 2 above. It is preferred because it is faster & uses less memory + */ +public class LPSubscriptionMap extends HashMap> { + + // the plugin instance + private final LPBukkitPlugin plugin; + + public LPSubscriptionMap(LPBukkitPlugin plugin, Map> existingData) { + super(existingData); + this.plugin = plugin; + } + + /* The get method is the only one which is actually used by SimplePluginManager + * we override it to always return a value - which means the null check in + * subscribeToDefaultPerms always fails - soo, we don't have to worry too much + * about implementing #put. + * + * we also ensure all returns are LPSubscriptionValueMaps. this extension + * will also delegate checks to online players - meaning we don't ever + * have to register their subscriptions with the plugin manager. + */ + @Override + public Map get(Object key) { + if (key == null || !(key instanceof String)) { + return null; + } + + String permission = ((String) key); + + Map result = super.get(key); + + if (result == null) { + // calculate a new map - always! + result = new LPSubscriptionValueMap(permission); + super.put(permission, result); + } else if (!(result instanceof LPSubscriptionValueMap)) { + // ensure return type is a LPSubscriptionMap + result = new LPSubscriptionValueMap(permission, result); + super.put(permission, result); + } + return result; + } + + @Override + public Map put(String key, Map value) { + if (value == null) { + throw new NullPointerException("Map value cannot be null"); + } + + // ensure values are LP subscription maps + if (!(value instanceof LPSubscriptionValueMap)) { + value = new LPSubscriptionValueMap(key, value); + } + return super.put(key, value); + } + + // if the key isn't null and is a string, #get will always return a value for it + @Override + public boolean containsKey(Object key) { + return key != null && key instanceof String; + } + + /** + * Converts this map back to a standard HashMap + * + * @return a standard representation of this map + */ + public Map> detach() { + Map> ret = new HashMap<>(); + + for (Map.Entry> ent : entrySet()) { + if (ent.getValue() instanceof LPSubscriptionValueMap) { + ret.put(ent.getKey(), ((LPSubscriptionValueMap) ent.getValue()).backing); + } else { + ret.put(ent.getKey(), ent.getValue()); + } + } + + return ret; + } + + /** + * Value map extension which includes LP objects in Permissible related queries. + */ + public class LPSubscriptionValueMap implements Map { + + // the permission being mapped to this value map + private final String permission; + + // the backing map + private final Map backing; + + public LPSubscriptionValueMap(String permission, Map backing) { + this.permission = permission; + this.backing = backing; + } + + public LPSubscriptionValueMap(String permission) { + this(permission, new WeakHashMap<>()); + } + + @Override + public Boolean get(Object key) { + boolean isPlayer = key instanceof Player; + + // if the key is a player, check their LPPermissible first + if (isPlayer) { + Permissible p = (Permissible) key; + if (p.isPermissionSet(permission)) { + return p.hasPermission(permission); + } + } + + // then try the map + Boolean result = backing.get(key); + if (result != null) { + return result; + } + + // then try the map, if we haven't already + if (!isPlayer && key instanceof Permissible) { + Permissible p = (Permissible) key; + if (p.isPermissionSet(permission)) { + return p.hasPermission(permission); + } + } + + // no result + return null; + } + + @Override + public boolean containsKey(Object key) { + // check the backing map, as well as if the permissible has the perm set + return backing.containsKey(key) || (key instanceof Permissible && ((Permissible) key).isPermissionSet(permission)); + } + + @Override + public Set keySet() { + // gather players (LPPermissibles) + Set players = plugin.getServer().getOnlinePlayers().stream() + .filter(player -> player.isPermissionSet(permission)) + .collect(Collectors.toSet()); + + // then combine the players with the backing map + return Sets.union(players, backing.keySet()); + } + + @Override + public Set> entrySet() { + return keySet().stream() + .map(p -> { + Boolean ret = get(p); + return ret != null ? Maps.immutableEntry(p, ret) : null; + }) + .filter(Objects::nonNull) + .collect(ImmutableCollectors.toImmutableSet()); + } + + @Override + public boolean isEmpty() { + // we never want to remove this map from the parent - since it just gets recreated + // on subsequent calls + return false; + } + + // just delegate to the backing map + + @Override + public Boolean put(Permissible key, Boolean value) { + return backing.put(key, value); + } + + @Override + public Boolean remove(Object key) { + return backing.remove(key); + } + + // the following methods are not used in the current impls of PluginManager, but just delegate them for now + + @Override + public int size() { + return backing.size(); + } + + @Override + public boolean containsValue(Object value) { + return backing.containsValue(value); + } + + @Override + public void putAll(Map m) { + backing.putAll(m); + } + + @Override + public void clear() { + backing.clear(); + } + + @Override + public Collection values() { + return backing.values(); + } + } +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionManager.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionManager.java deleted file mode 100644 index b28ac75fc..000000000 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionManager.java +++ /dev/null @@ -1,103 +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 lombok.AllArgsConstructor; -import lombok.RequiredArgsConstructor; - -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; - -import org.bukkit.permissions.Permission; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * Handles permission subscriptions with Bukkits plugin manager, for a given LPPermissible. - * - * Bukkit for some reason sometimes uses subscription status to determine whether a permissible has a given node, instead - * of checking directly with {@link org.bukkit.permissions.Permissible#hasPermission(Permission)}. - * - * {@link org.bukkit.Bukkit#broadcast(String, String)} is a good example of this. - */ -@RequiredArgsConstructor -public class SubscriptionManager { - - private final LPPermissible permissible; - private Set currentSubscriptions = ImmutableSet.of(); - - public synchronized void subscribe(Set perms) { - Set newPerms = ImmutableSet.copyOf(perms); - - // we compare changes to avoid unnecessary time wasted on the main thread mutating this data. - // the changes can be calculated here async, and then only the needed changes can be applied. - Map.Entry, Set> changes = compareSets(newPerms, currentSubscriptions); - if (!changes.getKey().isEmpty() || !changes.getValue().isEmpty()) { - permissible.getPlugin().getScheduler().doSync(new SubscriptionUpdateTask(permissible, changes.getKey(), changes.getValue())); - } - - this.currentSubscriptions = newPerms; - } - - @AllArgsConstructor - public static final class SubscriptionUpdateTask implements Runnable { - private final LPPermissible permissible; - private final Set toAdd; - private final Set toRemove; - - @Override - public void run() { - for (String s : toAdd) { - permissible.getPlugin().getServer().getPluginManager().subscribeToPermission(s, permissible.getPlayer()); - } - for (String s : toRemove) { - permissible.getPlugin().getServer().getPluginManager().unsubscribeFromPermission(s, permissible.getPlayer()); - } - } - } - - /** - * Compares two sets - * @param local the local set - * @param remote the remote set - * @return the entries to add to remote, and the entries to remove from remote - */ - private static Map.Entry, Set> compareSets(Set local, Set remote) { - // entries in local but not remote need to be added - // entries in remote but not local need to be removed - - Set toAdd = new HashSet<>(local); - toAdd.removeAll(remote); - - Set toRemove = new HashSet<>(remote); - toRemove.removeAll(local); - - return Maps.immutableEntry(toAdd, toRemove); - } - -} diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionMapInjector.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionMapInjector.java new file mode 100644 index 000000000..4c7f4e5e4 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionMapInjector.java @@ -0,0 +1,108 @@ +/* + * 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 lombok.RequiredArgsConstructor; + +import me.lucko.luckperms.bukkit.LPBukkitPlugin; + +import org.bukkit.Bukkit; +import org.bukkit.permissions.Permissible; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.SimplePluginManager; + +import java.lang.reflect.Field; +import java.util.Map; + +@RequiredArgsConstructor +public class SubscriptionMapInjector implements Runnable { + private static final Field PERM_SUBS_FIELD; + + static { + Field permSubsField; + try { + permSubsField = SimplePluginManager.class.getDeclaredField("permSubs"); + permSubsField.setAccessible(true); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + PERM_SUBS_FIELD = permSubsField; + } + + private final LPBukkitPlugin plugin; + + @Override + public void run() { + try { + inject(); + } catch (Exception e) { + plugin.getLog().severe("Exception occurred whilst injecting LuckPerms Permission Subscription map."); + e.printStackTrace(); + } + } + + private void inject() throws Exception { + PluginManager pluginManager = plugin.getServer().getPluginManager(); + + if (!(pluginManager instanceof SimplePluginManager)) { + plugin.getLog().severe("PluginManager instance is not a 'SimplePluginManager', instead: " + pluginManager.getClass()); + plugin.getLog().severe("Unable to inject LuckPerms Permission Subscription map."); + return; + } + + Object map = PERM_SUBS_FIELD.get(pluginManager); + if (map instanceof LPSubscriptionMap) { + return; // already injected + } + + //noinspection unchecked + Map> castedMap = (Map>) map; + + // make a new subscription map + LPSubscriptionMap newMap = new LPSubscriptionMap(plugin, castedMap); + + // inject it + PERM_SUBS_FIELD.set(pluginManager, newMap); + } + + public static void uninject() { + try { + PluginManager pluginManager = Bukkit.getServer().getPluginManager(); + if (!(pluginManager instanceof SimplePluginManager)) { + return; + } + + Object map = PERM_SUBS_FIELD.get(pluginManager); + if (map instanceof LPSubscriptionMap) { + LPSubscriptionMap lpMap = (LPSubscriptionMap) map; + PERM_SUBS_FIELD.set(pluginManager, lpMap.detach()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} 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 690efca28..dd277054d 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 @@ -45,7 +45,7 @@ public class DefaultsProcessor implements PermissionProcessor { @Override public Tristate hasPermission(String permission) { - Tristate t = defaultsProvider.hasDefault(permission, isOp); + Tristate t = defaultsProvider.lookup(permission, isOp); if (t != Tristate.UNDEFINED) { return t; } 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 index 79e14226a..a4d7c592e 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/DefaultsProvider.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/processors/DefaultsProvider.java @@ -78,7 +78,7 @@ public class DefaultsProvider { * @param isOp if the player is op * @return a tristate result */ - public Tristate hasDefault(String permission, boolean isOp) { + public Tristate lookup(String permission, boolean isOp) { Map map = isOp ? opDefaults : nonOpDefaults; Boolean b = map.get(permission); @@ -126,6 +126,10 @@ public class DefaultsProvider { unregisterDefaults(nonOpDefaults, nonOpDummy, false); } + private static PluginManager pm() { + return Bukkit.getServer().getPluginManager(); + } + /** * Unregisters defaults for a given permissible. * @@ -136,21 +140,21 @@ public class DefaultsProvider { Set perms = map.keySet(); for (String name : perms) { - Bukkit.getServer().getPluginManager().unsubscribeFromPermission(name, p); + pm().unsubscribeFromPermission(name, p); } - Bukkit.getServer().getPluginManager().unsubscribeFromDefaultPerms(op, p); + pm().unsubscribeFromDefaultPerms(op, p); } private static void calculateDefaults(Map map, DummyPermissible p, boolean op) { - Bukkit.getServer().getPluginManager().subscribeToDefaultPerms(op, p); + pm().subscribeToDefaultPerms(op, p); - Set defaults = Bukkit.getServer().getPluginManager().getDefaultPermissions(op); + Set defaults = pm().getDefaultPermissions(op); for (Permission perm : defaults) { String name = perm.getName().toLowerCase(); map.put(name, true); - Bukkit.getServer().getPluginManager().subscribeToPermission(name, p); + pm().subscribeToPermission(name, p); // register defaults for any children too calculateChildPermissions(map, p, perm.getChildren(), false); @@ -167,10 +171,10 @@ public class DefaultsProvider { boolean value = e.getValue() ^ invert; accumulator.put(e.getKey().toLowerCase(), value); - Bukkit.getServer().getPluginManager().subscribeToPermission(e.getKey(), p); + pm().subscribeToPermission(e.getKey(), p); // lookup any deeper children & resolve if present - Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey()); + Permission perm = pm().getPermission(e.getKey()); if (perm != null) { calculateChildPermissions(accumulator, p, perm.getChildren(), !value); } diff --git a/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java index dfb203107..0504613ef 100644 --- a/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java +++ b/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java @@ -381,15 +381,6 @@ public interface LuckPermsPlugin { } - /** - * Called when a users data is refreshed - * - * @param user the user - */ - default void onUserRefresh(User user) { - - } - static void sendStartupBanner(Sender sender, LuckPermsPlugin plugin) { sender.sendMessage(Util.color("&b __ &3 __ ___ __ __ ")); sender.sendMessage(Util.color("&b | | | / ` |__/ &3|__) |__ |__) |\\/| /__` "));