Inject our own subscription map into the plugin manager instead of registering permissions individually for each player

This commit is contained in:
Luck 2017-10-29 15:16:48 +00:00
parent 72e6c75433
commit dee41b315f
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
10 changed files with 406 additions and 208 deletions

View File

@ -39,6 +39,7 @@ import me.lucko.luckperms.bukkit.listeners.BukkitPlatformListener;
import me.lucko.luckperms.bukkit.messaging.BukkitMessagingFactory; import me.lucko.luckperms.bukkit.messaging.BukkitMessagingFactory;
import me.lucko.luckperms.bukkit.model.Injector; import me.lucko.luckperms.bukkit.model.Injector;
import me.lucko.luckperms.bukkit.model.LPPermissible; 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.BukkitProcessorsSetupTask;
import me.lucko.luckperms.bukkit.processors.ChildPermissionProvider; import me.lucko.luckperms.bukkit.processors.ChildPermissionProvider;
import me.lucko.luckperms.bukkit.processors.DefaultsProvider; 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 WorldCalculator(this));
contextManager.registerCalculator(new LuckPermsCalculator<>(getConfiguration()), true); 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 // Provide vault support
tryVaultHook(false); tryVaultHook(false);
@ -324,9 +332,10 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
permissionVault.shutdown(); permissionVault.shutdown();
verboseHandler.shutdown(); verboseHandler.shutdown();
// uninject from players
for (Player player : getServer().getOnlinePlayers()) { for (Player player : getServer().getOnlinePlayers()) {
try { try {
Injector.unInject(player, false, false); Injector.unInject(player, false);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -342,6 +351,9 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
} }
} }
// uninject subscription map
SubscriptionMapInjector.uninject();
getLog().info("Closing storage..."); getLog().info("Closing storage...");
storage.shutdown(); 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) { public void refreshAutoOp(User user, Player player) {
if (user == null) { if (user == null) {
return; return;

View File

@ -209,7 +209,7 @@ public class BukkitConnectionListener implements Listener {
// Remove the custom permissible // Remove the custom permissible
try { try {
Injector.unInject(player, true, true); Injector.unInject(player, true);
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
} }

View File

@ -35,9 +35,6 @@ import org.bukkit.permissions.PermissionAttachment;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.List; 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}. * Injects a {@link LPPermissible} into a {@link Player}.
@ -47,7 +44,6 @@ import java.util.concurrent.ConcurrentHashMap;
*/ */
@UtilityClass @UtilityClass
public class Injector { public class Injector {
private static final Map<UUID, LPPermissible> INJECTED_PERMISSIBLES = new ConcurrentHashMap<>();
/** /**
* All permission checks made on standard Bukkit objects are effectively proxied to a * All permission checks made on standard Bukkit objects are effectively proxied to a
@ -123,13 +119,9 @@ public class Injector {
// Setup the new permissible // Setup the new permissible
newPermissible.getActive().set(true); newPermissible.getActive().set(true);
newPermissible.setOldPermissible(oldPermissible); newPermissible.setOldPermissible(oldPermissible);
newPermissible.updateSubscriptionsAsync();
// inject the new instance // inject the new instance
HUMAN_ENTITY_PERMISSIBLE_FIELD.set(player, newPermissible); 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 player the player to uninject from
* @param dummy if the replacement permissible should be a dummy. * @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 * @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. // gets the players current permissible.
PermissibleBase permissible = (PermissibleBase) HUMAN_ENTITY_PERMISSIBLE_FIELD.get(player); PermissibleBase permissible = (PermissibleBase) HUMAN_ENTITY_PERMISSIBLE_FIELD.get(player);
@ -152,11 +143,6 @@ public class Injector {
// clear all permissions // clear all permissions
lpPermissible.clearPermissions(); lpPermissible.clearPermissions();
// try to unsubscribe
if (unsubscribe) {
lpPermissible.unsubscribeFromAllAsync();
}
// set to inactive // set to inactive
lpPermissible.getActive().set(false); lpPermissible.getActive().set(false);
@ -174,12 +160,6 @@ public class Injector {
HUMAN_ENTITY_PERMISSIBLE_FIELD.set(player, newPb); HUMAN_ENTITY_PERMISSIBLE_FIELD.set(player, newPb);
} }
} }
INJECTED_PERMISSIBLES.remove(player.getUniqueId());
}
public static LPPermissible getPermissible(UUID uuid) {
return INJECTED_PERMISSIBLES.get(uuid);
} }
} }

View File

@ -32,7 +32,6 @@ import lombok.Setter;
import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Tristate; import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.bukkit.LPBukkitPlugin; 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.config.ConfigKeys;
import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.verbose.CheckOrigin; import me.lucko.luckperms.common.verbose.CheckOrigin;
@ -45,7 +44,6 @@ import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -78,9 +76,6 @@ public class LPPermissible extends PermissibleBase {
// the luckperms plugin instance // the luckperms plugin instance
private final LPBukkitPlugin plugin; 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) // the players previous permissible. (the one they had before this one was injected)
@Setter @Setter
private PermissibleBase oldPermissible = null; private PermissibleBase oldPermissible = null;
@ -97,7 +92,6 @@ public class LPPermissible extends PermissibleBase {
this.user = user; this.user = user;
this.player = player; this.player = player;
this.plugin = plugin; this.plugin = plugin;
this.subscriptions = new SubscriptionManager(this);
} }
@Override @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<String> 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. * Adds attachments to this permissible.
* *

View File

@ -0,0 +1,270 @@
/*
* 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 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<String, Map<Permissible, Boolean>> {
// the plugin instance
private final LPBukkitPlugin plugin;
public LPSubscriptionMap(LPBukkitPlugin plugin, Map<String, Map<Permissible, Boolean>> 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<Permissible, Boolean> get(Object key) {
if (key == null || !(key instanceof String)) {
return null;
}
String permission = ((String) key);
Map<Permissible, Boolean> 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<Permissible, Boolean> put(String key, Map<Permissible, Boolean> 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<String, Map<Permissible, Boolean>> detach() {
Map<String, Map<Permissible, Boolean>> ret = new HashMap<>();
for (Map.Entry<String, Map<Permissible, Boolean>> 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<Permissible, Boolean> {
// the permission being mapped to this value map
private final String permission;
// the backing map
private final Map<Permissible, Boolean> backing;
public LPSubscriptionValueMap(String permission, Map<Permissible, Boolean> 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<Permissible> keySet() {
// gather players (LPPermissibles)
Set<Permissible> 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<Entry<Permissible, Boolean>> 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<? extends Permissible, ? extends Boolean> m) {
backing.putAll(m);
}
@Override
public void clear() {
backing.clear();
}
@Override
public Collection<Boolean> values() {
return backing.values();
}
}
}

View File

@ -1,103 +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 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<String> currentSubscriptions = ImmutableSet.of();
public synchronized void subscribe(Set<String> perms) {
Set<String> 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<String>, Set<String>> 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<String> toAdd;
private final Set<String> 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<String>, Set<String>> compareSets(Set<String> local, Set<String> remote) {
// entries in local but not remote need to be added
// entries in remote but not local need to be removed
Set<String> toAdd = new HashSet<>(local);
toAdd.removeAll(remote);
Set<String> toRemove = new HashSet<>(remote);
toRemove.removeAll(local);
return Maps.immutableEntry(toAdd, toRemove);
}
}

View File

@ -0,0 +1,108 @@
/*
* 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 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<String, Map<Permissible, Boolean>> castedMap = (Map<String, Map<Permissible, Boolean>>) 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();
}
}
}

View File

@ -45,7 +45,7 @@ public class DefaultsProcessor implements PermissionProcessor {
@Override @Override
public Tristate hasPermission(String permission) { public Tristate hasPermission(String permission) {
Tristate t = defaultsProvider.hasDefault(permission, isOp); Tristate t = defaultsProvider.lookup(permission, isOp);
if (t != Tristate.UNDEFINED) { if (t != Tristate.UNDEFINED) {
return t; return t;
} }

View File

@ -78,7 +78,7 @@ public class DefaultsProvider {
* @param isOp if the player is op * @param isOp if the player is op
* @return a tristate result * @return a tristate result
*/ */
public Tristate hasDefault(String permission, boolean isOp) { public Tristate lookup(String permission, boolean isOp) {
Map<String, Boolean> map = isOp ? opDefaults : nonOpDefaults; Map<String, Boolean> map = isOp ? opDefaults : nonOpDefaults;
Boolean b = map.get(permission); Boolean b = map.get(permission);
@ -126,6 +126,10 @@ public class DefaultsProvider {
unregisterDefaults(nonOpDefaults, nonOpDummy, false); unregisterDefaults(nonOpDefaults, nonOpDummy, false);
} }
private static PluginManager pm() {
return Bukkit.getServer().getPluginManager();
}
/** /**
* Unregisters defaults for a given permissible. * Unregisters defaults for a given permissible.
* *
@ -136,21 +140,21 @@ public class DefaultsProvider {
Set<String> perms = map.keySet(); Set<String> perms = map.keySet();
for (String name : perms) { 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<String, Boolean> map, DummyPermissible p, boolean op) { private static void calculateDefaults(Map<String, Boolean> map, DummyPermissible p, boolean op) {
Bukkit.getServer().getPluginManager().subscribeToDefaultPerms(op, p); pm().subscribeToDefaultPerms(op, p);
Set<Permission> defaults = Bukkit.getServer().getPluginManager().getDefaultPermissions(op); Set<Permission> defaults = pm().getDefaultPermissions(op);
for (Permission perm : defaults) { for (Permission perm : defaults) {
String name = perm.getName().toLowerCase(); String name = perm.getName().toLowerCase();
map.put(name, true); map.put(name, true);
Bukkit.getServer().getPluginManager().subscribeToPermission(name, p); pm().subscribeToPermission(name, p);
// register defaults for any children too // register defaults for any children too
calculateChildPermissions(map, p, perm.getChildren(), false); calculateChildPermissions(map, p, perm.getChildren(), false);
@ -167,10 +171,10 @@ public class DefaultsProvider {
boolean value = e.getValue() ^ invert; boolean value = e.getValue() ^ invert;
accumulator.put(e.getKey().toLowerCase(), value); 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 // lookup any deeper children & resolve if present
Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey()); Permission perm = pm().getPermission(e.getKey());
if (perm != null) { if (perm != null) {
calculateChildPermissions(accumulator, p, perm.getChildren(), !value); calculateChildPermissions(accumulator, p, perm.getChildren(), !value);
} }

View File

@ -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) { static void sendStartupBanner(Sender sender, LuckPermsPlugin plugin) {
sender.sendMessage(Util.color("&b __ &3 __ ___ __ __ ")); sender.sendMessage(Util.color("&b __ &3 __ ___ __ __ "));
sender.sendMessage(Util.color("&b | | | / ` |__/ &3|__) |__ |__) |\\/| /__` ")); sender.sendMessage(Util.color("&b | | | / ` |__/ &3|__) |__ |__) |\\/| /__` "));