Refactor caching system (WIP) - still working towards #23
This commit is contained in:
+21
-32
@@ -20,53 +20,42 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.vault.cache;
|
||||
package me.lucko.luckperms;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import lombok.AllArgsConstructor;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.calculators.*;
|
||||
import me.lucko.luckperms.users.BukkitUser;
|
||||
import me.lucko.luckperms.inject.Injector;
|
||||
import me.lucko.luckperms.inject.LPPermissible;
|
||||
import me.lucko.luckperms.users.User;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ContextCache {
|
||||
@AllArgsConstructor
|
||||
public class BukkitCalculatorFactory implements CalculatorFactory {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
@Getter
|
||||
private final Map<String, String> context;
|
||||
|
||||
@Getter
|
||||
private final Map<String, Boolean> permissionCache = new ConcurrentHashMap<>();
|
||||
|
||||
private final PermissionCalculator calculator;
|
||||
|
||||
public ContextCache(User user, Map<String, String> context, LuckPermsPlugin plugin, DefaultsProvider defaultsProvider) {
|
||||
this.context = context;
|
||||
@Override
|
||||
public PermissionCalculator build(Contexts contexts, User user, Map<String, Boolean> map) {
|
||||
UUID uuid = plugin.getUuidCache().getExternalUUID(user.getUuid());
|
||||
|
||||
List<PermissionProcessor> processors = new ArrayList<>(5);
|
||||
processors.add(new MapProcessor(permissionCache));
|
||||
processors.add(new MapProcessor(map));
|
||||
processors.add(new AttachmentProcessor(() -> {
|
||||
LPPermissible permissible = Injector.getPermissible(uuid);
|
||||
return permissible == null ? null : permissible.getAttachmentPermissions();
|
||||
}));
|
||||
if (plugin.getConfiguration().isApplyingWildcards()) {
|
||||
processors.add(new WildcardProcessor(permissionCache));
|
||||
processors.add(new WildcardProcessor(map));
|
||||
}
|
||||
if (plugin.getConfiguration().isApplyingRegex()) {
|
||||
processors.add(new RegexProcessor(permissionCache));
|
||||
processors.add(new RegexProcessor(map));
|
||||
}
|
||||
processors.add(new DefaultsProcessor(contexts.isOp(), plugin.getDefaultsProvider()));
|
||||
|
||||
processors.add(new DefaultsProcessor(((BukkitUser) user)::isOp, defaultsProvider));
|
||||
calculator = new PermissionCalculator(plugin, user.getName(), plugin.getConfiguration().isDebugPermissionChecks(), processors);
|
||||
return new PermissionCalculator(plugin, user.getName(), plugin.getConfiguration().isDebugPermissionChecks(), processors);
|
||||
}
|
||||
|
||||
public void invalidateCache() {
|
||||
calculator.invalidateCache();
|
||||
}
|
||||
|
||||
public Tristate getPermissionValue(@NonNull String permission) {
|
||||
return calculator.getPermissionValue(permission);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,21 +22,20 @@
|
||||
|
||||
package me.lucko.luckperms;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.constants.Message;
|
||||
import me.lucko.luckperms.inject.Injector;
|
||||
import me.lucko.luckperms.inject.LPPermissible;
|
||||
import me.lucko.luckperms.users.BukkitUser;
|
||||
import me.lucko.luckperms.users.User;
|
||||
import me.lucko.luckperms.utils.AbstractListener;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.*;
|
||||
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
class BukkitListener extends AbstractListener implements Listener {
|
||||
@@ -50,6 +49,7 @@ class BukkitListener extends AbstractListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerPreLogin(AsyncPlayerPreLoginEvent e) {
|
||||
if (!plugin.getDatastore().isAcceptingLogins()) {
|
||||
|
||||
// The datastore is disabled, prevent players from joining the server
|
||||
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
|
||||
return;
|
||||
@@ -57,38 +57,14 @@ class BukkitListener extends AbstractListener implements Listener {
|
||||
|
||||
// Process login
|
||||
onAsyncLogin(e.getUniqueId(), e.getName());
|
||||
|
||||
// Pre-process the user's permissions, so they're ready for PLE.
|
||||
BukkitUser user = (BukkitUser) plugin.getUserManager().get(plugin.getUuidCache().getUUID(e.getUniqueId()));
|
||||
Map<String, Boolean> toApply = user.exportNodes(
|
||||
new Contexts(
|
||||
Collections.singletonMap("server", plugin.getConfiguration().getServer()),
|
||||
plugin.getConfiguration().isIncludingGlobalPerms(),
|
||||
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
|
||||
true,
|
||||
plugin.getConfiguration().isApplyingGlobalGroups(),
|
||||
plugin.getConfiguration().isApplyingGlobalWorldGroups()
|
||||
),
|
||||
Collections.emptyList(),
|
||||
true
|
||||
);
|
||||
user.setLoginPreProcess(toApply);
|
||||
|
||||
// Hook with Vault early
|
||||
if (plugin.getVaultHook() != null && plugin.getVaultHook().isHooked()) {
|
||||
plugin.getVaultHook().getPermissionHook().getVaultUserManager().setupUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerPreLoginMonitor(AsyncPlayerPreLoginEvent e) {
|
||||
if (plugin.getDatastore().isAcceptingLogins() && e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
|
||||
|
||||
// Login event was cancelled by another plugin
|
||||
final UUID internal = plugin.getUuidCache().getUUID(e.getUniqueId());
|
||||
onLeave(e.getUniqueId());
|
||||
if (plugin.getVaultHook() != null && plugin.getVaultHook().isHooked()) {
|
||||
plugin.getVaultHook().getPermissionHook().getVaultUserManager().clearUser(internal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,61 +74,56 @@ class BukkitListener extends AbstractListener implements Listener {
|
||||
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||
|
||||
if (user == null) {
|
||||
// User wasn't loaded for whatever reason.
|
||||
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
BukkitUser u = (BukkitUser) user;
|
||||
try {
|
||||
// Make a new permissible for the user
|
||||
LPPermissible lpPermissible = new LPPermissible(player, plugin, plugin.getDefaultsProvider());
|
||||
|
||||
// Insert the pre-processed permissions into the permissible
|
||||
lpPermissible.getLuckPermsPermissions().putAll(u.getLoginPreProcess());
|
||||
u.setLoginPreProcess(null);
|
||||
LPPermissible lpPermissible = new LPPermissible(player, user, plugin);
|
||||
|
||||
// Inject into the player
|
||||
Injector.inject(player, lpPermissible);
|
||||
u.setPermissible(lpPermissible);
|
||||
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
if (player.isOp()) {
|
||||
|
||||
// We assume all users are not op, but those who are need extra calculation.
|
||||
plugin.doAsync(() -> user.getUserData().preCalculate(plugin.getPreProcessContexts(true)));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerLoginMonitor(PlayerLoginEvent e) {
|
||||
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
|
||||
|
||||
// The player got denied on sync login.
|
||||
final UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
|
||||
onLeave(e.getPlayer().getUniqueId());
|
||||
if (plugin.getVaultHook() != null && plugin.getVaultHook().isHooked()) {
|
||||
plugin.getVaultHook().getPermissionHook().getVaultUserManager().clearUser(internal);
|
||||
}
|
||||
} else {
|
||||
User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
|
||||
|
||||
// Call another update to calculate full context. (incl. per world permissions)
|
||||
plugin.doAsync(user::refreshPermissions);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerJoin(PlayerJoinEvent e) {
|
||||
// Refresh permissions again
|
||||
UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
|
||||
plugin.getWorldCalculator().getWorldCache().put(internal, e.getPlayer().getWorld().getName());
|
||||
plugin.doAsync(() -> refreshPlayer(internal));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
@EventHandler(priority = EventPriority.HIGHEST) // Allow other plugins to see data when this event gets called.
|
||||
public void onPlayerQuit(PlayerQuitEvent e) {
|
||||
final UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
|
||||
final Player player = e.getPlayer();
|
||||
final UUID internal = plugin.getUuidCache().getUUID(player.getUniqueId());
|
||||
|
||||
// Remove from World cache
|
||||
plugin.getWorldCalculator().getWorldCache().remove(internal);
|
||||
onLeave(e.getPlayer().getUniqueId());
|
||||
if (plugin.getVaultHook() != null && plugin.getVaultHook().isHooked()) {
|
||||
plugin.getVaultHook().getPermissionHook().getVaultUserManager().clearUser(internal);
|
||||
|
||||
// Remove the custom permissible
|
||||
Injector.unInject(player);
|
||||
|
||||
// Handle auto op
|
||||
if (plugin.getConfiguration().isAutoOp()) {
|
||||
player.setOp(false);
|
||||
}
|
||||
|
||||
// Call internal leave handling
|
||||
onLeave(player.getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
||||
@@ -23,11 +23,13 @@
|
||||
package me.lucko.luckperms;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Logger;
|
||||
import me.lucko.luckperms.api.LuckPermsApi;
|
||||
import me.lucko.luckperms.api.PlatformType;
|
||||
import me.lucko.luckperms.api.implementation.ApiProvider;
|
||||
import me.lucko.luckperms.api.vault.VaultHook;
|
||||
import me.lucko.luckperms.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.calculators.DefaultsProvider;
|
||||
import me.lucko.luckperms.commands.ConsecutiveExecutor;
|
||||
import me.lucko.luckperms.commands.Sender;
|
||||
@@ -35,7 +37,6 @@ import me.lucko.luckperms.config.LPConfiguration;
|
||||
import me.lucko.luckperms.constants.Message;
|
||||
import me.lucko.luckperms.contexts.ContextManager;
|
||||
import me.lucko.luckperms.contexts.ServerCalculator;
|
||||
import me.lucko.luckperms.contexts.WorldCalculator;
|
||||
import me.lucko.luckperms.core.UuidCache;
|
||||
import me.lucko.luckperms.data.Importer;
|
||||
import me.lucko.luckperms.groups.GroupManager;
|
||||
@@ -44,9 +45,10 @@ import me.lucko.luckperms.runnables.UpdateTask;
|
||||
import me.lucko.luckperms.storage.Datastore;
|
||||
import me.lucko.luckperms.storage.StorageFactory;
|
||||
import me.lucko.luckperms.tracks.TrackManager;
|
||||
import me.lucko.luckperms.users.BukkitUserManager;
|
||||
import me.lucko.luckperms.users.UserManager;
|
||||
import me.lucko.luckperms.utils.LocaleManager;
|
||||
import me.lucko.luckperms.utils.LogFactory;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permission;
|
||||
@@ -66,7 +68,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
|
||||
private LPConfiguration configuration;
|
||||
private BukkitUserManager userManager;
|
||||
private UserManager userManager;
|
||||
private GroupManager groupManager;
|
||||
private TrackManager trackManager;
|
||||
private Datastore datastore;
|
||||
@@ -79,6 +81,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private LocaleManager localeManager;
|
||||
private ContextManager<Player> contextManager;
|
||||
private WorldCalculator worldCalculator;
|
||||
private CalculatorFactory calculatorFactory;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
@@ -117,18 +120,18 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
getLog().info("Loading internal permission managers...");
|
||||
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
|
||||
userManager = new BukkitUserManager(this);
|
||||
userManager = new UserManager(this);
|
||||
groupManager = new GroupManager(this);
|
||||
trackManager = new TrackManager();
|
||||
importer = new Importer(commandManager);
|
||||
consecutiveExecutor = new ConsecutiveExecutor(commandManager);
|
||||
calculatorFactory = new BukkitCalculatorFactory(this);
|
||||
|
||||
contextManager = new ContextManager<>();
|
||||
worldCalculator = new WorldCalculator(this);
|
||||
pm.registerEvents(worldCalculator, this);
|
||||
contextManager.registerCalculator(worldCalculator);
|
||||
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
|
||||
contextManager.registerListener(userManager);
|
||||
|
||||
int mins = getConfiguration().getSyncTime();
|
||||
if (mins > 0) {
|
||||
@@ -244,15 +247,68 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPossiblePermissions() {
|
||||
final List<String> perms = new ArrayList<>();
|
||||
public Set<Contexts> getPreProcessContexts(boolean op) {
|
||||
Set<Map<String, String>> c = new HashSet<>();
|
||||
c.add(Collections.emptyMap());
|
||||
c.add(Collections.singletonMap("server", getConfiguration().getServer()));
|
||||
|
||||
getServer().getPluginManager().getPermissions().forEach(p -> {
|
||||
perms.add(p.getName());
|
||||
p.getChildren().keySet().forEach(perms::add);
|
||||
});
|
||||
// Pre process all worlds
|
||||
c.addAll(getServer().getWorlds().stream()
|
||||
.map(World::getName)
|
||||
.map(s -> {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("server", getConfiguration().getServer());
|
||||
map.put("world", s);
|
||||
return map;
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
return perms;
|
||||
// Pre process the separate Vault server, if any
|
||||
if (!getConfiguration().getServer().equals(getConfiguration().getVaultServer())) {
|
||||
c.add(Collections.singletonMap("server", getConfiguration().getVaultServer()));
|
||||
c.addAll(getServer().getWorlds().stream()
|
||||
.map(World::getName)
|
||||
.map(s -> {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("server", getConfiguration().getVaultServer());
|
||||
map.put("world", s);
|
||||
return map;
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
Set<Contexts> contexts = new HashSet<>();
|
||||
|
||||
// Convert to full Contexts
|
||||
contexts.addAll(c.stream()
|
||||
.map(map -> new Contexts(
|
||||
map,
|
||||
getConfiguration().isIncludingGlobalPerms(),
|
||||
getConfiguration().isIncludingGlobalWorldPerms(),
|
||||
true,
|
||||
getConfiguration().isApplyingGlobalGroups(),
|
||||
getConfiguration().isApplyingGlobalWorldGroups(),
|
||||
op
|
||||
))
|
||||
.collect(Collectors.toSet())
|
||||
);
|
||||
|
||||
// Check for and include varying Vault config options
|
||||
try {
|
||||
assert getConfiguration().isVaultIncludingGlobal() == getConfiguration().isIncludingGlobalPerms();
|
||||
assert getConfiguration().isIncludingGlobalWorldPerms();
|
||||
assert getConfiguration().isApplyingGlobalGroups();
|
||||
assert getConfiguration().isApplyingGlobalWorldGroups();
|
||||
} catch (AssertionError e) {
|
||||
contexts.addAll(c.stream()
|
||||
.map(map -> new Contexts(map, getConfiguration().isVaultIncludingGlobal(), true, true, true, true, op))
|
||||
.collect(Collectors.toSet())
|
||||
);
|
||||
}
|
||||
|
||||
return contexts;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.contexts;
|
||||
package me.lucko.luckperms;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.Getter;
|
||||
@@ -25,8 +25,7 @@ package me.lucko.luckperms.api.vault;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.vault.cache.ChatCache;
|
||||
import me.lucko.luckperms.api.vault.cache.VaultUser;
|
||||
import me.lucko.luckperms.caching.MetaData;
|
||||
import me.lucko.luckperms.core.PermissionHolder;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
@@ -74,14 +73,14 @@ public class VaultChatHook extends Chat {
|
||||
return perms.isEnabled();
|
||||
}
|
||||
|
||||
private void saveMeta(PermissionHolder holder, String world, String node, String value) {
|
||||
private void setMeta(PermissionHolder holder, String world, String node, String value) {
|
||||
String finalWorld = perms.isIgnoreWorld() ? null : world;
|
||||
if (holder == null) return;
|
||||
if (node.equals("")) return;
|
||||
|
||||
perms.log("Setting meta: '" + node + "' for " + holder.getObjectName() + " on world " + world + ", server " + perms.getServer());
|
||||
|
||||
perms.scheduleTask(() -> {
|
||||
perms.getScheduler().scheduleTask(() -> {
|
||||
String k = escapeCharacters(node);
|
||||
String v = escapeCharacters(value);
|
||||
|
||||
@@ -118,7 +117,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
perms.log("Setting " + (prefix ? "prefix" : "suffix") + " for " + holder.getObjectName() + " on world " + world + ", server " + perms.getServer());
|
||||
|
||||
perms.scheduleTask(() -> {
|
||||
perms.getScheduler().scheduleTask(() -> {
|
||||
Node.Builder node = new me.lucko.luckperms.core.Node.Builder(prefix ? "prefix" : "suffix" + ".1000." + escapeCharacters(value));
|
||||
node.setValue(true);
|
||||
if (!perms.getServer().equalsIgnoreCase("global")) {
|
||||
@@ -138,46 +137,32 @@ public class VaultChatHook extends Chat {
|
||||
}
|
||||
|
||||
private String getUserMeta(User user, String world, String node, String defaultValue) {
|
||||
world = perms.isIgnoreWorld() ? null : world;
|
||||
if (user == null) return defaultValue;
|
||||
world = perms.isIgnoreWorld() ? null : world;
|
||||
node = escapeCharacters(node);
|
||||
|
||||
perms.log("Getting meta: '" + node + "' for user " + user.getName() + " on world " + world + ", server " + perms.getServer());
|
||||
|
||||
if (!perms.getVaultUserManager().containsUser(user.getUuid())) {
|
||||
if (user.getUserData() == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
VaultUser vaultUser = perms.getVaultUserManager().getUser(user.getUuid());
|
||||
Map<String, String> context = new HashMap<>();
|
||||
context.put("server", perms.getServer());
|
||||
if (world != null) {
|
||||
context.put("world", world);
|
||||
}
|
||||
|
||||
ChatCache cd = vaultUser.processChatData(context);
|
||||
return unescapeCharacters(cd.getMeta().getOrDefault(node, defaultValue));
|
||||
return unescapeCharacters(user.getUserData().getMetaData(perms.createContext(perms.getServer(), world)).getMeta().getOrDefault(node, defaultValue));
|
||||
}
|
||||
|
||||
private String getUserChatMeta(boolean prefix, User user, String world) {
|
||||
world = perms.isIgnoreWorld() ? null : world;
|
||||
if (user == null) return "";
|
||||
world = perms.isIgnoreWorld() ? null : world;
|
||||
|
||||
perms.log("Getting " + (prefix ? "prefix" : "suffix") + " for user " + user.getName() + " on world " + world + ", server " + perms.getServer());
|
||||
|
||||
if (!perms.getVaultUserManager().containsUser(user.getUuid())) {
|
||||
if (user.getUserData() == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
VaultUser vaultUser = perms.getVaultUserManager().getUser(user.getUuid());
|
||||
Map<String, String> context = new HashMap<>();
|
||||
context.put("server", perms.getServer());
|
||||
if (world != null) {
|
||||
context.put("world", world);
|
||||
}
|
||||
|
||||
ChatCache cd = vaultUser.processChatData(context);
|
||||
return unescapeCharacters(prefix ? (cd.getPrefix() == null ? "" : cd.getPrefix()) : (cd.getSuffix() == null ? "" : cd.getSuffix()));
|
||||
MetaData data = user.getUserData().getMetaData(perms.createContext(perms.getServer(), world));
|
||||
String v = prefix ? data.getPrefix() : data.getSuffix();
|
||||
return v == null ? "" : unescapeCharacters(v);
|
||||
}
|
||||
|
||||
private String getGroupMeta(Group group, String world, String node, String defaultValue) {
|
||||
@@ -307,7 +292,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
public void setPlayerInfoInteger(String world, @NonNull String player, @NonNull String node, int value) {
|
||||
final User user = perms.getPlugin().getUserManager().get(player);
|
||||
saveMeta(user, world, node, String.valueOf(value));
|
||||
setMeta(user, world, node, String.valueOf(value));
|
||||
}
|
||||
|
||||
public int getGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int defaultValue) {
|
||||
@@ -321,7 +306,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
public void setGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int value) {
|
||||
final Group g = perms.getPlugin().getGroupManager().get(group);
|
||||
saveMeta(g, world, node, String.valueOf(value));
|
||||
setMeta(g, world, node, String.valueOf(value));
|
||||
}
|
||||
|
||||
public double getPlayerInfoDouble(String world, @NonNull String player, @NonNull String node, double defaultValue) {
|
||||
@@ -335,7 +320,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
public void setPlayerInfoDouble(String world, @NonNull String player, @NonNull String node, double value) {
|
||||
final User user = perms.getPlugin().getUserManager().get(player);
|
||||
saveMeta(user, world, node, String.valueOf(value));
|
||||
setMeta(user, world, node, String.valueOf(value));
|
||||
}
|
||||
|
||||
public double getGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double defaultValue) {
|
||||
@@ -349,7 +334,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
public void setGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double value) {
|
||||
final Group g = perms.getPlugin().getGroupManager().get(group);
|
||||
saveMeta(g, world, node, String.valueOf(value));
|
||||
setMeta(g, world, node, String.valueOf(value));
|
||||
}
|
||||
|
||||
public boolean getPlayerInfoBoolean(String world, @NonNull String player, @NonNull String node, boolean defaultValue) {
|
||||
@@ -363,7 +348,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
public void setPlayerInfoBoolean(String world, @NonNull String player, @NonNull String node, boolean value) {
|
||||
final User user = perms.getPlugin().getUserManager().get(player);
|
||||
saveMeta(user, world, node, String.valueOf(value));
|
||||
setMeta(user, world, node, String.valueOf(value));
|
||||
}
|
||||
|
||||
public boolean getGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean defaultValue) {
|
||||
@@ -377,7 +362,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
public void setGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean value) {
|
||||
final Group g = perms.getPlugin().getGroupManager().get(group);
|
||||
saveMeta(g, world, node, String.valueOf(value));
|
||||
setMeta(g, world, node, String.valueOf(value));
|
||||
}
|
||||
|
||||
public String getPlayerInfoString(String world, @NonNull String player, @NonNull String node, String defaultValue) {
|
||||
@@ -387,7 +372,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
public void setPlayerInfoString(String world, @NonNull String player, @NonNull String node, String value) {
|
||||
final User user = perms.getPlugin().getUserManager().get(player);
|
||||
saveMeta(user, world, node, value);
|
||||
setMeta(user, world, node, value);
|
||||
}
|
||||
|
||||
public String getGroupInfoString(String world, @NonNull String group, @NonNull String node, String defaultValue) {
|
||||
@@ -397,7 +382,7 @@ public class VaultChatHook extends Chat {
|
||||
|
||||
public void setGroupInfoString(String world, @NonNull String group, @NonNull String node, String value) {
|
||||
final Group g = perms.getPlugin().getGroupManager().get(group);
|
||||
saveMeta(g, world, node, value);
|
||||
setMeta(g, world, node, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@ import lombok.Setter;
|
||||
import me.lucko.luckperms.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.vault.cache.VaultUser;
|
||||
import me.lucko.luckperms.api.vault.cache.VaultUserManager;
|
||||
import me.lucko.luckperms.core.PermissionHolder;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
@@ -37,21 +35,22 @@ import me.lucko.luckperms.groups.Group;
|
||||
import me.lucko.luckperms.users.User;
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The LuckPerms Vault Permission implementation
|
||||
* Most lookups are cached.
|
||||
*/
|
||||
public class VaultPermissionHook extends Permission implements Runnable {
|
||||
private final List<Runnable> tasks = new ArrayList<>();
|
||||
public class VaultPermissionHook extends Permission {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private LPBukkitPlugin plugin;
|
||||
|
||||
@Getter
|
||||
private VaultUserManager vaultUserManager;
|
||||
private VaultScheduler scheduler;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@@ -66,8 +65,7 @@ public class VaultPermissionHook extends Permission implements Runnable {
|
||||
private boolean ignoreWorld = false;
|
||||
|
||||
public void setup() {
|
||||
vaultUserManager = new VaultUserManager(plugin, this);
|
||||
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this, 1L, 1L);
|
||||
scheduler = new VaultScheduler(plugin);
|
||||
}
|
||||
|
||||
public void log(String s) {
|
||||
@@ -76,23 +74,6 @@ public class VaultPermissionHook extends Permission implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
void scheduleTask(Runnable r) {
|
||||
synchronized (tasks) {
|
||||
tasks.add(r);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
List<Runnable> toRun = new ArrayList<>();
|
||||
synchronized (tasks) {
|
||||
toRun.addAll(tasks);
|
||||
tasks.clear();
|
||||
}
|
||||
|
||||
toRun.forEach(Runnable::run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "LuckPerms";
|
||||
@@ -108,133 +89,149 @@ public class VaultPermissionHook extends Permission implements Runnable {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean objectHas(String world, Group group, String permission) {
|
||||
if (group == null) return false;
|
||||
/**
|
||||
* Generic method to add a permission to a holder
|
||||
* @param world the world to add in
|
||||
* @param holder the holder to add the permission to
|
||||
* @param permission the permission to add
|
||||
*/
|
||||
private void add(String world, PermissionHolder holder, String permission) {
|
||||
try {
|
||||
if (world != null && !world.equals("")) {
|
||||
holder.setPermission(permission, true, server, world);
|
||||
} else {
|
||||
holder.setPermission(permission, true, server);
|
||||
}
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
|
||||
save(holder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic method to remove a permission from a holder
|
||||
* @param world the world to remove in
|
||||
* @param holder the holder to remove the permission from
|
||||
* @param permission the permission to remove
|
||||
*/
|
||||
private void remove(String world, PermissionHolder holder, String permission) {
|
||||
try {
|
||||
if (world != null && !world.equals("")) {
|
||||
holder.unsetPermission(permission, server, world);
|
||||
} else {
|
||||
holder.unsetPermission(permission, server);
|
||||
}
|
||||
} catch (ObjectLacksException ignored) {}
|
||||
|
||||
save(holder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for saving a user or group
|
||||
* @param holder the holder instance
|
||||
*/
|
||||
void save(PermissionHolder holder) {
|
||||
if (holder instanceof User) {
|
||||
((User) holder).refreshPermissions();
|
||||
plugin.getDatastore().saveUser(((User) holder));
|
||||
}
|
||||
if (holder instanceof Group) {
|
||||
plugin.getDatastore().saveGroup(((Group) holder));
|
||||
plugin.runUpdateTask();
|
||||
}
|
||||
}
|
||||
|
||||
Contexts createContext(String server, String world) {
|
||||
Map<String, String> context = new HashMap<>();
|
||||
if (world != null && !world.equals("")) {
|
||||
context.put("world", world);
|
||||
}
|
||||
context.put("server", server);
|
||||
|
||||
Map<String, Boolean> toApply = group.exportNodes(
|
||||
new Contexts(context, includeGlobal, includeGlobal, true, true, true),
|
||||
Collections.emptyList(), true
|
||||
);
|
||||
|
||||
return toApply.containsKey(permission) && toApply.get(permission);
|
||||
}
|
||||
|
||||
private boolean add(String world, PermissionHolder object, String permission) {
|
||||
if (object == null) return false;
|
||||
|
||||
try {
|
||||
if (world != null && !world.equals("")) {
|
||||
object.setPermission(permission, true, server, world);
|
||||
} else {
|
||||
object.setPermission(permission, true, server);
|
||||
}
|
||||
} catch (ObjectAlreadyHasException ignored) {}
|
||||
|
||||
save(object);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean remove(String world, PermissionHolder object, String permission) {
|
||||
if (object == null) return false;
|
||||
|
||||
try {
|
||||
if (world != null && !world.equals("")) {
|
||||
object.unsetPermission(permission, server, world);
|
||||
} else {
|
||||
object.unsetPermission(permission, server);
|
||||
}
|
||||
} catch (ObjectLacksException ignored) {}
|
||||
|
||||
save(object);
|
||||
return true;
|
||||
}
|
||||
|
||||
void save(PermissionHolder t) {
|
||||
if (t instanceof User) {
|
||||
((User) t).refreshPermissions();
|
||||
plugin.getDatastore().saveUser(((User) t));
|
||||
}
|
||||
if (t instanceof Group) {
|
||||
plugin.getDatastore().saveGroup(((Group) t));
|
||||
plugin.runUpdateTask();
|
||||
}
|
||||
return new Contexts(context, isIncludeGlobal(), true, true, true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerHas(String world, @NonNull String player, @NonNull String permission) {
|
||||
world = ignoreWorld ? null : world;
|
||||
world = ignoreWorld ? null : world; // Correct world value
|
||||
log("Checking if player " + player + " has permission: " + permission + " on world " + world + ", server " + server);
|
||||
|
||||
User user = plugin.getUserManager().get(player);
|
||||
if (user == null) return false;
|
||||
|
||||
if (!vaultUserManager.containsUser(user.getUuid())) {
|
||||
if (user.getUserData() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VaultUser vaultUser = vaultUserManager.getUser(user.getUuid());
|
||||
Map<String, String> context = new HashMap<>();
|
||||
context.put("server", server);
|
||||
if (world != null) {
|
||||
context.put("world", world);
|
||||
}
|
||||
|
||||
return vaultUser.hasPermission(context, permission);
|
||||
// Effectively fallback to the standard Bukkit #hasPermission check.
|
||||
return user.getUserData().getPermissionData(createContext(server, world)).getPermissionValue(permission).asBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerAdd(String world, @NonNull String player, @NonNull String permission) {
|
||||
String finalWorld = ignoreWorld ? null : world;
|
||||
String finalWorld = ignoreWorld ? null : world; // Correct world value
|
||||
log("Adding permission to player " + player + ": '" + permission + "' on world " + finalWorld + ", server " + server);
|
||||
|
||||
final User user = plugin.getUserManager().get(player);
|
||||
scheduleTask(() -> add(finalWorld, user, permission));
|
||||
if (user == null) return false;
|
||||
|
||||
scheduler.scheduleTask(() -> add(finalWorld, user, permission));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerRemove(String world, @NonNull String player, @NonNull String permission) {
|
||||
String finalWorld = ignoreWorld ? null : world;
|
||||
String finalWorld = ignoreWorld ? null : world; // Correct world value
|
||||
log("Removing permission from player " + player + ": '" + permission + "' on world " + finalWorld + ", server " + server);
|
||||
|
||||
final User user = plugin.getUserManager().get(player);
|
||||
scheduleTask(() -> remove(finalWorld, user, permission));
|
||||
if (user == null) return false;
|
||||
|
||||
scheduler.scheduleTask(() -> remove(finalWorld, user, permission));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean groupHas(String world, @NonNull String groupName, @NonNull String permission) {
|
||||
world = ignoreWorld ? null : world;
|
||||
world = ignoreWorld ? null : world; // Correct world value
|
||||
log("Checking if group " + groupName + " has permission: " + permission + " on world " + world + ", server " + server);
|
||||
|
||||
final Group group = plugin.getGroupManager().get(groupName);
|
||||
return objectHas(world, group, permission);
|
||||
if (group == null) return false;
|
||||
|
||||
// This is a nasty call. Groups aren't cached. :(
|
||||
Map<String, Boolean> permissions = group.exportNodes(createContext(server, world), Collections.emptyList(), true);
|
||||
|
||||
return permissions.containsKey(permission) && permissions.get(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean groupAdd(String world, @NonNull String groupName, @NonNull String permission) {
|
||||
String finalWorld = ignoreWorld ? null : world;
|
||||
String finalWorld = ignoreWorld ? null : world; // Correct world value
|
||||
log("Adding permission to group " + groupName + ": '" + permission + "' on world " + finalWorld + ", server " + server);
|
||||
|
||||
final Group group = plugin.getGroupManager().get(groupName);
|
||||
scheduleTask(() -> add(finalWorld, group, permission));
|
||||
if (group == null) return false;
|
||||
|
||||
scheduler.scheduleTask(() -> add(finalWorld, group, permission));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean groupRemove(String world, @NonNull String groupName, @NonNull String permission) {
|
||||
String finalWorld = ignoreWorld ? null : world;
|
||||
String finalWorld = ignoreWorld ? null : world; // Correct world value
|
||||
log("Removing permission from group " + groupName + ": '" + permission + "' on world " + finalWorld + ", server " + server);
|
||||
|
||||
final Group group = plugin.getGroupManager().get(groupName);
|
||||
scheduleTask(() -> remove(finalWorld, group, permission));
|
||||
if (group == null) return false;
|
||||
|
||||
scheduler.scheduleTask(() -> remove(finalWorld, group, permission));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerInGroup(String world, @NonNull String player, @NonNull String group) {
|
||||
String finalWorld = ignoreWorld ? null : world;
|
||||
String finalWorld = ignoreWorld ? null : world; // Correct world value
|
||||
log("Checking if player " + player + " is in group: " + group + " on world " + finalWorld + ", server " + server);
|
||||
|
||||
final User user = plugin.getUserManager().get(player);
|
||||
if (user == null) return false;
|
||||
|
||||
@@ -249,15 +246,16 @@ public class VaultPermissionHook extends Permission implements Runnable {
|
||||
|
||||
@Override
|
||||
public boolean playerAddGroup(String world, @NonNull String player, @NonNull String groupName) {
|
||||
String finalWorld = ignoreWorld ? null : world;
|
||||
String finalWorld = ignoreWorld ? null : world; // Correct world value
|
||||
log("Adding player " + player + " to group: '" + groupName + "' on world " + finalWorld + ", server " + server);
|
||||
|
||||
final User user = plugin.getUserManager().get(player);
|
||||
if (user == null) return false;
|
||||
|
||||
final Group group = plugin.getGroupManager().get(groupName);
|
||||
if (group == null) return false;
|
||||
|
||||
scheduleTask(() -> {
|
||||
scheduler.scheduleTask(() -> {
|
||||
try {
|
||||
if (finalWorld != null && !finalWorld.equals("")) {
|
||||
user.addGroup(group, server, finalWorld);
|
||||
@@ -272,15 +270,16 @@ public class VaultPermissionHook extends Permission implements Runnable {
|
||||
|
||||
@Override
|
||||
public boolean playerRemoveGroup(String world, @NonNull String player, @NonNull String groupName) {
|
||||
String finalWorld = ignoreWorld ? null : world;
|
||||
String finalWorld = ignoreWorld ? null : world; // Correct world value
|
||||
log("Removing player " + player + " from group: '" + groupName + "' on world " + finalWorld + ", server " + server);
|
||||
|
||||
final User user = plugin.getUserManager().get(player);
|
||||
if (user == null) return false;
|
||||
|
||||
final Group group = plugin.getGroupManager().get(groupName);
|
||||
if (group == null) return false;
|
||||
|
||||
scheduleTask(() -> {
|
||||
scheduler.scheduleTask(() -> {
|
||||
try {
|
||||
if (finalWorld != null && !finalWorld.equals("")) {
|
||||
user.removeGroup(group, server, finalWorld);
|
||||
@@ -295,8 +294,9 @@ public class VaultPermissionHook extends Permission implements Runnable {
|
||||
|
||||
@Override
|
||||
public String[] getPlayerGroups(String world, @NonNull String player) {
|
||||
String finalWorld = ignoreWorld ? null : world;
|
||||
String finalWorld = ignoreWorld ? null : world; // Correct world value
|
||||
log("Getting groups of player: " + player + ", on world " + finalWorld + ", server " + server);
|
||||
|
||||
User user = plugin.getUserManager().get(player);
|
||||
if (user == null) return new String[0];
|
||||
|
||||
|
||||
+24
-22
@@ -20,32 +20,34 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.vault.cache;
|
||||
package me.lucko.luckperms.api.vault;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import me.lucko.luckperms.LPBukkitPlugin;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class ChatCache {
|
||||
private final Map<String, String> context;
|
||||
public class VaultScheduler implements Runnable {
|
||||
private final List<Runnable> tasks = new ArrayList<>();
|
||||
|
||||
@Setter
|
||||
private String prefix = null;
|
||||
|
||||
@Setter
|
||||
private String suffix = null;
|
||||
|
||||
private Map<String, String> meta = new ConcurrentHashMap<>();
|
||||
|
||||
public void invalidateCache() {
|
||||
prefix = null;
|
||||
suffix = null;
|
||||
meta.clear();
|
||||
public VaultScheduler(LPBukkitPlugin plugin) {
|
||||
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this, 1L, 1L);
|
||||
}
|
||||
|
||||
public void scheduleTask(Runnable r) {
|
||||
synchronized (tasks) {
|
||||
tasks.add(r);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
List<Runnable> toRun = new ArrayList<>();
|
||||
synchronized (tasks) {
|
||||
toRun.addAll(tasks);
|
||||
tasks.clear();
|
||||
}
|
||||
|
||||
toRun.forEach(Runnable::run);
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.vault.cache;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.lucko.luckperms.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.vault.VaultPermissionHook;
|
||||
import me.lucko.luckperms.users.User;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class VaultUser {
|
||||
private final LPBukkitPlugin plugin;
|
||||
private final VaultPermissionHook vault;
|
||||
|
||||
@Getter
|
||||
private final User user;
|
||||
|
||||
@Getter
|
||||
private final Map<Map<String, String>, ContextCache> contextData = new ConcurrentHashMap<>();
|
||||
|
||||
@Getter
|
||||
private final Map<Map<String, String>, ChatCache> chatData = new ConcurrentHashMap<>();
|
||||
|
||||
public boolean hasPermission(Map<String, String> context, String permission) {
|
||||
ContextCache cd = contextData.computeIfAbsent(context, map -> calculatePermissions(map, false));
|
||||
return cd.getPermissionValue(permission).asBoolean();
|
||||
}
|
||||
|
||||
public ChatCache processChatData(Map<String, String> context) {
|
||||
return chatData.computeIfAbsent(context, map -> calculateChat(map, false));
|
||||
}
|
||||
|
||||
public ContextCache calculatePermissions(Map<String, String> context, boolean apply) {
|
||||
Map<String, Boolean> toApply = user.exportNodes(
|
||||
new Contexts(context, vault.isIncludeGlobal(), true, true, true, true),
|
||||
Collections.emptyList(),
|
||||
true
|
||||
);
|
||||
|
||||
ContextCache existing = contextData.get(context);
|
||||
if (existing == null) {
|
||||
existing = new ContextCache(user, context, plugin, plugin.getDefaultsProvider());
|
||||
if (apply) {
|
||||
contextData.put(context, existing);
|
||||
}
|
||||
}
|
||||
|
||||
boolean different = false;
|
||||
if (toApply.size() != existing.getPermissionCache().size()) {
|
||||
different = true;
|
||||
} else {
|
||||
for (Map.Entry<String, Boolean> e : existing.getPermissionCache().entrySet()) {
|
||||
if (toApply.containsKey(e.getKey()) && toApply.get(e.getKey()) == e.getValue()) {
|
||||
continue;
|
||||
}
|
||||
different = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!different) return existing;
|
||||
|
||||
existing.getPermissionCache().clear();
|
||||
existing.invalidateCache();
|
||||
existing.getPermissionCache().putAll(toApply);
|
||||
return existing;
|
||||
}
|
||||
|
||||
public ChatCache calculateChat(Map<String, String> context, boolean apply) {
|
||||
ChatCache existing = chatData.get(context);
|
||||
if (existing == null) {
|
||||
existing = new ChatCache(context);
|
||||
if (apply) {
|
||||
chatData.put(context, existing);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> contexts = new HashMap<>(context);
|
||||
String server = contexts.get("server");
|
||||
String world = contexts.get("world");
|
||||
contexts.remove("server");
|
||||
contexts.remove("world");
|
||||
|
||||
existing.invalidateCache();
|
||||
|
||||
// Load meta
|
||||
for (Node n : user.getPermissions(true)) {
|
||||
if (!n.getValue()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!n.isMeta()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!n.shouldApplyOnServer(server, vault.isIncludeGlobal(), false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!n.shouldApplyOnWorld(world, true, false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!n.shouldApplyWithContext(contexts, false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map.Entry<String, String> meta = n.getMeta();
|
||||
existing.getMeta().put(meta.getKey(), meta.getValue());
|
||||
}
|
||||
|
||||
// Load prefixes & suffixes
|
||||
|
||||
int prefixPriority = Integer.MIN_VALUE;
|
||||
int suffixPriority = Integer.MIN_VALUE;
|
||||
|
||||
for (Node n : user.getAllNodes(null, new Contexts(context, vault.isIncludeGlobal(), true, true, true, true))) {
|
||||
if (!n.getValue()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!n.isPrefix() && !n.isSuffix()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!n.shouldApplyOnServer(server, vault.isIncludeGlobal(), false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!n.shouldApplyOnWorld(world, true, false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!n.shouldApplyWithContext(contexts, false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n.isPrefix()) {
|
||||
Map.Entry<Integer, String> value = n.getPrefix();
|
||||
if (value.getKey() > prefixPriority) {
|
||||
existing.setPrefix(value.getValue());
|
||||
prefixPriority = value.getKey();
|
||||
}
|
||||
} else {
|
||||
Map.Entry<Integer, String> value = n.getSuffix();
|
||||
if (value.getKey() > suffixPriority) {
|
||||
existing.setSuffix(value.getValue());
|
||||
suffixPriority = value.getKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
}
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.api.vault.cache;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.lucko.luckperms.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.api.vault.VaultPermissionHook;
|
||||
import me.lucko.luckperms.users.User;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class VaultUserManager {
|
||||
private final LPBukkitPlugin plugin;
|
||||
private final VaultPermissionHook vault;
|
||||
private final Map<UUID, VaultUser> userCache = new ConcurrentHashMap<>();
|
||||
|
||||
public void setupUser(User user) {
|
||||
VaultUser vaultUser = userCache.computeIfAbsent(user.getUuid(), uuid -> new VaultUser(plugin, vault, user));
|
||||
vaultUser.calculatePermissions(Collections.singletonMap("server", vault.getServer()), true);
|
||||
vaultUser.calculateChat(Collections.singletonMap("server", vault.getServer()), true);
|
||||
for (World world : plugin.getServer().getWorlds()) {
|
||||
Map<String, String> context = new HashMap<>();
|
||||
context.put("server", vault.getServer());
|
||||
context.put("world", world.getName());
|
||||
vaultUser.calculatePermissions(context, true);
|
||||
vaultUser.calculateChat(context, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearUser(UUID uuid) {
|
||||
userCache.remove(uuid);
|
||||
}
|
||||
|
||||
public boolean containsUser(UUID uuid) {
|
||||
return userCache.containsKey(uuid);
|
||||
}
|
||||
|
||||
public VaultUser getUser(UUID uuid) {
|
||||
return userCache.get(uuid);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,19 +28,24 @@ import me.lucko.luckperms.api.Tristate;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class AttachmentProcessor implements PermissionProcessor {
|
||||
|
||||
@Getter
|
||||
private final Map<String, PermissionAttachmentInfo> map;
|
||||
private final Supplier<Map<String, PermissionAttachmentInfo>> map;
|
||||
|
||||
@Override
|
||||
public Tristate hasPermission(String permission) {
|
||||
if (map.containsKey(permission)) {
|
||||
return Tristate.fromBoolean(map.get(permission).getValue());
|
||||
Map<String, PermissionAttachmentInfo> m = map.get();
|
||||
if (m == null) {
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
|
||||
if (m.containsKey(permission)) {
|
||||
return Tristate.fromBoolean(m.get(permission).getValue());
|
||||
}
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,19 +31,19 @@ import java.util.function.Supplier;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class DefaultsProcessor implements PermissionProcessor {
|
||||
private final Supplier<Boolean> isOp;
|
||||
private final boolean isOp;
|
||||
private final DefaultsProvider defaultsProvider;
|
||||
|
||||
@Override
|
||||
public Tristate hasPermission(String permission) {
|
||||
Tristate t = defaultsProvider.hasDefault(permission, isOp.get());
|
||||
Tristate t = defaultsProvider.hasDefault(permission, isOp);
|
||||
if (t != Tristate.UNDEFINED) {
|
||||
return t;
|
||||
}
|
||||
|
||||
Permission defPerm = Bukkit.getServer().getPluginManager().getPermission(permission);
|
||||
if (defPerm != null) {
|
||||
return Tristate.fromBoolean(defPerm.getDefault().getValue(isOp.get()));
|
||||
return Tristate.fromBoolean(defPerm.getDefault().getValue(isOp));
|
||||
} else {
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
|
||||
@@ -27,30 +27,33 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Injects a {@link LPPermissible} into a {@link Player}
|
||||
*/
|
||||
@UtilityClass
|
||||
public class Injector {
|
||||
private static final Map<UUID, LPPermissible> INJECTED_PERMISSIBLES = new ConcurrentHashMap<>();
|
||||
private static Field HUMAN_ENTITY_FIELD;
|
||||
|
||||
static {
|
||||
try {
|
||||
HUMAN_ENTITY_FIELD = Class.forName(getInternalClassName("entity.CraftHumanEntity")).getDeclaredField("perm");
|
||||
HUMAN_ENTITY_FIELD = Class.forName(getVersionedClassName("entity.CraftHumanEntity")).getDeclaredField("perm");
|
||||
HUMAN_ENTITY_FIELD.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean inject(CommandSender sender, PermissibleBase permissible) {
|
||||
public static boolean inject(Player player, LPPermissible permissible) {
|
||||
try {
|
||||
Field f = getPermField(sender);
|
||||
f.set(sender, permissible);
|
||||
HUMAN_ENTITY_FIELD.set(player, permissible);
|
||||
INJECTED_PERMISSIBLES.put(player.getUniqueId(), permissible);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -58,15 +61,16 @@ public class Injector {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean unInject(CommandSender sender) {
|
||||
public static boolean unInject(Player player) {
|
||||
try {
|
||||
Permissible permissible = getPermissible(sender);
|
||||
Permissible permissible = (Permissible) HUMAN_ENTITY_FIELD.get(player);
|
||||
if (permissible instanceof LPPermissible) {
|
||||
/* The player is most likely leaving. Bukkit will attempt to call #clearPermissions, so we cannot set to null.
|
||||
However, there's no need to re-inject a real PermissibleBase, so we just inject a dummy instead.
|
||||
This saves tick time, pointlessly recalculating defaults when the instance will never be used. */
|
||||
getPermField(sender).set(sender, new DummyPermissibleBase());
|
||||
HUMAN_ENTITY_FIELD.set(player, new DummyPermissibleBase());
|
||||
}
|
||||
INJECTED_PERMISSIBLES.remove(player.getUniqueId());
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -74,23 +78,11 @@ public class Injector {
|
||||
}
|
||||
}
|
||||
|
||||
private static Permissible getPermissible(CommandSender sender) {
|
||||
try {
|
||||
Field f = getPermField(sender);
|
||||
return (Permissible) f.get(sender);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
public static LPPermissible getPermissible(UUID uuid) {
|
||||
return INJECTED_PERMISSIBLES.get(uuid);
|
||||
}
|
||||
|
||||
private static Field getPermField(CommandSender sender) {
|
||||
if (sender instanceof Player) {
|
||||
return HUMAN_ENTITY_FIELD;
|
||||
}
|
||||
throw new RuntimeException("Couldn't get perm field for sender " + sender.getClass().getName());
|
||||
}
|
||||
|
||||
private static String getInternalClassName(String className) {
|
||||
private static String getVersionedClassName(String className) {
|
||||
Class server = Bukkit.getServer().getClass();
|
||||
if (!server.getSimpleName().equals("CraftServer")) {
|
||||
throw new RuntimeException("Couldn't inject into server " + server);
|
||||
|
||||
@@ -24,61 +24,60 @@ package me.lucko.luckperms.inject;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.calculators.*;
|
||||
import me.lucko.luckperms.users.User;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.*;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Modified PermissibleBase for LuckPerms
|
||||
*/
|
||||
public class LPPermissible extends PermissibleBase {
|
||||
public class LPPermissible extends PermissibleBase { // TODO autoop stuff
|
||||
|
||||
@Getter
|
||||
private final CommandSender parent;
|
||||
|
||||
private final PermissionCalculator calculator;
|
||||
private final User user;
|
||||
|
||||
@Getter
|
||||
private final Map<String, Boolean> luckPermsPermissions = new ConcurrentHashMap<>();
|
||||
private final List<PermissionAttachment> attachments = new LinkedList<>();
|
||||
private final Player parent;
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
// Attachment stuff.
|
||||
@Getter
|
||||
private final Map<String, PermissionAttachmentInfo> attachmentPermissions = new HashMap<>();
|
||||
private final List<PermissionAttachment> attachments = new LinkedList<>();
|
||||
|
||||
public LPPermissible(@NonNull CommandSender sender, LuckPermsPlugin plugin, DefaultsProvider defaultsProvider) {
|
||||
super(sender);
|
||||
this.parent = sender;
|
||||
|
||||
List<PermissionProcessor> processors = new ArrayList<>(5);
|
||||
processors.add(new MapProcessor(luckPermsPermissions));
|
||||
processors.add(new AttachmentProcessor(attachmentPermissions));
|
||||
if (plugin.getConfiguration().isApplyingWildcards()) {
|
||||
processors.add(new WildcardProcessor(luckPermsPermissions));
|
||||
}
|
||||
if (plugin.getConfiguration().isApplyingRegex()) {
|
||||
processors.add(new RegexProcessor(luckPermsPermissions));
|
||||
}
|
||||
processors.add(new DefaultsProcessor(parent::isOp, defaultsProvider));
|
||||
|
||||
calculator = new PermissionCalculator(plugin, parent.getName(), plugin.getConfiguration().isDebugPermissionChecks(), processors);
|
||||
public LPPermissible(@NonNull Player parent, User user, LPBukkitPlugin plugin) {
|
||||
super(parent);
|
||||
this.user = user;
|
||||
this.parent = parent;
|
||||
this.plugin = plugin;
|
||||
|
||||
recalculatePermissions();
|
||||
}
|
||||
|
||||
public void invalidateCache() {
|
||||
calculator.invalidateCache();
|
||||
private Contexts calculateContexts() {
|
||||
return new Contexts(
|
||||
plugin.getContextManager().giveApplicableContext(parent, new HashMap<>()),
|
||||
plugin.getConfiguration().isIncludingGlobalPerms(),
|
||||
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
|
||||
true,
|
||||
plugin.getConfiguration().isApplyingGlobalGroups(),
|
||||
plugin.getConfiguration().isApplyingGlobalWorldGroups(),
|
||||
parent.isOp()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOp() {
|
||||
return parent.isOp();
|
||||
private boolean hasData() {
|
||||
return user.getUserData() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,7 +87,7 @@ public class LPPermissible extends PermissibleBase {
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(@NonNull String name) {
|
||||
return calculator.getPermissionValue(name) != Tristate.UNDEFINED;
|
||||
return hasData() && user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(name) != Tristate.UNDEFINED;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,9 +97,11 @@ public class LPPermissible extends PermissibleBase {
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull String name) {
|
||||
Tristate ts = calculator.getPermissionValue(name);
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
return ts.asBoolean();
|
||||
if (hasData()) {
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(name);
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
return ts.asBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
return Permission.DEFAULT_PERMISSION.getValue(isOp());
|
||||
@@ -108,14 +109,32 @@ public class LPPermissible extends PermissibleBase {
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull Permission perm) {
|
||||
Tristate ts = calculator.getPermissionValue(perm.getName());
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
return ts.asBoolean();
|
||||
if (hasData()) {
|
||||
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(perm.getName());
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
return ts.asBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
return perm.getDefault().getValue(isOp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
perms.addAll(attachmentPermissions.values());
|
||||
|
||||
if (hasData()) {
|
||||
perms.addAll(
|
||||
user.getUserData().getPermissionData(calculateContexts()).getImmutableBacking().entrySet().stream()
|
||||
.map(e -> new PermissionAttachmentInfo(parent, e.getKey(), null, e.getValue()))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String name, boolean value) {
|
||||
if (!plugin.isEnabled()) {
|
||||
@@ -202,7 +221,9 @@ public class LPPermissible extends PermissibleBase {
|
||||
calculateChildPermissions(attachment.getPermissions(), false, attachment);
|
||||
}
|
||||
|
||||
invalidateCache();
|
||||
if (hasData()) {
|
||||
user.getUserData().invalidateCache();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -234,18 +255,6 @@ public class LPPermissible extends PermissibleBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
perms.addAll(attachmentPermissions.values());
|
||||
|
||||
perms.addAll(luckPermsPermissions.entrySet().stream()
|
||||
.map(e -> new PermissionAttachmentInfo(parent, e.getKey(), null, e.getValue()))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
private class RemoveAttachmentRunnable implements Runnable {
|
||||
private PermissionAttachment attachment;
|
||||
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.users;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.lucko.luckperms.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.event.events.UserPermissionRefreshEvent;
|
||||
import me.lucko.luckperms.api.implementation.internal.UserLink;
|
||||
import me.lucko.luckperms.inject.LPPermissible;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitUser extends User {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private LPPermissible permissible = null;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private Map<String, Boolean> loginPreProcess = null;
|
||||
|
||||
BukkitUser(UUID uuid, LPBukkitPlugin plugin) {
|
||||
super(uuid, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
BukkitUser(UUID uuid, String username, LPBukkitPlugin plugin) {
|
||||
super(uuid, username, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public boolean isOp() {
|
||||
return permissible != null && permissible.isOp();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public synchronized void refreshPermissions() {
|
||||
LPPermissible permissible = getPermissible();
|
||||
if (permissible == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the permissions that should be applied. This is done async, who cares about how long it takes or how often it's done.
|
||||
Map<String, Boolean> toApply = exportNodes(
|
||||
new Contexts(
|
||||
plugin.getContextManager().giveApplicableContext((Player) permissible.getParent(), new HashMap<>()),
|
||||
plugin.getConfiguration().isIncludingGlobalPerms(),
|
||||
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
|
||||
true,
|
||||
plugin.getConfiguration().isApplyingGlobalGroups(),
|
||||
plugin.getConfiguration().isApplyingGlobalWorldGroups()
|
||||
),
|
||||
Collections.emptyList(),
|
||||
true
|
||||
);
|
||||
|
||||
try {
|
||||
Map<String, Boolean> existing = permissible.getLuckPermsPermissions();
|
||||
|
||||
boolean different = false;
|
||||
if (toApply.size() != existing.size()) {
|
||||
different = true;
|
||||
} else {
|
||||
for (Map.Entry<String, Boolean> e : existing.entrySet()) {
|
||||
if (toApply.containsKey(e.getKey()) && toApply.get(e.getKey()) == e.getValue()) {
|
||||
continue;
|
||||
}
|
||||
different = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!different) return;
|
||||
|
||||
existing.clear();
|
||||
permissible.invalidateCache();
|
||||
existing.putAll(toApply);
|
||||
|
||||
if (plugin.getConfiguration().isAutoOp()) {
|
||||
boolean op = false;
|
||||
|
||||
for (Map.Entry<String, Boolean> e : toApply.entrySet()) {
|
||||
if (e.getKey().equalsIgnoreCase("luckperms.autoop") && e.getValue()) {
|
||||
op = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final boolean finalOp = op;
|
||||
if (permissible.isOp() != op) {
|
||||
final Permissible parent = permissible.getParent();
|
||||
plugin.doSync(() -> parent.setOp(finalOp));
|
||||
}
|
||||
}
|
||||
|
||||
plugin.getApiProvider().fireEventAsync(new UserPermissionRefreshEvent(new UserLink(this)));
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (plugin.getVaultHook() != null && plugin.getVaultHook().isHooked()) {
|
||||
plugin.getVaultHook().getPermissionHook().getVaultUserManager().setupUser(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.users;
|
||||
|
||||
import me.lucko.luckperms.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.api.context.ContextListener;
|
||||
import me.lucko.luckperms.inject.Injector;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BukkitUserManager extends UserManager implements ContextListener<Player> {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public BukkitUserManager(LPBukkitPlugin plugin) {
|
||||
super(plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preUnload(User user) {
|
||||
if (user instanceof BukkitUser) {
|
||||
BukkitUser u = (BukkitUser) user;
|
||||
Player player = plugin.getServer().getPlayer(plugin.getUuidCache().getExternalUUID(u.getUuid()));
|
||||
if (player != null) {
|
||||
if (u.getPermissible() != null) {
|
||||
Injector.unInject(player);
|
||||
u.setPermissible(null);
|
||||
}
|
||||
|
||||
if (plugin.getConfiguration().isAutoOp()) {
|
||||
player.setOp(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup(User user) {
|
||||
if (plugin.getServer().getPlayer(plugin.getUuidCache().getExternalUUID(user.getUuid())) == null) {
|
||||
unload(user);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public User apply(UserIdentifier id) {
|
||||
BukkitUser user = id.getUsername() == null ?
|
||||
new BukkitUser(id.getUuid(), plugin) :
|
||||
new BukkitUser(id.getUuid(), id.getUsername(), plugin);
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAllUsers() {
|
||||
// Sometimes called async, as we need to get the players on the Bukkit thread.
|
||||
plugin.doSync(() -> {
|
||||
Set<UUID> players = plugin.getServer().getOnlinePlayers().stream()
|
||||
.map(p -> plugin.getUuidCache().getUUID(p.getUniqueId()))
|
||||
.collect(Collectors.toSet());
|
||||
plugin.doAsync(() -> players.forEach(u -> plugin.getDatastore().loadUser(u, "null")));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContextChange(Player subject, Map.Entry<String, String> before, Map.Entry<String, String> current) throws Exception {
|
||||
UUID internal = plugin.getUuidCache().getUUID(subject.getUniqueId());
|
||||
|
||||
User user = get(internal);
|
||||
if (user != null) {
|
||||
plugin.doAsync(user::refreshPermissions);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user