mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-11-28 05:35:26 +01:00
Refactor caching system (WIP) - still working towards #23
This commit is contained in:
parent
e079b0f3ed
commit
83d9229295
@ -41,14 +41,18 @@ public class Contexts {
|
|||||||
* @return a context that will not apply any filters
|
* @return a context that will not apply any filters
|
||||||
*/
|
*/
|
||||||
public static Contexts allowAll() {
|
public static Contexts allowAll() {
|
||||||
return new Contexts(Collections.emptyMap(), true, true, true, true, true);
|
return new Contexts(Collections.emptyMap(), true, true, true, true, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
|
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
|
||||||
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups);
|
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Contexts(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
|
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
|
||||||
|
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Contexts(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
throw new NullPointerException("context");
|
throw new NullPointerException("context");
|
||||||
}
|
}
|
||||||
@ -59,6 +63,11 @@ public class Contexts {
|
|||||||
this.applyGroups = applyGroups;
|
this.applyGroups = applyGroups;
|
||||||
this.applyGlobalGroups = applyGlobalGroups;
|
this.applyGlobalGroups = applyGlobalGroups;
|
||||||
this.applyGlobalWorldGroups = applyGlobalWorldGroups;
|
this.applyGlobalWorldGroups = applyGlobalWorldGroups;
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Contexts(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
|
||||||
|
this(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,6 +77,11 @@ public class Contexts {
|
|||||||
*/
|
*/
|
||||||
private final Map<String, String> context;
|
private final Map<String, String> context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mode to parse defaults on Bukkit
|
||||||
|
*/
|
||||||
|
private final boolean op;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If global or non server specific nodes should be applied
|
* If global or non server specific nodes should be applied
|
||||||
*/
|
*/
|
||||||
@ -101,6 +115,14 @@ public class Contexts {
|
|||||||
return this.context;
|
return this.context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if OP defaults should be included
|
||||||
|
* @return true if op defaults should be included
|
||||||
|
*/
|
||||||
|
public boolean isOp() {
|
||||||
|
return this.op;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets if global or non server specific nodes should be applied
|
* Gets if global or non server specific nodes should be applied
|
||||||
* @return true if global or non server specific nodes should be applied
|
* @return true if global or non server specific nodes should be applied
|
||||||
@ -144,6 +166,7 @@ public class Contexts {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "Contexts(" +
|
return "Contexts(" +
|
||||||
"context=" + this.getContext() + ", " +
|
"context=" + this.getContext() + ", " +
|
||||||
|
"op=" + this.isOp() + ", " +
|
||||||
"includeGlobal=" + this.isIncludeGlobal() + ", " +
|
"includeGlobal=" + this.isIncludeGlobal() + ", " +
|
||||||
"includeGlobalWorld=" + this.isIncludeGlobalWorld() + ", " +
|
"includeGlobalWorld=" + this.isIncludeGlobalWorld() + ", " +
|
||||||
"applyGroups=" + this.isApplyGroups() + ", " +
|
"applyGroups=" + this.isApplyGroups() + ", " +
|
||||||
@ -152,4 +175,49 @@ public class Contexts {
|
|||||||
")";
|
")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ugly auto-generated lombok code
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for equality
|
||||||
|
* @param o the other
|
||||||
|
* @return true if equal
|
||||||
|
* @since 2.12
|
||||||
|
*/
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o == this) return true;
|
||||||
|
if (!(o instanceof Contexts)) return false;
|
||||||
|
final Contexts other = (Contexts) o;
|
||||||
|
final Object this$context = this.getContext();
|
||||||
|
final Object other$context = other.getContext();
|
||||||
|
if (this$context == null ? other$context != null : !this$context.equals(other$context)) return false;
|
||||||
|
if (this.isOp() != other.isOp()) return false;
|
||||||
|
if (this.isIncludeGlobal() != other.isIncludeGlobal()) return false;
|
||||||
|
if (this.isIncludeGlobalWorld() != other.isIncludeGlobalWorld()) return false;
|
||||||
|
if (this.isApplyGroups() != other.isApplyGroups()) return false;
|
||||||
|
if (this.isApplyGlobalGroups() != other.isApplyGlobalGroups()) return false;
|
||||||
|
if (this.isApplyGlobalWorldGroups() != other.isApplyGlobalWorldGroups()) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hashcode
|
||||||
|
* @return the hashcode
|
||||||
|
* @since 2.12
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
final int PRIME = 59;
|
||||||
|
int result = 1;
|
||||||
|
final Object $context = this.getContext();
|
||||||
|
result = result * PRIME + ($context == null ? 43 : $context.hashCode());
|
||||||
|
result = result * PRIME + (this.isOp() ? 79 : 97);
|
||||||
|
result = result * PRIME + (this.isIncludeGlobal() ? 79 : 97);
|
||||||
|
result = result * PRIME + (this.isIncludeGlobalWorld() ? 79 : 97);
|
||||||
|
result = result * PRIME + (this.isApplyGroups() ? 79 : 97);
|
||||||
|
result = result * PRIME + (this.isApplyGlobalGroups() ? 79 : 97);
|
||||||
|
result = result * PRIME + (this.isApplyGlobalWorldGroups() ? 79 : 97);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,53 +20,42 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package me.lucko.luckperms.api.vault.cache;
|
package me.lucko.luckperms;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.NonNull;
|
import me.lucko.luckperms.api.Contexts;
|
||||||
import me.lucko.luckperms.LuckPermsPlugin;
|
|
||||||
import me.lucko.luckperms.api.Tristate;
|
|
||||||
import me.lucko.luckperms.calculators.*;
|
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 me.lucko.luckperms.users.User;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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
|
@Override
|
||||||
private final Map<String, String> context;
|
public PermissionCalculator build(Contexts contexts, User user, Map<String, Boolean> map) {
|
||||||
|
UUID uuid = plugin.getUuidCache().getExternalUUID(user.getUuid());
|
||||||
@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;
|
|
||||||
|
|
||||||
List<PermissionProcessor> processors = new ArrayList<>(5);
|
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()) {
|
if (plugin.getConfiguration().isApplyingWildcards()) {
|
||||||
processors.add(new WildcardProcessor(permissionCache));
|
processors.add(new WildcardProcessor(map));
|
||||||
}
|
}
|
||||||
if (plugin.getConfiguration().isApplyingRegex()) {
|
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));
|
return new PermissionCalculator(plugin, user.getName(), plugin.getConfiguration().isDebugPermissionChecks(), processors);
|
||||||
calculator = 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;
|
package me.lucko.luckperms;
|
||||||
|
|
||||||
import me.lucko.luckperms.api.Contexts;
|
|
||||||
import me.lucko.luckperms.constants.Message;
|
import me.lucko.luckperms.constants.Message;
|
||||||
import me.lucko.luckperms.inject.Injector;
|
import me.lucko.luckperms.inject.Injector;
|
||||||
import me.lucko.luckperms.inject.LPPermissible;
|
import me.lucko.luckperms.inject.LPPermissible;
|
||||||
import me.lucko.luckperms.users.BukkitUser;
|
|
||||||
import me.lucko.luckperms.users.User;
|
import me.lucko.luckperms.users.User;
|
||||||
import me.lucko.luckperms.utils.AbstractListener;
|
import me.lucko.luckperms.utils.AbstractListener;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
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;
|
import java.util.UUID;
|
||||||
|
|
||||||
class BukkitListener extends AbstractListener implements Listener {
|
class BukkitListener extends AbstractListener implements Listener {
|
||||||
@ -50,6 +49,7 @@ class BukkitListener extends AbstractListener implements Listener {
|
|||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onPlayerPreLogin(AsyncPlayerPreLoginEvent e) {
|
public void onPlayerPreLogin(AsyncPlayerPreLoginEvent e) {
|
||||||
if (!plugin.getDatastore().isAcceptingLogins()) {
|
if (!plugin.getDatastore().isAcceptingLogins()) {
|
||||||
|
|
||||||
// The datastore is disabled, prevent players from joining the server
|
// The datastore is disabled, prevent players from joining the server
|
||||||
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
|
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
|
||||||
return;
|
return;
|
||||||
@ -57,38 +57,14 @@ class BukkitListener extends AbstractListener implements Listener {
|
|||||||
|
|
||||||
// Process login
|
// Process login
|
||||||
onAsyncLogin(e.getUniqueId(), e.getName());
|
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)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
public void onPlayerPreLoginMonitor(AsyncPlayerPreLoginEvent e) {
|
public void onPlayerPreLoginMonitor(AsyncPlayerPreLoginEvent e) {
|
||||||
if (plugin.getDatastore().isAcceptingLogins() && e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
|
if (plugin.getDatastore().isAcceptingLogins() && e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
|
||||||
|
|
||||||
// Login event was cancelled by another plugin
|
// Login event was cancelled by another plugin
|
||||||
final UUID internal = plugin.getUuidCache().getUUID(e.getUniqueId());
|
|
||||||
onLeave(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()));
|
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
// User wasn't loaded for whatever reason.
|
||||||
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
|
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BukkitUser u = (BukkitUser) user;
|
|
||||||
try {
|
try {
|
||||||
// Make a new permissible for the user
|
// Make a new permissible for the user
|
||||||
LPPermissible lpPermissible = new LPPermissible(player, plugin, plugin.getDefaultsProvider());
|
LPPermissible lpPermissible = new LPPermissible(player, user, plugin);
|
||||||
|
|
||||||
// Insert the pre-processed permissions into the permissible
|
|
||||||
lpPermissible.getLuckPermsPermissions().putAll(u.getLoginPreProcess());
|
|
||||||
u.setLoginPreProcess(null);
|
|
||||||
|
|
||||||
// Inject into the player
|
// Inject into the player
|
||||||
Injector.inject(player, lpPermissible);
|
Injector.inject(player, lpPermissible);
|
||||||
u.setPermissible(lpPermissible);
|
|
||||||
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
t.printStackTrace();
|
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)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
public void onPlayerLoginMonitor(PlayerLoginEvent e) {
|
public void onPlayerLoginMonitor(PlayerLoginEvent e) {
|
||||||
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
|
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
|
||||||
|
|
||||||
// The player got denied on sync login.
|
// The player got denied on sync login.
|
||||||
final UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
|
|
||||||
onLeave(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)
|
@EventHandler(priority = EventPriority.HIGHEST) // Allow other plugins to see data when this event gets called.
|
||||||
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)
|
|
||||||
public void onPlayerQuit(PlayerQuitEvent e) {
|
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);
|
plugin.getWorldCalculator().getWorldCache().remove(internal);
|
||||||
onLeave(e.getPlayer().getUniqueId());
|
|
||||||
if (plugin.getVaultHook() != null && plugin.getVaultHook().isHooked()) {
|
// Remove the custom permissible
|
||||||
plugin.getVaultHook().getPermissionHook().getVaultUserManager().clearUser(internal);
|
Injector.unInject(player);
|
||||||
|
|
||||||
|
// Handle auto op
|
||||||
|
if (plugin.getConfiguration().isAutoOp()) {
|
||||||
|
player.setOp(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call internal leave handling
|
||||||
|
onLeave(player.getUniqueId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
|
@ -23,11 +23,13 @@
|
|||||||
package me.lucko.luckperms;
|
package me.lucko.luckperms;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import me.lucko.luckperms.api.Contexts;
|
||||||
import me.lucko.luckperms.api.Logger;
|
import me.lucko.luckperms.api.Logger;
|
||||||
import me.lucko.luckperms.api.LuckPermsApi;
|
import me.lucko.luckperms.api.LuckPermsApi;
|
||||||
import me.lucko.luckperms.api.PlatformType;
|
import me.lucko.luckperms.api.PlatformType;
|
||||||
import me.lucko.luckperms.api.implementation.ApiProvider;
|
import me.lucko.luckperms.api.implementation.ApiProvider;
|
||||||
import me.lucko.luckperms.api.vault.VaultHook;
|
import me.lucko.luckperms.api.vault.VaultHook;
|
||||||
|
import me.lucko.luckperms.calculators.CalculatorFactory;
|
||||||
import me.lucko.luckperms.calculators.DefaultsProvider;
|
import me.lucko.luckperms.calculators.DefaultsProvider;
|
||||||
import me.lucko.luckperms.commands.ConsecutiveExecutor;
|
import me.lucko.luckperms.commands.ConsecutiveExecutor;
|
||||||
import me.lucko.luckperms.commands.Sender;
|
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.constants.Message;
|
||||||
import me.lucko.luckperms.contexts.ContextManager;
|
import me.lucko.luckperms.contexts.ContextManager;
|
||||||
import me.lucko.luckperms.contexts.ServerCalculator;
|
import me.lucko.luckperms.contexts.ServerCalculator;
|
||||||
import me.lucko.luckperms.contexts.WorldCalculator;
|
|
||||||
import me.lucko.luckperms.core.UuidCache;
|
import me.lucko.luckperms.core.UuidCache;
|
||||||
import me.lucko.luckperms.data.Importer;
|
import me.lucko.luckperms.data.Importer;
|
||||||
import me.lucko.luckperms.groups.GroupManager;
|
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.Datastore;
|
||||||
import me.lucko.luckperms.storage.StorageFactory;
|
import me.lucko.luckperms.storage.StorageFactory;
|
||||||
import me.lucko.luckperms.tracks.TrackManager;
|
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.LocaleManager;
|
||||||
import me.lucko.luckperms.utils.LogFactory;
|
import me.lucko.luckperms.utils.LogFactory;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.command.PluginCommand;
|
import org.bukkit.command.PluginCommand;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.permissions.Permission;
|
import org.bukkit.permissions.Permission;
|
||||||
@ -66,7 +68,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
|||||||
|
|
||||||
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
|
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
|
||||||
private LPConfiguration configuration;
|
private LPConfiguration configuration;
|
||||||
private BukkitUserManager userManager;
|
private UserManager userManager;
|
||||||
private GroupManager groupManager;
|
private GroupManager groupManager;
|
||||||
private TrackManager trackManager;
|
private TrackManager trackManager;
|
||||||
private Datastore datastore;
|
private Datastore datastore;
|
||||||
@ -79,6 +81,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
|||||||
private LocaleManager localeManager;
|
private LocaleManager localeManager;
|
||||||
private ContextManager<Player> contextManager;
|
private ContextManager<Player> contextManager;
|
||||||
private WorldCalculator worldCalculator;
|
private WorldCalculator worldCalculator;
|
||||||
|
private CalculatorFactory calculatorFactory;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
@ -117,18 +120,18 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
|||||||
|
|
||||||
getLog().info("Loading internal permission managers...");
|
getLog().info("Loading internal permission managers...");
|
||||||
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
|
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
|
||||||
userManager = new BukkitUserManager(this);
|
userManager = new UserManager(this);
|
||||||
groupManager = new GroupManager(this);
|
groupManager = new GroupManager(this);
|
||||||
trackManager = new TrackManager();
|
trackManager = new TrackManager();
|
||||||
importer = new Importer(commandManager);
|
importer = new Importer(commandManager);
|
||||||
consecutiveExecutor = new ConsecutiveExecutor(commandManager);
|
consecutiveExecutor = new ConsecutiveExecutor(commandManager);
|
||||||
|
calculatorFactory = new BukkitCalculatorFactory(this);
|
||||||
|
|
||||||
contextManager = new ContextManager<>();
|
contextManager = new ContextManager<>();
|
||||||
worldCalculator = new WorldCalculator(this);
|
worldCalculator = new WorldCalculator(this);
|
||||||
pm.registerEvents(worldCalculator, this);
|
pm.registerEvents(worldCalculator, this);
|
||||||
contextManager.registerCalculator(worldCalculator);
|
contextManager.registerCalculator(worldCalculator);
|
||||||
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
|
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
|
||||||
contextManager.registerListener(userManager);
|
|
||||||
|
|
||||||
int mins = getConfiguration().getSyncTime();
|
int mins = getConfiguration().getSyncTime();
|
||||||
if (mins > 0) {
|
if (mins > 0) {
|
||||||
@ -244,15 +247,68 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getPossiblePermissions() {
|
public Set<Contexts> getPreProcessContexts(boolean op) {
|
||||||
final List<String> perms = new ArrayList<>();
|
Set<Map<String, String>> c = new HashSet<>();
|
||||||
|
c.add(Collections.emptyMap());
|
||||||
|
c.add(Collections.singletonMap("server", getConfiguration().getServer()));
|
||||||
|
|
||||||
getServer().getPluginManager().getPermissions().forEach(p -> {
|
// Pre process all worlds
|
||||||
perms.add(p.getName());
|
c.addAll(getServer().getWorlds().stream()
|
||||||
p.getChildren().keySet().forEach(perms::add);
|
.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
|
@Override
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package me.lucko.luckperms.contexts;
|
package me.lucko.luckperms;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
@ -25,8 +25,7 @@ package me.lucko.luckperms.api.vault;
|
|||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import me.lucko.luckperms.api.Contexts;
|
import me.lucko.luckperms.api.Contexts;
|
||||||
import me.lucko.luckperms.api.Node;
|
import me.lucko.luckperms.api.Node;
|
||||||
import me.lucko.luckperms.api.vault.cache.ChatCache;
|
import me.lucko.luckperms.caching.MetaData;
|
||||||
import me.lucko.luckperms.api.vault.cache.VaultUser;
|
|
||||||
import me.lucko.luckperms.core.PermissionHolder;
|
import me.lucko.luckperms.core.PermissionHolder;
|
||||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||||
@ -74,14 +73,14 @@ public class VaultChatHook extends Chat {
|
|||||||
return perms.isEnabled();
|
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;
|
String finalWorld = perms.isIgnoreWorld() ? null : world;
|
||||||
if (holder == null) return;
|
if (holder == null) return;
|
||||||
if (node.equals("")) return;
|
if (node.equals("")) return;
|
||||||
|
|
||||||
perms.log("Setting meta: '" + node + "' for " + holder.getObjectName() + " on world " + world + ", server " + perms.getServer());
|
perms.log("Setting meta: '" + node + "' for " + holder.getObjectName() + " on world " + world + ", server " + perms.getServer());
|
||||||
|
|
||||||
perms.scheduleTask(() -> {
|
perms.getScheduler().scheduleTask(() -> {
|
||||||
String k = escapeCharacters(node);
|
String k = escapeCharacters(node);
|
||||||
String v = escapeCharacters(value);
|
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.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.Builder node = new me.lucko.luckperms.core.Node.Builder(prefix ? "prefix" : "suffix" + ".1000." + escapeCharacters(value));
|
||||||
node.setValue(true);
|
node.setValue(true);
|
||||||
if (!perms.getServer().equalsIgnoreCase("global")) {
|
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) {
|
private String getUserMeta(User user, String world, String node, String defaultValue) {
|
||||||
world = perms.isIgnoreWorld() ? null : world;
|
|
||||||
if (user == null) return defaultValue;
|
if (user == null) return defaultValue;
|
||||||
|
world = perms.isIgnoreWorld() ? null : world;
|
||||||
node = escapeCharacters(node);
|
node = escapeCharacters(node);
|
||||||
|
|
||||||
perms.log("Getting meta: '" + node + "' for user " + user.getName() + " on world " + world + ", server " + perms.getServer());
|
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;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
VaultUser vaultUser = perms.getVaultUserManager().getUser(user.getUuid());
|
return unescapeCharacters(user.getUserData().getMetaData(perms.createContext(perms.getServer(), world)).getMeta().getOrDefault(node, defaultValue));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getUserChatMeta(boolean prefix, User user, String world) {
|
private String getUserChatMeta(boolean prefix, User user, String world) {
|
||||||
world = perms.isIgnoreWorld() ? null : world;
|
|
||||||
if (user == null) return "";
|
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());
|
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 "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
VaultUser vaultUser = perms.getVaultUserManager().getUser(user.getUuid());
|
MetaData data = user.getUserData().getMetaData(perms.createContext(perms.getServer(), world));
|
||||||
Map<String, String> context = new HashMap<>();
|
String v = prefix ? data.getPrefix() : data.getSuffix();
|
||||||
context.put("server", perms.getServer());
|
return v == null ? "" : unescapeCharacters(v);
|
||||||
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()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getGroupMeta(Group group, String world, String node, String defaultValue) {
|
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) {
|
public void setPlayerInfoInteger(String world, @NonNull String player, @NonNull String node, int value) {
|
||||||
final User user = perms.getPlugin().getUserManager().get(player);
|
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) {
|
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) {
|
public void setGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int value) {
|
||||||
final Group g = perms.getPlugin().getGroupManager().get(group);
|
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) {
|
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) {
|
public void setPlayerInfoDouble(String world, @NonNull String player, @NonNull String node, double value) {
|
||||||
final User user = perms.getPlugin().getUserManager().get(player);
|
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) {
|
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) {
|
public void setGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double value) {
|
||||||
final Group g = perms.getPlugin().getGroupManager().get(group);
|
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) {
|
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) {
|
public void setPlayerInfoBoolean(String world, @NonNull String player, @NonNull String node, boolean value) {
|
||||||
final User user = perms.getPlugin().getUserManager().get(player);
|
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) {
|
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) {
|
public void setGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean value) {
|
||||||
final Group g = perms.getPlugin().getGroupManager().get(group);
|
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) {
|
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) {
|
public void setPlayerInfoString(String world, @NonNull String player, @NonNull String node, String value) {
|
||||||
final User user = perms.getPlugin().getUserManager().get(player);
|
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) {
|
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) {
|
public void setGroupInfoString(String world, @NonNull String group, @NonNull String node, String value) {
|
||||||
final Group g = perms.getPlugin().getGroupManager().get(group);
|
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.LPBukkitPlugin;
|
||||||
import me.lucko.luckperms.api.Contexts;
|
import me.lucko.luckperms.api.Contexts;
|
||||||
import me.lucko.luckperms.api.Node;
|
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.core.PermissionHolder;
|
||||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||||
@ -37,21 +35,22 @@ import me.lucko.luckperms.groups.Group;
|
|||||||
import me.lucko.luckperms.users.User;
|
import me.lucko.luckperms.users.User;
|
||||||
import net.milkbowl.vault.permission.Permission;
|
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
|
* The LuckPerms Vault Permission implementation
|
||||||
* Most lookups are cached.
|
* Most lookups are cached.
|
||||||
*/
|
*/
|
||||||
public class VaultPermissionHook extends Permission implements Runnable {
|
public class VaultPermissionHook extends Permission {
|
||||||
private final List<Runnable> tasks = new ArrayList<>();
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private LPBukkitPlugin plugin;
|
private LPBukkitPlugin plugin;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private VaultUserManager vaultUserManager;
|
private VaultScheduler scheduler;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@ -66,8 +65,7 @@ public class VaultPermissionHook extends Permission implements Runnable {
|
|||||||
private boolean ignoreWorld = false;
|
private boolean ignoreWorld = false;
|
||||||
|
|
||||||
public void setup() {
|
public void setup() {
|
||||||
vaultUserManager = new VaultUserManager(plugin, this);
|
scheduler = new VaultScheduler(plugin);
|
||||||
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this, 1L, 1L);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(String s) {
|
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
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "LuckPerms";
|
return "LuckPerms";
|
||||||
@ -108,133 +89,149 @@ public class VaultPermissionHook extends Permission implements Runnable {
|
|||||||
return true;
|
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<>();
|
Map<String, String> context = new HashMap<>();
|
||||||
if (world != null && !world.equals("")) {
|
if (world != null && !world.equals("")) {
|
||||||
context.put("world", world);
|
context.put("world", world);
|
||||||
}
|
}
|
||||||
context.put("server", server);
|
context.put("server", server);
|
||||||
|
return new Contexts(context, isIncludeGlobal(), true, true, true, true);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean playerHas(String world, @NonNull String player, @NonNull String permission) {
|
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);
|
log("Checking if player " + player + " has permission: " + permission + " on world " + world + ", server " + server);
|
||||||
|
|
||||||
User user = plugin.getUserManager().get(player);
|
User user = plugin.getUserManager().get(player);
|
||||||
if (user == null) return false;
|
if (user == null) return false;
|
||||||
|
|
||||||
if (!vaultUserManager.containsUser(user.getUuid())) {
|
if (user.getUserData() == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
VaultUser vaultUser = vaultUserManager.getUser(user.getUuid());
|
// Effectively fallback to the standard Bukkit #hasPermission check.
|
||||||
Map<String, String> context = new HashMap<>();
|
return user.getUserData().getPermissionData(createContext(server, world)).getPermissionValue(permission).asBoolean();
|
||||||
context.put("server", server);
|
|
||||||
if (world != null) {
|
|
||||||
context.put("world", world);
|
|
||||||
}
|
|
||||||
|
|
||||||
return vaultUser.hasPermission(context, permission);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean playerAdd(String world, @NonNull String player, @NonNull String permission) {
|
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);
|
log("Adding permission to player " + player + ": '" + permission + "' on world " + finalWorld + ", server " + server);
|
||||||
|
|
||||||
final User user = plugin.getUserManager().get(player);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean playerRemove(String world, @NonNull String player, @NonNull String permission) {
|
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);
|
log("Removing permission from player " + player + ": '" + permission + "' on world " + finalWorld + ", server " + server);
|
||||||
|
|
||||||
final User user = plugin.getUserManager().get(player);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean groupHas(String world, @NonNull String groupName, @NonNull String permission) {
|
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);
|
log("Checking if group " + groupName + " has permission: " + permission + " on world " + world + ", server " + server);
|
||||||
|
|
||||||
final Group group = plugin.getGroupManager().get(groupName);
|
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
|
@Override
|
||||||
public boolean groupAdd(String world, @NonNull String groupName, @NonNull String permission) {
|
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);
|
log("Adding permission to group " + groupName + ": '" + permission + "' on world " + finalWorld + ", server " + server);
|
||||||
|
|
||||||
final Group group = plugin.getGroupManager().get(groupName);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean groupRemove(String world, @NonNull String groupName, @NonNull String permission) {
|
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);
|
log("Removing permission from group " + groupName + ": '" + permission + "' on world " + finalWorld + ", server " + server);
|
||||||
|
|
||||||
final Group group = plugin.getGroupManager().get(groupName);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean playerInGroup(String world, @NonNull String player, @NonNull String group) {
|
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);
|
log("Checking if player " + player + " is in group: " + group + " on world " + finalWorld + ", server " + server);
|
||||||
|
|
||||||
final User user = plugin.getUserManager().get(player);
|
final User user = plugin.getUserManager().get(player);
|
||||||
if (user == null) return false;
|
if (user == null) return false;
|
||||||
|
|
||||||
@ -249,15 +246,16 @@ public class VaultPermissionHook extends Permission implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean playerAddGroup(String world, @NonNull String player, @NonNull String groupName) {
|
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);
|
log("Adding player " + player + " to group: '" + groupName + "' on world " + finalWorld + ", server " + server);
|
||||||
|
|
||||||
final User user = plugin.getUserManager().get(player);
|
final User user = plugin.getUserManager().get(player);
|
||||||
if (user == null) return false;
|
if (user == null) return false;
|
||||||
|
|
||||||
final Group group = plugin.getGroupManager().get(groupName);
|
final Group group = plugin.getGroupManager().get(groupName);
|
||||||
if (group == null) return false;
|
if (group == null) return false;
|
||||||
|
|
||||||
scheduleTask(() -> {
|
scheduler.scheduleTask(() -> {
|
||||||
try {
|
try {
|
||||||
if (finalWorld != null && !finalWorld.equals("")) {
|
if (finalWorld != null && !finalWorld.equals("")) {
|
||||||
user.addGroup(group, server, finalWorld);
|
user.addGroup(group, server, finalWorld);
|
||||||
@ -272,15 +270,16 @@ public class VaultPermissionHook extends Permission implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean playerRemoveGroup(String world, @NonNull String player, @NonNull String groupName) {
|
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);
|
log("Removing player " + player + " from group: '" + groupName + "' on world " + finalWorld + ", server " + server);
|
||||||
|
|
||||||
final User user = plugin.getUserManager().get(player);
|
final User user = plugin.getUserManager().get(player);
|
||||||
if (user == null) return false;
|
if (user == null) return false;
|
||||||
|
|
||||||
final Group group = plugin.getGroupManager().get(groupName);
|
final Group group = plugin.getGroupManager().get(groupName);
|
||||||
if (group == null) return false;
|
if (group == null) return false;
|
||||||
|
|
||||||
scheduleTask(() -> {
|
scheduler.scheduleTask(() -> {
|
||||||
try {
|
try {
|
||||||
if (finalWorld != null && !finalWorld.equals("")) {
|
if (finalWorld != null && !finalWorld.equals("")) {
|
||||||
user.removeGroup(group, server, finalWorld);
|
user.removeGroup(group, server, finalWorld);
|
||||||
@ -295,8 +294,9 @@ public class VaultPermissionHook extends Permission implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getPlayerGroups(String world, @NonNull String player) {
|
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);
|
log("Getting groups of player: " + player + ", on world " + finalWorld + ", server " + server);
|
||||||
|
|
||||||
User user = plugin.getUserManager().get(player);
|
User user = plugin.getUserManager().get(player);
|
||||||
if (user == null) return new String[0];
|
if (user == null) return new String[0];
|
||||||
|
|
||||||
|
@ -20,26 +20,34 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package me.lucko.luckperms.contexts;
|
package me.lucko.luckperms.api.vault;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import me.lucko.luckperms.LPBukkitPlugin;
|
||||||
import me.lucko.luckperms.api.sponge.LuckPermsUserSubject;
|
|
||||||
import me.lucko.luckperms.api.sponge.collections.UserCollection;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
public class VaultScheduler implements Runnable {
|
||||||
public class ContextUpdateTask implements Runnable {
|
private final List<Runnable> tasks = new ArrayList<>();
|
||||||
private final UserCollection userCollection;
|
|
||||||
|
|
||||||
@Override
|
public VaultScheduler(LPBukkitPlugin plugin) {
|
||||||
public void run() {
|
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this, 1L, 1L);
|
||||||
for (LuckPermsUserSubject subject : userCollection.getUsers().values()) {
|
}
|
||||||
Set<Map<String, String>> contexts = new HashSet<>(subject.getContextData().keySet());
|
|
||||||
contexts.forEach(map -> subject.calculatePermissions(map, true));
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 org.bukkit.permissions.PermissionAttachmentInfo;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class AttachmentProcessor implements PermissionProcessor {
|
public class AttachmentProcessor implements PermissionProcessor {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final Map<String, PermissionAttachmentInfo> map;
|
private final Supplier<Map<String, PermissionAttachmentInfo>> map;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Tristate hasPermission(String permission) {
|
public Tristate hasPermission(String permission) {
|
||||||
if (map.containsKey(permission)) {
|
Map<String, PermissionAttachmentInfo> m = map.get();
|
||||||
return Tristate.fromBoolean(map.get(permission).getValue());
|
if (m == null) {
|
||||||
|
return Tristate.UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m.containsKey(permission)) {
|
||||||
|
return Tristate.fromBoolean(m.get(permission).getValue());
|
||||||
|
}
|
||||||
return Tristate.UNDEFINED;
|
return Tristate.UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,19 +31,19 @@ import java.util.function.Supplier;
|
|||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class DefaultsProcessor implements PermissionProcessor {
|
public class DefaultsProcessor implements PermissionProcessor {
|
||||||
private final Supplier<Boolean> isOp;
|
private final boolean isOp;
|
||||||
private final DefaultsProvider defaultsProvider;
|
private final DefaultsProvider defaultsProvider;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Tristate hasPermission(String permission) {
|
public Tristate hasPermission(String permission) {
|
||||||
Tristate t = defaultsProvider.hasDefault(permission, isOp.get());
|
Tristate t = defaultsProvider.hasDefault(permission, isOp);
|
||||||
if (t != Tristate.UNDEFINED) {
|
if (t != Tristate.UNDEFINED) {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
Permission defPerm = Bukkit.getServer().getPluginManager().getPermission(permission);
|
Permission defPerm = Bukkit.getServer().getPluginManager().getPermission(permission);
|
||||||
if (defPerm != null) {
|
if (defPerm != null) {
|
||||||
return Tristate.fromBoolean(defPerm.getDefault().getValue(isOp.get()));
|
return Tristate.fromBoolean(defPerm.getDefault().getValue(isOp));
|
||||||
} else {
|
} else {
|
||||||
return Tristate.UNDEFINED;
|
return Tristate.UNDEFINED;
|
||||||
}
|
}
|
||||||
|
@ -27,30 +27,33 @@ import org.bukkit.Bukkit;
|
|||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.permissions.Permissible;
|
import org.bukkit.permissions.Permissible;
|
||||||
import org.bukkit.permissions.PermissibleBase;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
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}
|
* Injects a {@link LPPermissible} into a {@link Player}
|
||||||
*/
|
*/
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class Injector {
|
public class Injector {
|
||||||
|
private static final Map<UUID, LPPermissible> INJECTED_PERMISSIBLES = new ConcurrentHashMap<>();
|
||||||
private static Field HUMAN_ENTITY_FIELD;
|
private static Field HUMAN_ENTITY_FIELD;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
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);
|
HUMAN_ENTITY_FIELD.setAccessible(true);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean inject(CommandSender sender, PermissibleBase permissible) {
|
public static boolean inject(Player player, LPPermissible permissible) {
|
||||||
try {
|
try {
|
||||||
Field f = getPermField(sender);
|
HUMAN_ENTITY_FIELD.set(player, permissible);
|
||||||
f.set(sender, permissible);
|
INJECTED_PERMISSIBLES.put(player.getUniqueId(), permissible);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -58,15 +61,16 @@ public class Injector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean unInject(CommandSender sender) {
|
public static boolean unInject(Player player) {
|
||||||
try {
|
try {
|
||||||
Permissible permissible = getPermissible(sender);
|
Permissible permissible = (Permissible) HUMAN_ENTITY_FIELD.get(player);
|
||||||
if (permissible instanceof LPPermissible) {
|
if (permissible instanceof LPPermissible) {
|
||||||
/* The player is most likely leaving. Bukkit will attempt to call #clearPermissions, so we cannot set to null.
|
/* 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.
|
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. */
|
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;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -74,23 +78,11 @@ public class Injector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Permissible getPermissible(CommandSender sender) {
|
public static LPPermissible getPermissible(UUID uuid) {
|
||||||
try {
|
return INJECTED_PERMISSIBLES.get(uuid);
|
||||||
Field f = getPermField(sender);
|
|
||||||
return (Permissible) f.get(sender);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Field getPermField(CommandSender sender) {
|
private static String getVersionedClassName(String className) {
|
||||||
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) {
|
|
||||||
Class server = Bukkit.getServer().getClass();
|
Class server = Bukkit.getServer().getClass();
|
||||||
if (!server.getSimpleName().equals("CraftServer")) {
|
if (!server.getSimpleName().equals("CraftServer")) {
|
||||||
throw new RuntimeException("Couldn't inject into server " + server);
|
throw new RuntimeException("Couldn't inject into server " + server);
|
||||||
|
@ -24,61 +24,60 @@ package me.lucko.luckperms.inject;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
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.api.Tristate;
|
||||||
import me.lucko.luckperms.calculators.*;
|
import me.lucko.luckperms.users.User;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.permissions.*;
|
import org.bukkit.permissions.*;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modified PermissibleBase for LuckPerms
|
* Modified PermissibleBase for LuckPerms
|
||||||
*/
|
*/
|
||||||
public class LPPermissible extends PermissibleBase {
|
public class LPPermissible extends PermissibleBase { // TODO autoop stuff
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final CommandSender parent;
|
private final User user;
|
||||||
|
|
||||||
private final PermissionCalculator calculator;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final Map<String, Boolean> luckPermsPermissions = new ConcurrentHashMap<>();
|
private final Player parent;
|
||||||
private final List<PermissionAttachment> attachments = new LinkedList<>();
|
|
||||||
|
private final LPBukkitPlugin plugin;
|
||||||
|
|
||||||
|
// Attachment stuff.
|
||||||
|
@Getter
|
||||||
private final Map<String, PermissionAttachmentInfo> attachmentPermissions = new HashMap<>();
|
private final Map<String, PermissionAttachmentInfo> attachmentPermissions = new HashMap<>();
|
||||||
|
private final List<PermissionAttachment> attachments = new LinkedList<>();
|
||||||
|
|
||||||
public LPPermissible(@NonNull CommandSender sender, LuckPermsPlugin plugin, DefaultsProvider defaultsProvider) {
|
public LPPermissible(@NonNull Player parent, User user, LPBukkitPlugin plugin) {
|
||||||
super(sender);
|
super(parent);
|
||||||
this.parent = sender;
|
this.user = user;
|
||||||
|
this.parent = parent;
|
||||||
List<PermissionProcessor> processors = new ArrayList<>(5);
|
this.plugin = plugin;
|
||||||
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);
|
|
||||||
|
|
||||||
recalculatePermissions();
|
recalculatePermissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void invalidateCache() {
|
private Contexts calculateContexts() {
|
||||||
calculator.invalidateCache();
|
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
|
private boolean hasData() {
|
||||||
public boolean isOp() {
|
return user.getUserData() != null;
|
||||||
return parent.isOp();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -88,7 +87,7 @@ public class LPPermissible extends PermissibleBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPermissionSet(@NonNull String name) {
|
public boolean isPermissionSet(@NonNull String name) {
|
||||||
return calculator.getPermissionValue(name) != Tristate.UNDEFINED;
|
return hasData() && user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(name) != Tristate.UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -98,9 +97,11 @@ public class LPPermissible extends PermissibleBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(@NonNull String name) {
|
public boolean hasPermission(@NonNull String name) {
|
||||||
Tristate ts = calculator.getPermissionValue(name);
|
if (hasData()) {
|
||||||
if (ts != Tristate.UNDEFINED) {
|
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(name);
|
||||||
return ts.asBoolean();
|
if (ts != Tristate.UNDEFINED) {
|
||||||
|
return ts.asBoolean();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Permission.DEFAULT_PERMISSION.getValue(isOp());
|
return Permission.DEFAULT_PERMISSION.getValue(isOp());
|
||||||
@ -108,14 +109,32 @@ public class LPPermissible extends PermissibleBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(@NonNull Permission perm) {
|
public boolean hasPermission(@NonNull Permission perm) {
|
||||||
Tristate ts = calculator.getPermissionValue(perm.getName());
|
if (hasData()) {
|
||||||
if (ts != Tristate.UNDEFINED) {
|
Tristate ts = user.getUserData().getPermissionData(calculateContexts()).getPermissionValue(perm.getName());
|
||||||
return ts.asBoolean();
|
if (ts != Tristate.UNDEFINED) {
|
||||||
|
return ts.asBoolean();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return perm.getDefault().getValue(isOp());
|
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
|
@Override
|
||||||
public PermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String name, boolean value) {
|
public PermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String name, boolean value) {
|
||||||
if (!plugin.isEnabled()) {
|
if (!plugin.isEnabled()) {
|
||||||
@ -202,7 +221,9 @@ public class LPPermissible extends PermissibleBase {
|
|||||||
calculateChildPermissions(attachment.getPermissions(), false, attachment);
|
calculateChildPermissions(attachment.getPermissions(), false, attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidateCache();
|
if (hasData()) {
|
||||||
|
user.getUserData().invalidateCache();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 class RemoveAttachmentRunnable implements Runnable {
|
||||||
private PermissionAttachment attachment;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,7 +20,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package me.lucko.luckperms.contexts;
|
package me.lucko.luckperms;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import me.lucko.luckperms.api.context.ContextCalculator;
|
import me.lucko.luckperms.api.context.ContextCalculator;
|
@ -22,39 +22,30 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms;
|
package me.lucko.luckperms;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.AllArgsConstructor;
|
||||||
|
import me.lucko.luckperms.api.Contexts;
|
||||||
import me.lucko.luckperms.calculators.*;
|
import me.lucko.luckperms.calculators.*;
|
||||||
|
import me.lucko.luckperms.users.User;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
public class BungeePlayerCache {
|
@AllArgsConstructor
|
||||||
|
public class BungeeCalculatorFactory implements CalculatorFactory {
|
||||||
|
private final LPBungeePlugin plugin;
|
||||||
|
|
||||||
private final PermissionCalculator calculator;
|
@Override
|
||||||
|
public PermissionCalculator build(Contexts contexts, User user, Map<String, Boolean> map) {
|
||||||
@Getter
|
|
||||||
private final Map<String, Boolean> permissions = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
public BungeePlayerCache(LuckPermsPlugin plugin, String name) {
|
|
||||||
List<PermissionProcessor> processors = new ArrayList<>(3);
|
List<PermissionProcessor> processors = new ArrayList<>(3);
|
||||||
processors.add(new MapProcessor(permissions));
|
processors.add(new MapProcessor(map));
|
||||||
if (plugin.getConfiguration().isApplyingWildcards()) {
|
if (plugin.getConfiguration().isApplyingWildcards()) {
|
||||||
processors.add(new WildcardProcessor(permissions));
|
processors.add(new WildcardProcessor(map));
|
||||||
}
|
}
|
||||||
if (plugin.getConfiguration().isApplyingRegex()) {
|
if (plugin.getConfiguration().isApplyingRegex()) {
|
||||||
processors.add(new RegexProcessor(permissions));
|
processors.add(new RegexProcessor(map));
|
||||||
}
|
}
|
||||||
|
|
||||||
calculator = new PermissionCalculator(plugin, name, plugin.getConfiguration().isDebugPermissionChecks(), processors);
|
return new PermissionCalculator(plugin, user.getName(), plugin.getConfiguration().isDebugPermissionChecks(), processors);
|
||||||
}
|
|
||||||
|
|
||||||
public void invalidateCache() {
|
|
||||||
calculator.invalidateCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getPermissionValue(String permission) {
|
|
||||||
return calculator.getPermissionValue(permission).asBoolean();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms;
|
package me.lucko.luckperms;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.api.Contexts;
|
||||||
|
import me.lucko.luckperms.api.event.events.UserFirstLoginEvent;
|
||||||
import me.lucko.luckperms.constants.Message;
|
import me.lucko.luckperms.constants.Message;
|
||||||
import me.lucko.luckperms.core.UuidCache;
|
import me.lucko.luckperms.core.UuidCache;
|
||||||
import me.lucko.luckperms.users.User;
|
import me.lucko.luckperms.users.User;
|
||||||
@ -36,6 +38,7 @@ import net.md_5.bungee.api.event.PostLoginEvent;
|
|||||||
import net.md_5.bungee.api.plugin.Listener;
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
import net.md_5.bungee.event.EventHandler;
|
import net.md_5.bungee.event.EventHandler;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@ -58,12 +61,26 @@ public class BungeeListener extends AbstractListener implements Listener {
|
|||||||
|
|
||||||
final ProxiedPlayer player = ((ProxiedPlayer) e.getSender());
|
final ProxiedPlayer player = ((ProxiedPlayer) e.getSender());
|
||||||
|
|
||||||
BungeePlayerCache playerCache = plugin.getPlayerCache().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||||
if (playerCache == null) {
|
if (user == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.setHasPermission(playerCache.getPermissionValue(e.getPermission()));
|
if (user.getUserData() == null) {
|
||||||
|
plugin.getLog().warn("Player " + player.getName() + " does not have any user data setup.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Contexts contexts = new Contexts(
|
||||||
|
plugin.getContextManager().giveApplicableContext(player, new HashMap<>()),
|
||||||
|
plugin.getConfiguration().isIncludingGlobalPerms(),
|
||||||
|
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
|
||||||
|
true,
|
||||||
|
plugin.getConfiguration().isApplyingGlobalGroups(),
|
||||||
|
plugin.getConfiguration().isApplyingGlobalWorldGroups()
|
||||||
|
);
|
||||||
|
|
||||||
|
e.setHasPermission(user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission()).asBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@ -83,10 +100,16 @@ public class BungeeListener extends AbstractListener implements Listener {
|
|||||||
cache.addToCache(c.getUniqueId(), uuid);
|
cache.addToCache(c.getUniqueId(), uuid);
|
||||||
} else {
|
} else {
|
||||||
// No previous data for this player
|
// No previous data for this player
|
||||||
|
plugin.getApiProvider().fireEventAsync(new UserFirstLoginEvent(c.getUniqueId(), c.getName()));
|
||||||
cache.addToCache(c.getUniqueId(), c.getUniqueId());
|
cache.addToCache(c.getUniqueId(), c.getUniqueId());
|
||||||
plugin.getDatastore().saveUUIDData(c.getName(), c.getUniqueId());
|
plugin.getDatastore().saveUUIDData(c.getName(), c.getUniqueId());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
UUID uuid = plugin.getDatastore().getUUID(c.getName());
|
||||||
|
if (uuid == null) {
|
||||||
|
plugin.getApiProvider().fireEventAsync(new UserFirstLoginEvent(c.getUniqueId(), c.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
// Online mode, no cache needed. This is just for name -> uuid lookup.
|
// Online mode, no cache needed. This is just for name -> uuid lookup.
|
||||||
plugin.getDatastore().saveUUIDData(c.getName(), c.getUniqueId());
|
plugin.getDatastore().saveUUIDData(c.getName(), c.getUniqueId());
|
||||||
}
|
}
|
||||||
@ -94,6 +117,13 @@ public class BungeeListener extends AbstractListener implements Listener {
|
|||||||
// We have to make a new user on this thread whilst the connection is being held, or we get concurrency issues as the Bukkit server
|
// We have to make a new user on this thread whilst the connection is being held, or we get concurrency issues as the Bukkit server
|
||||||
// and the BungeeCord server try to make a new user at the same time.
|
// and the BungeeCord server try to make a new user at the same time.
|
||||||
plugin.getDatastore().loadUser(cache.getUUID(c.getUniqueId()), c.getName());
|
plugin.getDatastore().loadUser(cache.getUUID(c.getUniqueId()), c.getName());
|
||||||
|
User user = plugin.getUserManager().get(cache.getUUID(c.getUniqueId()));
|
||||||
|
if (user == null) {
|
||||||
|
plugin.getLog().warn("Failed to load user: " + c.getName());
|
||||||
|
} else {
|
||||||
|
user.setupData(false); // Pretty nasty calculation call. Sets up the caching system so data is ready when the user joins.
|
||||||
|
}
|
||||||
|
|
||||||
final long time = System.currentTimeMillis() - startTime;
|
final long time = System.currentTimeMillis() - startTime;
|
||||||
if (time >= 1000) {
|
if (time >= 1000) {
|
||||||
plugin.getLog().warn("Processing login for " + c.getName() + " took " + time + "ms.");
|
plugin.getLog().warn("Processing login for " + c.getName() + " took " + time + "ms.");
|
||||||
@ -105,20 +135,15 @@ public class BungeeListener extends AbstractListener implements Listener {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerPostLogin(PostLoginEvent e) {
|
public void onPlayerPostLogin(PostLoginEvent e) {
|
||||||
final ProxiedPlayer player = e.getPlayer();
|
final ProxiedPlayer player = e.getPlayer();
|
||||||
final UUID internal = plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId());
|
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
|
||||||
final User user = plugin.getUserManager().get(internal);
|
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
plugin.getProxy().getScheduler().schedule(plugin, () -> player.sendMessage(WARN_MESSAGE), 3, TimeUnit.SECONDS);
|
plugin.getProxy().getScheduler().schedule(plugin, () -> player.sendMessage(WARN_MESSAGE), 3, TimeUnit.SECONDS);
|
||||||
} else {
|
|
||||||
plugin.getPlayerCache().put(internal, new BungeePlayerCache(plugin, e.getPlayer().getName()));
|
|
||||||
user.refreshPermissions();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerQuit(PlayerDisconnectEvent e) {
|
public void onPlayerQuit(PlayerDisconnectEvent e) {
|
||||||
plugin.getPlayerCache().remove(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
|
|
||||||
onLeave(e.getPlayer().getUniqueId());
|
onLeave(e.getPlayer().getUniqueId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,16 +23,17 @@
|
|||||||
package me.lucko.luckperms;
|
package me.lucko.luckperms;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import me.lucko.luckperms.api.Contexts;
|
||||||
import me.lucko.luckperms.api.Logger;
|
import me.lucko.luckperms.api.Logger;
|
||||||
import me.lucko.luckperms.api.PlatformType;
|
import me.lucko.luckperms.api.PlatformType;
|
||||||
import me.lucko.luckperms.api.implementation.ApiProvider;
|
import me.lucko.luckperms.api.implementation.ApiProvider;
|
||||||
|
import me.lucko.luckperms.calculators.CalculatorFactory;
|
||||||
import me.lucko.luckperms.commands.CommandManager;
|
import me.lucko.luckperms.commands.CommandManager;
|
||||||
import me.lucko.luckperms.commands.ConsecutiveExecutor;
|
import me.lucko.luckperms.commands.ConsecutiveExecutor;
|
||||||
import me.lucko.luckperms.commands.Sender;
|
import me.lucko.luckperms.commands.Sender;
|
||||||
import me.lucko.luckperms.config.LPConfiguration;
|
import me.lucko.luckperms.config.LPConfiguration;
|
||||||
import me.lucko.luckperms.constants.Message;
|
import me.lucko.luckperms.constants.Message;
|
||||||
import me.lucko.luckperms.constants.Permission;
|
import me.lucko.luckperms.constants.Permission;
|
||||||
import me.lucko.luckperms.contexts.BackendServerCalculator;
|
|
||||||
import me.lucko.luckperms.contexts.ContextManager;
|
import me.lucko.luckperms.contexts.ContextManager;
|
||||||
import me.lucko.luckperms.contexts.ServerCalculator;
|
import me.lucko.luckperms.contexts.ServerCalculator;
|
||||||
import me.lucko.luckperms.core.UuidCache;
|
import me.lucko.luckperms.core.UuidCache;
|
||||||
@ -43,9 +44,10 @@ import me.lucko.luckperms.runnables.UpdateTask;
|
|||||||
import me.lucko.luckperms.storage.Datastore;
|
import me.lucko.luckperms.storage.Datastore;
|
||||||
import me.lucko.luckperms.storage.StorageFactory;
|
import me.lucko.luckperms.storage.StorageFactory;
|
||||||
import me.lucko.luckperms.tracks.TrackManager;
|
import me.lucko.luckperms.tracks.TrackManager;
|
||||||
import me.lucko.luckperms.users.BungeeUserManager;
|
import me.lucko.luckperms.users.UserManager;
|
||||||
import me.lucko.luckperms.utils.LocaleManager;
|
import me.lucko.luckperms.utils.LocaleManager;
|
||||||
import me.lucko.luckperms.utils.LogFactory;
|
import me.lucko.luckperms.utils.LogFactory;
|
||||||
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
@ -57,10 +59,9 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||||
private final Map<UUID, BungeePlayerCache> playerCache = new ConcurrentHashMap<>();
|
|
||||||
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
|
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
|
||||||
private LPConfiguration configuration;
|
private LPConfiguration configuration;
|
||||||
private BungeeUserManager userManager;
|
private UserManager userManager;
|
||||||
private GroupManager groupManager;
|
private GroupManager groupManager;
|
||||||
private TrackManager trackManager;
|
private TrackManager trackManager;
|
||||||
private Datastore datastore;
|
private Datastore datastore;
|
||||||
@ -71,6 +72,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
|||||||
private ConsecutiveExecutor consecutiveExecutor;
|
private ConsecutiveExecutor consecutiveExecutor;
|
||||||
private LocaleManager localeManager;
|
private LocaleManager localeManager;
|
||||||
private ContextManager<ProxiedPlayer> contextManager;
|
private ContextManager<ProxiedPlayer> contextManager;
|
||||||
|
private CalculatorFactory calculatorFactory;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
@ -105,18 +107,18 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
|||||||
|
|
||||||
getLog().info("Loading internal permission managers...");
|
getLog().info("Loading internal permission managers...");
|
||||||
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
|
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
|
||||||
userManager = new BungeeUserManager(this);
|
userManager = new UserManager(this);
|
||||||
groupManager = new GroupManager(this);
|
groupManager = new GroupManager(this);
|
||||||
trackManager = new TrackManager();
|
trackManager = new TrackManager();
|
||||||
importer = new Importer(commandManager);
|
importer = new Importer(commandManager);
|
||||||
consecutiveExecutor = new ConsecutiveExecutor(commandManager);
|
consecutiveExecutor = new ConsecutiveExecutor(commandManager);
|
||||||
|
calculatorFactory = new BungeeCalculatorFactory(this);
|
||||||
|
|
||||||
contextManager = new ContextManager<>();
|
contextManager = new ContextManager<>();
|
||||||
BackendServerCalculator serverCalculator = new BackendServerCalculator();
|
BackendServerCalculator serverCalculator = new BackendServerCalculator();
|
||||||
getProxy().getPluginManager().registerListener(this, serverCalculator);
|
getProxy().getPluginManager().registerListener(this, serverCalculator);
|
||||||
contextManager.registerCalculator(serverCalculator);
|
contextManager.registerCalculator(serverCalculator);
|
||||||
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
|
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
|
||||||
contextManager.registerListener(userManager);
|
|
||||||
|
|
||||||
int mins = getConfiguration().getSyncTime();
|
int mins = getConfiguration().getSyncTime();
|
||||||
if (mins > 0) {
|
if (mins > 0) {
|
||||||
@ -196,9 +198,31 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getPossiblePermissions() {
|
public Set<Contexts> getPreProcessContexts(boolean op) {
|
||||||
// No such thing on Bungee. Wildcards are processed in the listener instead.
|
Set<Map<String, String>> c = new HashSet<>();
|
||||||
return Collections.emptyList();
|
c.add(Collections.emptyMap());
|
||||||
|
c.add(Collections.singletonMap("server", getConfiguration().getServer()));
|
||||||
|
c.addAll(getProxy().getServers().values().stream()
|
||||||
|
.map(ServerInfo::getName)
|
||||||
|
.map(s -> {
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
map.put("server", getConfiguration().getServer());
|
||||||
|
map.put("world", s);
|
||||||
|
return map;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
);
|
||||||
|
|
||||||
|
return c.stream()
|
||||||
|
.map(map -> new Contexts(
|
||||||
|
map,
|
||||||
|
getConfiguration().isIncludingGlobalPerms(),
|
||||||
|
getConfiguration().isIncludingGlobalWorldPerms(),
|
||||||
|
true,
|
||||||
|
getConfiguration().isApplyingGlobalGroups(),
|
||||||
|
getConfiguration().isApplyingGlobalWorldGroups()
|
||||||
|
))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,99 +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.BungeePlayerCache;
|
|
||||||
import me.lucko.luckperms.LPBungeePlugin;
|
|
||||||
import me.lucko.luckperms.api.Contexts;
|
|
||||||
import me.lucko.luckperms.api.event.events.UserPermissionRefreshEvent;
|
|
||||||
import me.lucko.luckperms.api.implementation.internal.UserLink;
|
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class BungeeUser extends User {
|
|
||||||
private final LPBungeePlugin plugin;
|
|
||||||
|
|
||||||
BungeeUser(UUID uuid, LPBungeePlugin plugin) {
|
|
||||||
super(uuid, plugin);
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
BungeeUser(UUID uuid, String username, LPBungeePlugin plugin) {
|
|
||||||
super(uuid, username, plugin);
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void refreshPermissions() {
|
|
||||||
ProxiedPlayer player = plugin.getProxy().getPlayer(plugin.getUuidCache().getExternalUUID(getUuid()));
|
|
||||||
if (player == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BungeePlayerCache playerCache = plugin.getPlayerCache().get(getUuid());
|
|
||||||
if (playerCache == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the permissions that should be applied. This is done async.
|
|
||||||
Map<String, Boolean> toApply = exportNodes(
|
|
||||||
new Contexts(
|
|
||||||
plugin.getContextManager().giveApplicableContext(player, new HashMap<>()),
|
|
||||||
plugin.getConfiguration().isIncludingGlobalPerms(),
|
|
||||||
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
|
|
||||||
true,
|
|
||||||
plugin.getConfiguration().isApplyingGlobalGroups(),
|
|
||||||
plugin.getConfiguration().isApplyingGlobalWorldGroups()
|
|
||||||
),
|
|
||||||
Collections.emptyList(),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, Boolean> existing = playerCache.getPermissions();
|
|
||||||
|
|
||||||
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();
|
|
||||||
playerCache.invalidateCache();
|
|
||||||
existing.putAll(toApply);
|
|
||||||
|
|
||||||
plugin.getApiProvider().fireEventAsync(new UserPermissionRefreshEvent(new UserLink(this)));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +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.LPBungeePlugin;
|
|
||||||
import me.lucko.luckperms.api.context.ContextListener;
|
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class BungeeUserManager extends UserManager implements ContextListener<ProxiedPlayer> {
|
|
||||||
private final LPBungeePlugin plugin;
|
|
||||||
|
|
||||||
public BungeeUserManager(LPBungeePlugin plugin) {
|
|
||||||
super(plugin);
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cleanup(User user) {
|
|
||||||
if (plugin.getProxy().getPlayer(plugin.getUuidCache().getExternalUUID(user.getUuid())) == null) {
|
|
||||||
unload(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User apply(UserIdentifier id) {
|
|
||||||
BungeeUser user = id.getUsername() == null ?
|
|
||||||
new BungeeUser(id.getUuid(), plugin) :
|
|
||||||
new BungeeUser(id.getUuid(), id.getUsername(), plugin);
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateAllUsers() {
|
|
||||||
plugin.getProxy().getPlayers().stream()
|
|
||||||
.map(p -> plugin.getUuidCache().getUUID(p.getUniqueId()))
|
|
||||||
.forEach(u -> plugin.getDatastore().loadUser(u, "null"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onContextChange(ProxiedPlayer 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -22,9 +22,11 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms;
|
package me.lucko.luckperms;
|
||||||
|
|
||||||
|
import me.lucko.luckperms.api.Contexts;
|
||||||
import me.lucko.luckperms.api.Logger;
|
import me.lucko.luckperms.api.Logger;
|
||||||
import me.lucko.luckperms.api.PlatformType;
|
import me.lucko.luckperms.api.PlatformType;
|
||||||
import me.lucko.luckperms.api.implementation.ApiProvider;
|
import me.lucko.luckperms.api.implementation.ApiProvider;
|
||||||
|
import me.lucko.luckperms.calculators.CalculatorFactory;
|
||||||
import me.lucko.luckperms.commands.ConsecutiveExecutor;
|
import me.lucko.luckperms.commands.ConsecutiveExecutor;
|
||||||
import me.lucko.luckperms.commands.Sender;
|
import me.lucko.luckperms.commands.Sender;
|
||||||
import me.lucko.luckperms.config.LPConfiguration;
|
import me.lucko.luckperms.config.LPConfiguration;
|
||||||
@ -64,6 +66,7 @@ public interface LuckPermsPlugin {
|
|||||||
ConsecutiveExecutor getConsecutiveExecutor();
|
ConsecutiveExecutor getConsecutiveExecutor();
|
||||||
LocaleManager getLocaleManager();
|
LocaleManager getLocaleManager();
|
||||||
ContextManager getContextManager();
|
ContextManager getContextManager();
|
||||||
|
CalculatorFactory getCalculatorFactory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the version of the plugin
|
* @return the version of the plugin
|
||||||
@ -114,11 +117,8 @@ public interface LuckPermsPlugin {
|
|||||||
*/
|
*/
|
||||||
Sender getConsoleSender();
|
Sender getConsoleSender();
|
||||||
|
|
||||||
/**
|
// TODO javadoc
|
||||||
* Gets all possible permission nodes, used for resolving wildcards
|
Set<Contexts> getPreProcessContexts(boolean op);
|
||||||
* @return a {@link List} of permission nodes
|
|
||||||
*/
|
|
||||||
List<String> getPossiblePermissions();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a set of players ignoring logging output
|
* Gets a set of players ignoring logging output
|
||||||
|
116
common/src/main/java/me/lucko/luckperms/caching/MetaData.java
Normal file
116
common/src/main/java/me/lucko/luckperms/caching/MetaData.java
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* 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.caching;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import me.lucko.luckperms.api.Contexts;
|
||||||
|
import me.lucko.luckperms.api.LocalizedNode;
|
||||||
|
import me.lucko.luckperms.api.Node;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MetaData {
|
||||||
|
private final Contexts contexts;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private String prefix = null;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private String suffix = null;
|
||||||
|
private Map<String, String> meta = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public void loadMeta(SortedSet<LocalizedNode> nodes) {
|
||||||
|
invalidateCache();
|
||||||
|
|
||||||
|
Map<String, String> contexts = new HashMap<>(this.contexts.getContext());
|
||||||
|
String server = contexts.remove("server");
|
||||||
|
String world = contexts.remove("world");
|
||||||
|
|
||||||
|
int prefixPriority = Integer.MIN_VALUE;
|
||||||
|
int suffixPriority = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
for (LocalizedNode ln : nodes) {
|
||||||
|
Node n = ln.getNode();
|
||||||
|
|
||||||
|
if (!n.getValue()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!n.isMeta() || !n.isPrefix() || n.isSuffix()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!n.shouldApplyOnServer(server, this.contexts.isIncludeGlobal(), false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!n.shouldApplyOnWorld(world, this.contexts.isIncludeGlobalWorld(), false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!n.shouldApplyWithContext(contexts, false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.isPrefix()) {
|
||||||
|
Map.Entry<Integer, String> value = n.getPrefix();
|
||||||
|
if (value.getKey() > prefixPriority) {
|
||||||
|
this.prefix = value.getValue();
|
||||||
|
prefixPriority = value.getKey();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.isSuffix()) {
|
||||||
|
Map.Entry<Integer, String> value = n.getSuffix();
|
||||||
|
if (value.getKey() > suffixPriority) {
|
||||||
|
this.suffix = value.getValue();
|
||||||
|
suffixPriority = value.getKey();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.isMeta()) {
|
||||||
|
Map.Entry<String, String> meta = n.getMeta();
|
||||||
|
this.meta.put(meta.getKey(), meta.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidateCache() {
|
||||||
|
meta.clear();
|
||||||
|
prefix = null;
|
||||||
|
suffix = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getMeta() {
|
||||||
|
return ImmutableMap.copyOf(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -20,56 +20,67 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package me.lucko.luckperms.api.sponge;
|
package me.lucko.luckperms.caching;
|
||||||
|
|
||||||
import lombok.Getter;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
|
import me.lucko.luckperms.api.Contexts;
|
||||||
import me.lucko.luckperms.api.Tristate;
|
import me.lucko.luckperms.api.Tristate;
|
||||||
import me.lucko.luckperms.calculators.*;
|
import me.lucko.luckperms.calculators.CalculatorFactory;
|
||||||
import org.spongepowered.api.service.context.Context;
|
import me.lucko.luckperms.calculators.PermissionCalculator;
|
||||||
|
import me.lucko.luckperms.users.User;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class ContextData {
|
public class PermissionData {
|
||||||
|
private final Contexts contexts;
|
||||||
@Getter
|
private final Map<String, Boolean> permissions;
|
||||||
private final Map<String, String> context;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final Map<String, Boolean> permissionCache = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private final PermissionCalculator calculator;
|
private final PermissionCalculator calculator;
|
||||||
|
|
||||||
public ContextData(LuckPermsUserSubject parent, Map<String, String> context, LuckPermsService service) {
|
public PermissionData(Contexts contexts, User user, CalculatorFactory calculatorFactory) {
|
||||||
this.context = context;
|
this.contexts = contexts;
|
||||||
|
permissions = new ConcurrentHashMap<>();
|
||||||
Set<Context> contexts = context.entrySet().stream().map(e -> new Context(e.getKey(), e.getValue())).collect(Collectors.toSet());
|
calculator = calculatorFactory.build(contexts, user, permissions);
|
||||||
List<PermissionProcessor> processors = new ArrayList<>(5);
|
|
||||||
processors.add(new MapProcessor(permissionCache));
|
|
||||||
if (service.getPlugin().getConfiguration().isApplyingWildcards()) {
|
|
||||||
processors.add(new SpongeWildcardProcessor(permissionCache));
|
|
||||||
processors.add(new WildcardProcessor(permissionCache));
|
|
||||||
}
|
|
||||||
if (service.getPlugin().getConfiguration().isApplyingRegex()) {
|
|
||||||
processors.add(new RegexProcessor(permissionCache));
|
|
||||||
}
|
|
||||||
processors.add(new DefaultsProcessor(service, contexts));
|
|
||||||
|
|
||||||
calculator = new PermissionCalculator(service.getPlugin(), parent.getUser().getName(), service.getPlugin().getConfiguration().isDebugPermissionChecks(), processors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void invalidateCache() {
|
public void invalidateCache() {
|
||||||
calculator.invalidateCache();
|
calculator.invalidateCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPermissions(Map<String, Boolean> permissions) {
|
||||||
|
this.permissions.clear();
|
||||||
|
this.permissions.putAll(permissions);
|
||||||
|
invalidateCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void comparePermissions(Map<String, Boolean> toApply) {
|
||||||
|
boolean different = false;
|
||||||
|
if (toApply.size() != permissions.size()) {
|
||||||
|
different = true;
|
||||||
|
} else {
|
||||||
|
for (Map.Entry<String, Boolean> e : permissions.entrySet()) {
|
||||||
|
if (toApply.containsKey(e.getKey()) && toApply.get(e.getKey()) == e.getValue()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
different = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (different) {
|
||||||
|
setPermissions(toApply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Boolean> getImmutableBacking() {
|
||||||
|
return ImmutableMap.copyOf(permissions);
|
||||||
|
}
|
||||||
|
|
||||||
public Tristate getPermissionValue(@NonNull String permission) {
|
public Tristate getPermissionValue(@NonNull String permission) {
|
||||||
me.lucko.luckperms.api.Tristate t = calculator.getPermissionValue(permission);
|
Tristate t = calculator.getPermissionValue(permission);
|
||||||
if (t != me.lucko.luckperms.api.Tristate.UNDEFINED) {
|
if (t != Tristate.UNDEFINED) {
|
||||||
return Tristate.fromBoolean(t.asBoolean());
|
return Tristate.fromBoolean(t.asBoolean());
|
||||||
} else {
|
} else {
|
||||||
return Tristate.UNDEFINED;
|
return Tristate.UNDEFINED;
|
107
common/src/main/java/me/lucko/luckperms/caching/UserData.java
Normal file
107
common/src/main/java/me/lucko/luckperms/caching/UserData.java
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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.caching;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import me.lucko.luckperms.api.Contexts;
|
||||||
|
import me.lucko.luckperms.calculators.CalculatorFactory;
|
||||||
|
import me.lucko.luckperms.users.User;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UserData {
|
||||||
|
private final User user;
|
||||||
|
private final CalculatorFactory calculatorFactory;
|
||||||
|
|
||||||
|
private final Map<Contexts, PermissionData> permission = new ConcurrentHashMap<>();
|
||||||
|
private final Map<Contexts, MetaData> meta = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public PermissionData getPermissionData(Contexts contexts) {
|
||||||
|
return permission.computeIfAbsent(contexts, this::calculatePermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetaData getMetaData(Contexts contexts) {
|
||||||
|
return meta.computeIfAbsent(contexts, this::calculateMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PermissionData calculatePermissions(Contexts contexts) {
|
||||||
|
PermissionData data = new PermissionData(contexts, user, calculatorFactory);
|
||||||
|
data.setPermissions(user.exportNodes(contexts, Collections.emptyList(), true));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recalculatePermissions(Contexts contexts) {
|
||||||
|
permission.compute(contexts, (c, data) -> {
|
||||||
|
if (data == null) {
|
||||||
|
data = new PermissionData(c, user, calculatorFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.comparePermissions(user.exportNodes(c, Collections.emptyList(), true));
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recalculatePermissions() {
|
||||||
|
permission.keySet().forEach(this::recalculatePermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetaData calculateMeta(Contexts contexts) {
|
||||||
|
MetaData data = new MetaData(contexts);
|
||||||
|
data.loadMeta(user.getAllNodes(null, contexts));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recalculateMeta(Contexts contexts) {
|
||||||
|
meta.compute(contexts, (c, data) -> {
|
||||||
|
if (data == null) {
|
||||||
|
data = new MetaData(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.loadMeta(user.getAllNodes(null, c));
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recalculateMeta() {
|
||||||
|
meta.keySet().forEach(this::recalculateMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void preCalculate(Set<Contexts> contexts) {
|
||||||
|
contexts.forEach(this::preCalculate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void preCalculate(Contexts contexts) {
|
||||||
|
getPermissionData(contexts);
|
||||||
|
getMetaData(contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidateCache() {
|
||||||
|
permission.clear();
|
||||||
|
meta.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -20,32 +20,18 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package me.lucko.luckperms.api.vault.cache;
|
package me.lucko.luckperms.calculators;
|
||||||
|
|
||||||
import lombok.Getter;
|
import me.lucko.luckperms.api.Contexts;
|
||||||
import lombok.RequiredArgsConstructor;
|
import me.lucko.luckperms.users.User;
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
@Getter
|
/**
|
||||||
@RequiredArgsConstructor
|
* Creates a calculator instance given a set of contexts
|
||||||
public class ChatCache {
|
*/
|
||||||
private final Map<String, String> context;
|
public interface CalculatorFactory {
|
||||||
|
|
||||||
@Setter
|
PermissionCalculator build(Contexts contexts, User user, Map<String, Boolean> map);
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -30,6 +30,7 @@ import me.lucko.luckperms.LuckPermsPlugin;
|
|||||||
import me.lucko.luckperms.api.event.events.GroupAddEvent;
|
import me.lucko.luckperms.api.event.events.GroupAddEvent;
|
||||||
import me.lucko.luckperms.api.implementation.internal.GroupLink;
|
import me.lucko.luckperms.api.implementation.internal.GroupLink;
|
||||||
import me.lucko.luckperms.api.implementation.internal.PermissionHolderLink;
|
import me.lucko.luckperms.api.implementation.internal.PermissionHolderLink;
|
||||||
|
import me.lucko.luckperms.caching.UserData;
|
||||||
import me.lucko.luckperms.core.PermissionHolder;
|
import me.lucko.luckperms.core.PermissionHolder;
|
||||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||||
@ -40,7 +41,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
@ToString(of = {"uuid"})
|
@ToString(of = {"uuid"})
|
||||||
@EqualsAndHashCode(of = {"uuid"}, callSuper = false)
|
@EqualsAndHashCode(of = {"uuid"}, callSuper = false)
|
||||||
public abstract class User extends PermissionHolder implements Identifiable<UserIdentifier> {
|
public class User extends PermissionHolder implements Identifiable<UserIdentifier> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The users Mojang UUID
|
* The users Mojang UUID
|
||||||
@ -62,6 +63,9 @@ public abstract class User extends PermissionHolder implements Identifiable<User
|
|||||||
@Setter
|
@Setter
|
||||||
private String primaryGroup = null;
|
private String primaryGroup = null;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private UserData userData = null;
|
||||||
|
|
||||||
protected User(UUID uuid, LuckPermsPlugin plugin) {
|
protected User(UUID uuid, LuckPermsPlugin plugin) {
|
||||||
super(uuid.toString(), plugin);
|
super(uuid.toString(), plugin);
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
@ -85,9 +89,43 @@ public abstract class User extends PermissionHolder implements Identifiable<User
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh and re-assign the users permissions
|
* Sets up the UserData cache
|
||||||
|
* Blocking call.
|
||||||
*/
|
*/
|
||||||
public abstract void refreshPermissions();
|
public void setupData(boolean op) {
|
||||||
|
if (userData != null) {
|
||||||
|
throw new IllegalStateException("Data already setup");
|
||||||
|
}
|
||||||
|
|
||||||
|
userData = new UserData(this, null);
|
||||||
|
userData.preCalculate(getPlugin().getPreProcessContexts(op));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the UserData cache from this user
|
||||||
|
*/
|
||||||
|
public void unregisterData() {
|
||||||
|
if (userData != null) {
|
||||||
|
userData.invalidateCache();
|
||||||
|
userData = null;
|
||||||
|
}
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh and re-assign the users permissions
|
||||||
|
* Blocking call.
|
||||||
|
*/
|
||||||
|
public synchronized void refreshPermissions() {
|
||||||
|
if (userData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserData ud = userData;
|
||||||
|
ud.recalculatePermissions();
|
||||||
|
ud.recalculateMeta();
|
||||||
|
// TODO api call?
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check to see if the user is a member of a group
|
* Check to see if the user is a member of a group
|
||||||
|
@ -33,7 +33,7 @@ import me.lucko.luckperms.utils.Identifiable;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public abstract class UserManager extends AbstractManager<UserIdentifier, User> {
|
public class UserManager extends AbstractManager<UserIdentifier, User> {
|
||||||
private final LuckPermsPlugin plugin;
|
private final LuckPermsPlugin plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,10 +121,21 @@ public abstract class UserManager extends AbstractManager<UserIdentifier, User>
|
|||||||
* Checks to see if the user is online, and if they are not, runs {@link #unload(Identifiable)}
|
* Checks to see if the user is online, and if they are not, runs {@link #unload(Identifiable)}
|
||||||
* @param user The user to be cleaned up
|
* @param user The user to be cleaned up
|
||||||
*/
|
*/
|
||||||
public abstract void cleanup(User user);
|
public void cleanup(User user) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reloads the data of all online users
|
* Reloads the data of all online users
|
||||||
*/
|
*/
|
||||||
public abstract void updateAllUsers();
|
public void updateAllUsers() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User apply(UserIdentifier id) {
|
||||||
|
return id.getUsername() == null ?
|
||||||
|
new User(id.getUuid(), plugin) :
|
||||||
|
new User(id.getUuid(), id.getUsername(), plugin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,13 @@ public class AbstractListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugin.getDatastore().loadUser(cache.getUUID(u), username);
|
plugin.getDatastore().loadUser(cache.getUUID(u), username);
|
||||||
|
User user = plugin.getUserManager().get(cache.getUUID(u));
|
||||||
|
if (user == null) {
|
||||||
|
plugin.getLog().warn("Failed to load user: " + username);
|
||||||
|
} else {
|
||||||
|
user.setupData(false); // Pretty nasty calculation call. Sets up the caching system so data is ready when the user joins.
|
||||||
|
}
|
||||||
|
|
||||||
final long time = System.currentTimeMillis() - startTime;
|
final long time = System.currentTimeMillis() - startTime;
|
||||||
if (time >= 1000) {
|
if (time >= 1000) {
|
||||||
plugin.getLog().warn("Processing login for " + username + " took " + time + "ms.");
|
plugin.getLog().warn("Processing login for " + username + " took " + time + "ms.");
|
||||||
@ -71,6 +78,7 @@ public class AbstractListener {
|
|||||||
|
|
||||||
final User user = plugin.getUserManager().get(cache.getUUID(uuid));
|
final User user = plugin.getUserManager().get(cache.getUUID(uuid));
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
|
user.unregisterData();
|
||||||
plugin.getUserManager().unload(user);
|
plugin.getUserManager().unload(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ import me.lucko.luckperms.config.LPConfiguration;
|
|||||||
import me.lucko.luckperms.constants.Message;
|
import me.lucko.luckperms.constants.Message;
|
||||||
import me.lucko.luckperms.constants.Permission;
|
import me.lucko.luckperms.constants.Permission;
|
||||||
import me.lucko.luckperms.contexts.ContextManager;
|
import me.lucko.luckperms.contexts.ContextManager;
|
||||||
import me.lucko.luckperms.contexts.ContextUpdateTask;
|
|
||||||
import me.lucko.luckperms.contexts.ServerCalculator;
|
import me.lucko.luckperms.contexts.ServerCalculator;
|
||||||
import me.lucko.luckperms.contexts.WorldCalculator;
|
import me.lucko.luckperms.contexts.WorldCalculator;
|
||||||
import me.lucko.luckperms.core.UuidCache;
|
import me.lucko.luckperms.core.UuidCache;
|
||||||
@ -46,6 +45,7 @@ import me.lucko.luckperms.storage.Datastore;
|
|||||||
import me.lucko.luckperms.storage.StorageFactory;
|
import me.lucko.luckperms.storage.StorageFactory;
|
||||||
import me.lucko.luckperms.tracks.TrackManager;
|
import me.lucko.luckperms.tracks.TrackManager;
|
||||||
import me.lucko.luckperms.users.SpongeUserManager;
|
import me.lucko.luckperms.users.SpongeUserManager;
|
||||||
|
import me.lucko.luckperms.users.UserManager;
|
||||||
import me.lucko.luckperms.utils.LocaleManager;
|
import me.lucko.luckperms.utils.LocaleManager;
|
||||||
import me.lucko.luckperms.utils.LogFactory;
|
import me.lucko.luckperms.utils.LogFactory;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -89,7 +89,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
|
|||||||
|
|
||||||
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
|
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
|
||||||
private LPConfiguration configuration;
|
private LPConfiguration configuration;
|
||||||
private SpongeUserManager userManager;
|
private UserManager userManager;
|
||||||
private GroupManager groupManager;
|
private GroupManager groupManager;
|
||||||
private TrackManager trackManager;
|
private TrackManager trackManager;
|
||||||
private Datastore datastore;
|
private Datastore datastore;
|
||||||
@ -133,7 +133,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
|
|||||||
|
|
||||||
getLog().info("Loading internal permission managers...");
|
getLog().info("Loading internal permission managers...");
|
||||||
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
|
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
|
||||||
userManager = new SpongeUserManager(this);
|
userManager = new UserManager(this);
|
||||||
groupManager = new GroupManager(this);
|
groupManager = new GroupManager(this);
|
||||||
trackManager = new TrackManager();
|
trackManager = new TrackManager();
|
||||||
importer = new Importer(commandManager);
|
importer = new Importer(commandManager);
|
||||||
@ -142,7 +142,6 @@ public class LPSpongePlugin implements LuckPermsPlugin {
|
|||||||
contextManager = new ContextManager<>();
|
contextManager = new ContextManager<>();
|
||||||
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
|
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
|
||||||
contextManager.registerCalculator(new WorldCalculator());
|
contextManager.registerCalculator(new WorldCalculator());
|
||||||
contextManager.registerListener(userManager);
|
|
||||||
|
|
||||||
getLog().info("Registering PermissionService...");
|
getLog().info("Registering PermissionService...");
|
||||||
Sponge.getServiceManager().setProvider(this, PermissionService.class, (service = new LuckPermsService(this)));
|
Sponge.getServiceManager().setProvider(this, PermissionService.class, (service = new LuckPermsService(this)));
|
||||||
@ -164,7 +163,6 @@ public class LPSpongePlugin implements LuckPermsPlugin {
|
|||||||
scheduler.createTaskBuilder().intervalTicks(1L).execute(SpongeSenderFactory.get(this)).submit(this);
|
scheduler.createTaskBuilder().intervalTicks(1L).execute(SpongeSenderFactory.get(this)).submit(this);
|
||||||
scheduler.createTaskBuilder().async().intervalTicks(60L).execute(new ExpireTemporaryTask(this)).submit(this);
|
scheduler.createTaskBuilder().async().intervalTicks(60L).execute(new ExpireTemporaryTask(this)).submit(this);
|
||||||
scheduler.createTaskBuilder().async().intervalTicks(20L).execute(consecutiveExecutor).submit(this);
|
scheduler.createTaskBuilder().async().intervalTicks(20L).execute(consecutiveExecutor).submit(this);
|
||||||
scheduler.createTaskBuilder().async().intervalTicks(600L).execute(new ContextUpdateTask(service.getUserSubjects())).submit(this);
|
|
||||||
|
|
||||||
getLog().info("Successfully loaded.");
|
getLog().info("Successfully loaded.");
|
||||||
}
|
}
|
||||||
@ -252,15 +250,6 @@ public class LPSpongePlugin implements LuckPermsPlugin {
|
|||||||
return SpongeSenderFactory.get(this).wrap(game.getServer().getConsole());
|
return SpongeSenderFactory.get(this).wrap(game.getServer().getConsole());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> getPossiblePermissions() {
|
|
||||||
Optional<PermissionService> p = game.getServiceManager().provide(PermissionService.class);
|
|
||||||
if (!p.isPresent()) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return p.get().getDescriptions().stream().map(PermissionDescription::getId).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getPlugin(String name) {
|
public Object getPlugin(String name) {
|
||||||
return game.getPluginManager().getPlugin(name).get().getInstance().get();
|
return game.getPluginManager().getPlugin(name).get().getInstance().get();
|
||||||
|
@ -30,7 +30,6 @@ import me.lucko.luckperms.api.Contexts;
|
|||||||
import me.lucko.luckperms.api.Node;
|
import me.lucko.luckperms.api.Node;
|
||||||
import me.lucko.luckperms.core.PermissionHolder;
|
import me.lucko.luckperms.core.PermissionHolder;
|
||||||
import me.lucko.luckperms.groups.Group;
|
import me.lucko.luckperms.groups.Group;
|
||||||
import me.lucko.luckperms.users.User;
|
|
||||||
import org.spongepowered.api.command.CommandSource;
|
import org.spongepowered.api.command.CommandSource;
|
||||||
import org.spongepowered.api.service.context.Context;
|
import org.spongepowered.api.service.context.Context;
|
||||||
import org.spongepowered.api.service.permission.Subject;
|
import org.spongepowered.api.service.permission.Subject;
|
||||||
@ -43,48 +42,33 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import static me.lucko.luckperms.utils.ArgumentChecker.unescapeCharacters;
|
import static me.lucko.luckperms.utils.ArgumentChecker.unescapeCharacters;
|
||||||
|
|
||||||
@EqualsAndHashCode(of = {"holder"})
|
@EqualsAndHashCode(of = "group")
|
||||||
public class LuckPermsSubject implements Subject {
|
public class LuckPermsGroupSubject implements Subject {
|
||||||
public static LuckPermsSubject wrapHolder(PermissionHolder holder, LuckPermsService service) {
|
public static LuckPermsGroupSubject wrapGroup(Group group, LuckPermsService service) {
|
||||||
return new LuckPermsSubject(holder, service);
|
return new LuckPermsGroupSubject(group, service);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private PermissionHolder holder;
|
private PermissionHolder group;
|
||||||
private LuckPermsSubjectData enduringData;
|
|
||||||
private LuckPermsSubjectData transientData;
|
|
||||||
protected LuckPermsService service;
|
|
||||||
|
|
||||||
LuckPermsSubject(PermissionHolder holder, LuckPermsService service) {
|
private LuckPermsService service;
|
||||||
this.holder = holder;
|
|
||||||
this.enduringData = new LuckPermsSubjectData(true, this, service, holder);
|
@Getter
|
||||||
this.transientData = new LuckPermsSubjectData(true, this, service, holder);
|
private LuckPermsSubjectData subjectData;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private LuckPermsSubjectData transientSubjectData;
|
||||||
|
|
||||||
|
private LuckPermsGroupSubject(PermissionHolder group, LuckPermsService service) {
|
||||||
|
this.group = group;
|
||||||
|
this.subjectData = new LuckPermsSubjectData(true, service, group);
|
||||||
|
this.transientSubjectData = new LuckPermsSubjectData(false, service, group);
|
||||||
this.service = service;
|
this.service = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deprovision() {
|
|
||||||
holder = null;
|
|
||||||
enduringData = null;
|
|
||||||
transientData = null;
|
|
||||||
service = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void objectSave(PermissionHolder t) {
|
|
||||||
service.getPlugin().doAsync(() -> {
|
|
||||||
if (t instanceof User) {
|
|
||||||
((User) t).refreshPermissions();
|
|
||||||
service.getPlugin().getDatastore().saveUser(((User) t));
|
|
||||||
}
|
|
||||||
if (t instanceof Group) {
|
|
||||||
service.getPlugin().getDatastore().saveGroup(((Group) t));
|
|
||||||
service.getPlugin().runUpdateTask();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIdentifier() {
|
public String getIdentifier() {
|
||||||
return holder.getObjectName();
|
return group.getObjectName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -94,25 +78,7 @@ public class LuckPermsSubject implements Subject {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SubjectCollection getContainingCollection() {
|
public SubjectCollection getContainingCollection() {
|
||||||
if (holder instanceof Group) {
|
return service.getGroupSubjects();
|
||||||
return service.getGroupSubjects();
|
|
||||||
} else {
|
|
||||||
return service.getUserSubjects();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SubjectData getSubjectData() {
|
|
||||||
return enduringData;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SubjectData getTransientSubjectData() {
|
|
||||||
return transientData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPermissionSet(@NonNull Set<Context> contexts, @NonNull String node) {
|
|
||||||
return getPermissionValue(contexts, node) != Tristate.UNDEFINED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -120,11 +86,6 @@ public class LuckPermsSubject implements Subject {
|
|||||||
return getPermissionValue(contexts, node).asBoolean();
|
return getPermissionValue(contexts, node).asBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPermission(String permission) {
|
|
||||||
return getPermissionValue(getActiveContexts(), permission).asBoolean();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
|
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
|
||||||
Map<String, String> context = new HashMap<>();
|
Map<String, String> context = new HashMap<>();
|
||||||
@ -132,7 +93,7 @@ public class LuckPermsSubject implements Subject {
|
|||||||
context.put(c.getKey(), c.getValue());
|
context.put(c.getKey(), c.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (holder.inheritsPermission(new me.lucko.luckperms.core.Node.Builder(node).withExtraContext(context).build())) {
|
switch (group.inheritsPermission(new me.lucko.luckperms.core.Node.Builder(node).withExtraContext(context).build())) {
|
||||||
case UNDEFINED:
|
case UNDEFINED:
|
||||||
return Tristate.UNDEFINED;
|
return Tristate.UNDEFINED;
|
||||||
case TRUE:
|
case TRUE:
|
||||||
@ -142,53 +103,45 @@ public class LuckPermsSubject implements Subject {
|
|||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// TODO
|
||||||
public boolean isChildOf(@NonNull Subject parent) {
|
|
||||||
return isChildOf(getActiveContexts(), parent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject parent) {
|
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject parent) {
|
||||||
return parent instanceof PermissionHolder && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean();
|
return parent instanceof LuckPermsGroupSubject && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Subject> getParents() {
|
|
||||||
return getParents(getActiveContexts());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Subject> getParents(@NonNull Set<Context> contexts) {
|
public List<Subject> getParents(@NonNull Set<Context> contexts) {
|
||||||
List<Subject> parents = new ArrayList<>();
|
List<Subject> parents = new ArrayList<>();
|
||||||
parents.addAll(enduringData.getParents(contexts));
|
parents.addAll(subjectData.getParents(contexts));
|
||||||
parents.addAll(transientData.getParents(contexts));
|
parents.addAll(transientSubjectData.getParents(contexts));
|
||||||
return ImmutableList.copyOf(parents);
|
return ImmutableList.copyOf(parents);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<String> getOption(Set<Context> set, String s) {
|
public Optional<String> getOption(Set<Context> set, String s) {
|
||||||
if (s.equalsIgnoreCase("prefix")) {
|
if (s.equalsIgnoreCase("prefix")) {
|
||||||
String prefix = getChatMeta(set, true, holder);
|
String prefix = getChatMeta(set, true, group);
|
||||||
if (!prefix.equals("")) {
|
if (!prefix.equals("")) {
|
||||||
return Optional.of(prefix);
|
return Optional.of(prefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.equalsIgnoreCase("suffix")) {
|
if (s.equalsIgnoreCase("suffix")) {
|
||||||
String suffix = getChatMeta(set, false, holder);
|
String suffix = getChatMeta(set, false, group);
|
||||||
if (!suffix.equals("")) {
|
if (!suffix.equals("")) {
|
||||||
return Optional.of(suffix);
|
return Optional.of(suffix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> transientOptions = enduringData.getOptions(set);
|
Map<String, String> transientOptions = subjectData.getOptions(set);
|
||||||
if (transientOptions.containsKey(s)) {
|
if (transientOptions.containsKey(s)) {
|
||||||
return Optional.of(transientOptions.get(s));
|
return Optional.of(transientOptions.get(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> enduringOptions = enduringData.getOptions(set);
|
Map<String, String> enduringOptions = subjectData.getOptions(set);
|
||||||
if (enduringOptions.containsKey(s)) {
|
if (enduringOptions.containsKey(s)) {
|
||||||
return Optional.of(enduringOptions.get(s));
|
return Optional.of(enduringOptions.get(s));
|
||||||
}
|
}
|
||||||
@ -196,11 +149,6 @@ public class LuckPermsSubject implements Subject {
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<String> getOption(String key) {
|
|
||||||
return getOption(getActiveContexts(), key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Context> getActiveContexts() {
|
public Set<Context> getActiveContexts() {
|
||||||
return SubjectData.GLOBAL_CONTEXT;
|
return SubjectData.GLOBAL_CONTEXT;
|
@ -33,6 +33,7 @@ import me.lucko.luckperms.api.sponge.simple.persisted.SimplePersistedCollection;
|
|||||||
import me.lucko.luckperms.api.sponge.simple.persisted.SubjectStorage;
|
import me.lucko.luckperms.api.sponge.simple.persisted.SubjectStorage;
|
||||||
import me.lucko.luckperms.contexts.SpongeCalculatorLink;
|
import me.lucko.luckperms.contexts.SpongeCalculatorLink;
|
||||||
import org.spongepowered.api.plugin.PluginContainer;
|
import org.spongepowered.api.plugin.PluginContainer;
|
||||||
|
import org.spongepowered.api.service.context.Context;
|
||||||
import org.spongepowered.api.service.context.ContextCalculator;
|
import org.spongepowered.api.service.context.ContextCalculator;
|
||||||
import org.spongepowered.api.service.permission.*;
|
import org.spongepowered.api.service.permission.*;
|
||||||
import org.spongepowered.api.text.Text;
|
import org.spongepowered.api.text.Text;
|
||||||
@ -41,6 +42,7 @@ import org.spongepowered.api.util.Tristate;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The LuckPerms implementation of the Sponge Permission Service
|
* The LuckPerms implementation of the Sponge Permission Service
|
||||||
@ -140,6 +142,36 @@ public class LuckPermsService implements PermissionService {
|
|||||||
plugin.getContextManager().registerCalculator(new SpongeCalculatorLink(contextCalculator));
|
plugin.getContextManager().registerCalculator(new SpongeCalculatorLink(contextCalculator));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> convertContexts(Set<Context> contexts) {
|
||||||
|
return contexts.stream().collect(Collectors.toMap(Context::getKey, Context::getValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<Context> convertContexts(Map<String, String> contexts) {
|
||||||
|
return contexts.entrySet().stream().map(e -> new Context(e.getKey(), e.getValue())).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tristate convertTristate(me.lucko.luckperms.api.Tristate tristate) {
|
||||||
|
switch (tristate) {
|
||||||
|
case TRUE:
|
||||||
|
return Tristate.TRUE;
|
||||||
|
case FALSE:
|
||||||
|
return Tristate.FALSE;
|
||||||
|
default:
|
||||||
|
return Tristate.UNDEFINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static me.lucko.luckperms.api.Tristate convertTristate(Tristate tristate) {
|
||||||
|
switch (tristate) {
|
||||||
|
case TRUE:
|
||||||
|
return me.lucko.luckperms.api.Tristate.TRUE;
|
||||||
|
case FALSE:
|
||||||
|
return me.lucko.luckperms.api.Tristate.FALSE;
|
||||||
|
default:
|
||||||
|
return me.lucko.luckperms.api.Tristate.UNDEFINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
@ToString
|
@ToString
|
||||||
|
@ -31,6 +31,7 @@ import me.lucko.luckperms.api.Node;
|
|||||||
import me.lucko.luckperms.core.PermissionHolder;
|
import me.lucko.luckperms.core.PermissionHolder;
|
||||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||||
|
import me.lucko.luckperms.groups.Group;
|
||||||
import me.lucko.luckperms.users.User;
|
import me.lucko.luckperms.users.User;
|
||||||
import org.spongepowered.api.service.context.Context;
|
import org.spongepowered.api.service.context.Context;
|
||||||
import org.spongepowered.api.service.permission.Subject;
|
import org.spongepowered.api.service.permission.Subject;
|
||||||
@ -41,25 +42,34 @@ import java.util.*;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static me.lucko.luckperms.utils.ArgumentChecker.escapeCharacters;
|
import static me.lucko.luckperms.utils.ArgumentChecker.escapeCharacters;
|
||||||
import static me.lucko.luckperms.utils.ArgumentChecker.unescapeCharacters;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class LuckPermsSubjectData implements SubjectData {
|
public class LuckPermsSubjectData implements SubjectData {
|
||||||
private final boolean enduring;
|
private final boolean enduring;
|
||||||
private final LuckPermsSubject superClass;
|
|
||||||
private final LuckPermsService service;
|
private final LuckPermsService service;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final PermissionHolder holder;
|
private final PermissionHolder holder;
|
||||||
|
|
||||||
|
private void objectSave(PermissionHolder t) {
|
||||||
|
service.getPlugin().doAsync(() -> {
|
||||||
|
if (t instanceof User) {
|
||||||
|
((User) t).refreshPermissions();
|
||||||
|
service.getPlugin().getDatastore().saveUser(((User) t));
|
||||||
|
}
|
||||||
|
if (t instanceof Group) {
|
||||||
|
service.getPlugin().getDatastore().saveGroup(((Group) t));
|
||||||
|
service.getPlugin().runUpdateTask();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Set<Context>, Map<String, Boolean>> getAllPermissions() {
|
public Map<Set<Context>, Map<String, Boolean>> getAllPermissions() {
|
||||||
Map<Set<Context>, Map<String, Boolean>> perms = new HashMap<>();
|
Map<Set<Context>, Map<String, Boolean>> perms = new HashMap<>();
|
||||||
|
|
||||||
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
|
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
|
||||||
Set<Context> contexts = n.getExtraContexts().entrySet().stream()
|
Set<Context> contexts = LuckPermsService.convertContexts(n.getExtraContexts());
|
||||||
.map(entry -> new Context(entry.getKey(), entry.getValue()))
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
|
||||||
if (n.isServerSpecific()) {
|
if (n.isServerSpecific()) {
|
||||||
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
|
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
|
||||||
@ -84,8 +94,14 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Boolean> getPermissions(Set<Context> set) {
|
public Map<String, Boolean> getPermissions(Set<Context> contexts) {
|
||||||
return getAllPermissions().getOrDefault(set, ImmutableMap.of());
|
ImmutableMap.Builder<String, Boolean> permissions = ImmutableMap.builder();
|
||||||
|
|
||||||
|
(enduring ? holder.getNodes() : holder.getTransientNodes()).stream()
|
||||||
|
.filter(n -> n.shouldApplyWithContext(LuckPermsService.convertContexts(contexts), true))
|
||||||
|
.forEach(n -> permissions.put(n.getKey(), n.getValue()));
|
||||||
|
|
||||||
|
return permissions.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -105,7 +121,8 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
holder.unsetTransientPermission(builder.build());
|
holder.unsetTransientPermission(builder.build());
|
||||||
}
|
}
|
||||||
} catch (ObjectLacksException ignored) {}
|
} catch (ObjectLacksException ignored) {}
|
||||||
superClass.objectSave(holder);
|
|
||||||
|
objectSave(holder);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +140,8 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
holder.setTransientPermission(builder.build());
|
holder.setTransientPermission(builder.build());
|
||||||
}
|
}
|
||||||
} catch (ObjectAlreadyHasException ignored) {}
|
} catch (ObjectAlreadyHasException ignored) {}
|
||||||
superClass.objectSave(holder);
|
|
||||||
|
objectSave(holder);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,15 +152,14 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
} else {
|
} else {
|
||||||
holder.clearTransientNodes();
|
holder.clearTransientNodes();
|
||||||
}
|
}
|
||||||
superClass.objectSave(holder);
|
objectSave(holder);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean clearPermissions(Set<Context> set) {
|
public boolean clearPermissions(Set<Context> contexts) {
|
||||||
Map<String, String> context = set.stream().collect(Collectors.toMap(Context::getKey, Context::getValue));
|
|
||||||
List<Node> toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream()
|
List<Node> toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream()
|
||||||
.filter(node -> node.shouldApplyWithContext(context))
|
.filter(node -> node.shouldApplyWithContext(LuckPermsService.convertContexts(contexts)))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
toRemove.forEach(n -> {
|
toRemove.forEach(n -> {
|
||||||
@ -159,7 +176,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
|
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
superClass.objectSave(holder);
|
objectSave(holder);
|
||||||
return !toRemove.isEmpty();
|
return !toRemove.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,9 +189,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Context> contexts = n.getExtraContexts().entrySet().stream()
|
Set<Context> contexts = LuckPermsService.convertContexts(n.getExtraContexts());
|
||||||
.map(entry -> new Context(entry.getKey(), entry.getValue()))
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
|
||||||
if (n.isServerSpecific()) {
|
if (n.isServerSpecific()) {
|
||||||
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
|
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
|
||||||
@ -200,14 +215,21 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Subject> getParents(Set<Context> contexts) {
|
public List<Subject> getParents(Set<Context> contexts) {
|
||||||
return getAllParents().getOrDefault(contexts, ImmutableList.of());
|
ImmutableList.Builder<Subject> parents = ImmutableList.builder();
|
||||||
|
|
||||||
|
(enduring ? holder.getNodes() : holder.getTransientNodes()).stream()
|
||||||
|
.filter(Node::isGroupNode)
|
||||||
|
.filter(n -> n.shouldApplyWithContext(LuckPermsService.convertContexts(contexts), true))
|
||||||
|
.forEach(n -> parents.add(service.getGroupSubjects().get(n.getGroupName())));
|
||||||
|
|
||||||
|
return parents.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean addParent(Set<Context> set, Subject subject) {
|
public boolean addParent(Set<Context> set, Subject subject) {
|
||||||
if (subject instanceof LuckPermsSubject) {
|
if (subject instanceof LuckPermsGroupSubject) {
|
||||||
LuckPermsSubject permsSubject = ((LuckPermsSubject) subject);
|
LuckPermsGroupSubject permsSubject = ((LuckPermsGroupSubject) subject);
|
||||||
Map<String, String> contexts = set.stream().collect(Collectors.toMap(Context::getKey, Context::getValue));
|
Map<String, String> contexts = LuckPermsService.convertContexts(set);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (enduring) {
|
if (enduring) {
|
||||||
@ -220,18 +242,18 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
} catch (ObjectAlreadyHasException ignored) {}
|
} catch (ObjectAlreadyHasException ignored) {}
|
||||||
superClass.objectSave(holder);
|
|
||||||
} else {
|
objectSave(holder);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeParent(Set<Context> set, Subject subject) {
|
public boolean removeParent(Set<Context> set, Subject subject) {
|
||||||
if (subject instanceof LuckPermsSubject) {
|
if (subject instanceof LuckPermsGroupSubject) {
|
||||||
LuckPermsSubject permsSubject = ((LuckPermsSubject) subject);
|
LuckPermsGroupSubject permsSubject = ((LuckPermsGroupSubject) subject);
|
||||||
Map<String, String> contexts = set.stream().collect(Collectors.toMap(Context::getKey, Context::getValue));
|
Map<String, String> contexts = LuckPermsService.convertContexts(set);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (enduring) {
|
if (enduring) {
|
||||||
@ -244,9 +266,9 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
} catch (ObjectLacksException ignored) {}
|
} catch (ObjectLacksException ignored) {}
|
||||||
superClass.objectSave(holder);
|
|
||||||
} else {
|
objectSave(holder);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -271,13 +293,14 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
|
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
superClass.objectSave(holder);
|
objectSave(holder);
|
||||||
return !toRemove.isEmpty();
|
return !toRemove.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean clearParents(Set<Context> set) {
|
public boolean clearParents(Set<Context> set) {
|
||||||
Map<String, String> context = set.stream().collect(Collectors.toMap(Context::getKey, Context::getValue));
|
Map<String, String> context = LuckPermsService.convertContexts(set);
|
||||||
|
|
||||||
List<Node> toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream()
|
List<Node> toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream()
|
||||||
.filter(Node::isGroupNode)
|
.filter(Node::isGroupNode)
|
||||||
.filter(node -> node.shouldApplyWithContext(context))
|
.filter(node -> node.shouldApplyWithContext(context))
|
||||||
@ -297,7 +320,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
|
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
superClass.objectSave(holder);
|
objectSave(holder);
|
||||||
return !toRemove.isEmpty();
|
return !toRemove.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,14 +328,19 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
public Map<Set<Context>, Map<String, String>> getAllOptions() {
|
public Map<Set<Context>, Map<String, String>> getAllOptions() {
|
||||||
Map<Set<Context>, Map<String, String>> options = new HashMap<>();
|
Map<Set<Context>, Map<String, String>> options = new HashMap<>();
|
||||||
|
|
||||||
|
int prefixPriority = Integer.MIN_VALUE;
|
||||||
|
int suffixPriority = Integer.MIN_VALUE;
|
||||||
|
|
||||||
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
|
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
|
||||||
if (!n.isMeta() && !n.isPrefix() && !n.isSuffix()) {
|
if (!n.getValue()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Context> contexts = n.getExtraContexts().entrySet().stream()
|
if (!n.isMeta() || !n.isPrefix() || n.isSuffix()) {
|
||||||
.map(entry -> new Context(entry.getKey(), entry.getValue()))
|
continue;
|
||||||
.collect(Collectors.toSet());
|
}
|
||||||
|
|
||||||
|
Set<Context> contexts = LuckPermsService.convertContexts(n.getExtraContexts());
|
||||||
|
|
||||||
if (n.isServerSpecific()) {
|
if (n.isServerSpecific()) {
|
||||||
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
|
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
|
||||||
@ -326,7 +354,28 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
options.put(contexts, new HashMap<>());
|
options.put(contexts, new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
options.get(contexts).put(unescapeCharacters(n.getMeta().getKey()), unescapeCharacters(n.getMeta().getValue()));
|
if (n.isPrefix()) {
|
||||||
|
Map.Entry<Integer, String> value = n.getPrefix();
|
||||||
|
if (value.getKey() > prefixPriority) {
|
||||||
|
options.get(contexts).put("prefix", value.getValue());
|
||||||
|
prefixPriority = value.getKey();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.isSuffix()) {
|
||||||
|
Map.Entry<Integer, String> value = n.getSuffix();
|
||||||
|
if (value.getKey() > suffixPriority) {
|
||||||
|
options.get(contexts).put("suffix", value.getValue());
|
||||||
|
suffixPriority = value.getKey();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.isMeta()) {
|
||||||
|
Map.Entry<String, String> meta = n.getMeta();
|
||||||
|
options.get(contexts).put(meta.getKey(), meta.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImmutableMap.Builder<Set<Context>, Map<String, String>> map = ImmutableMap.builder();
|
ImmutableMap.Builder<Set<Context>, Map<String, String>> map = ImmutableMap.builder();
|
||||||
@ -338,15 +387,55 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> getOptions(Set<Context> set) {
|
public Map<String, String> getOptions(Set<Context> set) {
|
||||||
return getAllOptions().getOrDefault(set, Collections.emptyMap());
|
ImmutableMap.Builder<String, String> options = ImmutableMap.builder();
|
||||||
|
Map<String, String> contexts = LuckPermsService.convertContexts(set);
|
||||||
|
|
||||||
|
int prefixPriority = Integer.MIN_VALUE;
|
||||||
|
int suffixPriority = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
|
||||||
|
if (!n.getValue()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!n.isMeta() || !n.isPrefix() || n.isSuffix()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!n.shouldApplyWithContext(contexts, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.isPrefix()) {
|
||||||
|
Map.Entry<Integer, String> value = n.getPrefix();
|
||||||
|
if (value.getKey() > prefixPriority) {
|
||||||
|
options.put("prefix", value.getValue());
|
||||||
|
prefixPriority = value.getKey();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.isSuffix()) {
|
||||||
|
Map.Entry<Integer, String> value = n.getSuffix();
|
||||||
|
if (value.getKey() > suffixPriority) {
|
||||||
|
options.put("suffix", value.getValue());
|
||||||
|
suffixPriority = value.getKey();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.isMeta()) {
|
||||||
|
Map.Entry<String, String> meta = n.getMeta();
|
||||||
|
options.put(meta.getKey(), meta.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return options.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setOption(Set<Context> set, String key, String value) {
|
public boolean setOption(Set<Context> set, String key, String value) {
|
||||||
Map<String, String> context = new HashMap<>();
|
Map<String, String> context = LuckPermsService.convertContexts(set);
|
||||||
for (Context c : set) {
|
|
||||||
context.put(c.getKey(), c.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
key = escapeCharacters(key);
|
key = escapeCharacters(key);
|
||||||
value = escapeCharacters(value);
|
value = escapeCharacters(value);
|
||||||
@ -364,13 +453,14 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (ObjectAlreadyHasException ignored) {}
|
} catch (ObjectAlreadyHasException ignored) {}
|
||||||
superClass.objectSave(holder);
|
objectSave(holder);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean clearOptions(Set<Context> set) {
|
public boolean clearOptions(Set<Context> set) {
|
||||||
Map<String, String> context = set.stream().collect(Collectors.toMap(Context::getKey, Context::getValue));
|
Map<String, String> context = LuckPermsService.convertContexts(set);
|
||||||
|
|
||||||
List<Node> toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream()
|
List<Node> toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream()
|
||||||
.filter(n -> n.isMeta() || n.isPrefix() || n.isSuffix())
|
.filter(n -> n.isMeta() || n.isPrefix() || n.isSuffix())
|
||||||
.filter(node -> node.shouldApplyWithContext(context))
|
.filter(node -> node.shouldApplyWithContext(context))
|
||||||
@ -386,7 +476,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
} catch (ObjectLacksException ignored) {}
|
} catch (ObjectLacksException ignored) {}
|
||||||
});
|
});
|
||||||
|
|
||||||
superClass.objectSave(holder);
|
objectSave(holder);
|
||||||
return !toRemove.isEmpty();
|
return !toRemove.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +496,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
|||||||
} catch (ObjectLacksException ignored) {}
|
} catch (ObjectLacksException ignored) {}
|
||||||
});
|
});
|
||||||
|
|
||||||
superClass.objectSave(holder);
|
objectSave(holder);
|
||||||
return !toRemove.isEmpty();
|
return !toRemove.isEmpty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,24 +22,26 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms.api.sponge;
|
package me.lucko.luckperms.api.sponge;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import me.lucko.luckperms.api.Contexts;
|
import me.lucko.luckperms.api.Contexts;
|
||||||
import me.lucko.luckperms.api.event.events.UserPermissionRefreshEvent;
|
import me.lucko.luckperms.caching.MetaData;
|
||||||
import me.lucko.luckperms.api.implementation.internal.UserLink;
|
|
||||||
import me.lucko.luckperms.users.User;
|
import me.lucko.luckperms.users.User;
|
||||||
import org.spongepowered.api.Sponge;
|
import org.spongepowered.api.Sponge;
|
||||||
import org.spongepowered.api.command.CommandSource;
|
import org.spongepowered.api.command.CommandSource;
|
||||||
import org.spongepowered.api.entity.living.player.Player;
|
import org.spongepowered.api.entity.living.player.Player;
|
||||||
import org.spongepowered.api.service.context.Context;
|
import org.spongepowered.api.service.context.Context;
|
||||||
|
import org.spongepowered.api.service.permission.Subject;
|
||||||
|
import org.spongepowered.api.service.permission.SubjectCollection;
|
||||||
import org.spongepowered.api.service.permission.SubjectData;
|
import org.spongepowered.api.service.permission.SubjectData;
|
||||||
import org.spongepowered.api.util.Tristate;
|
import org.spongepowered.api.util.Tristate;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class LuckPermsUserSubject extends LuckPermsSubject {
|
@EqualsAndHashCode(of = "user")
|
||||||
|
public class LuckPermsUserSubject implements Subject {
|
||||||
public static LuckPermsUserSubject wrapUser(User user, LuckPermsService service) {
|
public static LuckPermsUserSubject wrapUser(User user, LuckPermsService service) {
|
||||||
return new LuckPermsUserSubject(user, service);
|
return new LuckPermsUserSubject(user, service);
|
||||||
}
|
}
|
||||||
@ -47,92 +49,45 @@ public class LuckPermsUserSubject extends LuckPermsSubject {
|
|||||||
@Getter
|
@Getter
|
||||||
private User user;
|
private User user;
|
||||||
|
|
||||||
|
private LuckPermsService service;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private Map<Map<String, String>, ContextData> contextData;
|
private LuckPermsSubjectData subjectData;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private LuckPermsSubjectData transientSubjectData;
|
||||||
|
|
||||||
private LuckPermsUserSubject(User user, LuckPermsService service) {
|
private LuckPermsUserSubject(User user, LuckPermsService service) {
|
||||||
super(user, service);
|
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
this.service = service;
|
||||||
contextData = new ConcurrentHashMap<>();
|
this.subjectData = new LuckPermsSubjectData(true, service, user);
|
||||||
|
this.transientSubjectData = new LuckPermsSubjectData(false, service, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deprovision() {
|
public void deprovision() {
|
||||||
/* For some reason, Sponge holds onto User instances in a cache, which in turn, prevents LuckPerms data from being GCed.
|
/* For some reason, Sponge holds onto User instances in a cache, which in turn, prevents LuckPerms data from being GCed.
|
||||||
As well as unloading, we also remove all references to the User instances. */
|
As well as unloading, we also remove all references to the User instances. */
|
||||||
super.deprovision();
|
|
||||||
user = null;
|
user = null;
|
||||||
contextData = null;
|
service = null;
|
||||||
|
subjectData = null;
|
||||||
|
transientSubjectData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private Contexts calculateContexts(Set<Context> contexts) {
|
||||||
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String permission) {
|
return new Contexts(
|
||||||
Map<String, String> context = contexts.stream().collect(Collectors.toMap(Context::getKey, Context::getValue));
|
LuckPermsService.convertContexts(contexts),
|
||||||
ContextData cd = contextData.computeIfAbsent(context, map -> calculatePermissions(map, false));
|
service.getPlugin().getConfiguration().isIncludingGlobalPerms(),
|
||||||
|
service.getPlugin().getConfiguration().isIncludingGlobalWorldPerms(),
|
||||||
me.lucko.luckperms.api.Tristate t = cd.getPermissionValue(permission);
|
true,
|
||||||
if (t != me.lucko.luckperms.api.Tristate.UNDEFINED) {
|
service.getPlugin().getConfiguration().isApplyingGlobalGroups(),
|
||||||
return Tristate.fromBoolean(t.asBoolean());
|
service.getPlugin().getConfiguration().isApplyingGlobalWorldGroups()
|
||||||
} else {
|
|
||||||
return Tristate.UNDEFINED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContextData calculatePermissions(Map<String, String> context, boolean apply) {
|
|
||||||
Map<String, Boolean> toApply = user.exportNodes(
|
|
||||||
new Contexts(
|
|
||||||
context,
|
|
||||||
service.getPlugin().getConfiguration().isIncludingGlobalPerms(),
|
|
||||||
service.getPlugin().getConfiguration().isIncludingGlobalWorldPerms(),
|
|
||||||
true,
|
|
||||||
service.getPlugin().getConfiguration().isApplyingGlobalGroups(),
|
|
||||||
service.getPlugin().getConfiguration().isApplyingGlobalWorldGroups()
|
|
||||||
),
|
|
||||||
Collections.emptyList(),
|
|
||||||
true
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ContextData existing = contextData.get(context);
|
|
||||||
if (existing == null) {
|
|
||||||
existing = new ContextData(this, context, service);
|
|
||||||
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);
|
|
||||||
service.getPlugin().getApiProvider().fireEventAsync(new UserPermissionRefreshEvent(new UserLink(user)));
|
|
||||||
return existing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void calculatePermissions(Set<Context> contexts, boolean apply) {
|
private boolean hasData() {
|
||||||
Map<String, String> context = contexts.stream().collect(Collectors.toMap(Context::getKey, Context::getValue));
|
return user.getUserData() != null;
|
||||||
calculatePermissions(context, apply);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void calculateActivePermissions(boolean apply) {
|
|
||||||
calculatePermissions(getActiveContexts(), apply);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIdentifier() {
|
public String getIdentifier() {
|
||||||
return service.getPlugin().getUuidCache().getExternalUUID(user.getUuid()).toString();
|
return service.getPlugin().getUuidCache().getExternalUUID(user.getUuid()).toString();
|
||||||
@ -150,6 +105,82 @@ public class LuckPermsUserSubject extends LuckPermsSubject {
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SubjectCollection getContainingCollection() {
|
||||||
|
return service.getUserSubjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(Set<Context> contexts, String permission) {
|
||||||
|
return getPermissionValue(contexts, permission).asBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String permission) {
|
||||||
|
if (hasData()) {
|
||||||
|
return LuckPermsService.convertTristate(user.getUserData().getPermissionData(calculateContexts(contexts)).getPermissionValue(permission));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Tristate.UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject parent) {
|
||||||
|
return parent instanceof LuckPermsGroupSubject && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Subject> getParents(Set<Context> contexts) {
|
||||||
|
List<Subject> subjects = new ArrayList<>();
|
||||||
|
|
||||||
|
if (hasData()) {
|
||||||
|
for (String perm : user.getUserData().getPermissionData(calculateContexts(contexts)).getImmutableBacking().keySet()) {
|
||||||
|
if (!perm.startsWith("group.")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String groupName = perm.substring("group.".length());
|
||||||
|
if (service.getPlugin().getGroupManager().isLoaded(groupName)) {
|
||||||
|
subjects.add(service.getGroupSubjects().get(groupName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subjects.addAll(service.getUserSubjects().getDefaults().getParents(contexts));
|
||||||
|
subjects.addAll(service.getDefaults().getParents(contexts));
|
||||||
|
|
||||||
|
return subjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<String> getOption(Set<Context> contexts, String s) {
|
||||||
|
if (hasData()) {
|
||||||
|
MetaData data = user.getUserData().getMetaData(calculateContexts(contexts));
|
||||||
|
if (s.equalsIgnoreCase("prefix")) {
|
||||||
|
if (data.getPrefix() != null) {
|
||||||
|
return Optional.of(data.getPrefix());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.equalsIgnoreCase("suffix")) {
|
||||||
|
if (data.getSuffix() != null) {
|
||||||
|
return Optional.of(data.getSuffix());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.getMeta().containsKey(s)) {
|
||||||
|
return Optional.of(data.getMeta().get(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<String> v = service.getUserSubjects().getDefaults().getOption(contexts, s);
|
||||||
|
if (v.isPresent()) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return service.getDefaults().getOption(contexts, s);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Context> getActiveContexts() {
|
public Set<Context> getActiveContexts() {
|
||||||
final UUID uuid = service.getPlugin().getUuidCache().getExternalUUID(user.getUuid());
|
final UUID uuid = service.getPlugin().getUuidCache().getExternalUUID(user.getUuid());
|
||||||
|
@ -24,7 +24,7 @@ package me.lucko.luckperms.api.sponge.collections;
|
|||||||
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import me.lucko.luckperms.api.sponge.LuckPermsService;
|
import me.lucko.luckperms.api.sponge.LuckPermsService;
|
||||||
import me.lucko.luckperms.api.sponge.LuckPermsSubject;
|
import me.lucko.luckperms.api.sponge.LuckPermsGroupSubject;
|
||||||
import me.lucko.luckperms.api.sponge.simple.SimpleCollection;
|
import me.lucko.luckperms.api.sponge.simple.SimpleCollection;
|
||||||
import me.lucko.luckperms.groups.GroupManager;
|
import me.lucko.luckperms.groups.GroupManager;
|
||||||
import org.spongepowered.api.service.context.Context;
|
import org.spongepowered.api.service.context.Context;
|
||||||
@ -56,7 +56,7 @@ public class GroupCollection implements SubjectCollection {
|
|||||||
@Override
|
@Override
|
||||||
public Subject get(@NonNull String id) {
|
public Subject get(@NonNull String id) {
|
||||||
if (manager.isLoaded(id)) {
|
if (manager.isLoaded(id)) {
|
||||||
return LuckPermsSubject.wrapHolder(manager.get(id), service);
|
return LuckPermsGroupSubject.wrapGroup(manager.get(id), service);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fallback.get(id);
|
return fallback.get(id);
|
||||||
@ -70,7 +70,7 @@ public class GroupCollection implements SubjectCollection {
|
|||||||
@Override
|
@Override
|
||||||
public Iterable<Subject> getAllSubjects() {
|
public Iterable<Subject> getAllSubjects() {
|
||||||
return manager.getAll().values().stream()
|
return manager.getAll().values().stream()
|
||||||
.map(u -> LuckPermsSubject.wrapHolder(u, service))
|
.map(u -> LuckPermsGroupSubject.wrapGroup(u, service))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ public class GroupCollection implements SubjectCollection {
|
|||||||
@Override
|
@Override
|
||||||
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
|
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
|
||||||
return manager.getAll().values().stream()
|
return manager.getAll().values().stream()
|
||||||
.map(u -> LuckPermsSubject.wrapHolder(u, service))
|
.map(u -> LuckPermsGroupSubject.wrapGroup(u, service))
|
||||||
.filter(sub -> sub.isPermissionSet(contexts, node))
|
.filter(sub -> sub.isPermissionSet(contexts, node))
|
||||||
.collect(Collectors.toMap(sub -> sub, sub -> sub.getPermissionValue(contexts, node).asBoolean()));
|
.collect(Collectors.toMap(sub -> sub, sub -> sub.getPermissionValue(contexts, node).asBoolean()));
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,8 @@ import org.spongepowered.api.util.Tristate;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static me.lucko.luckperms.api.sponge.LuckPermsService.convertContexts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds SubjectData in a "gson friendly" format for serialization
|
* Holds SubjectData in a "gson friendly" format for serialization
|
||||||
*/
|
*/
|
||||||
@ -92,12 +94,4 @@ public class SimpleSubjectDataHolder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<String, String> convertContexts(Set<Context> contexts) {
|
|
||||||
return contexts.stream().collect(Collectors.toMap(Context::getKey, Context::getValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Set<Context> convertContexts(Map<String, String> contexts) {
|
|
||||||
return contexts.entrySet().stream().map(e -> new Context(e.getKey(), e.getValue())).collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,12 @@ package me.lucko.luckperms.calculators;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import me.lucko.luckperms.api.sponge.LuckPermsService;
|
import me.lucko.luckperms.api.sponge.LuckPermsService;
|
||||||
import org.spongepowered.api.service.context.Context;
|
import org.spongepowered.api.service.context.Context;
|
||||||
|
import org.spongepowered.api.util.Tristate;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static me.lucko.luckperms.api.sponge.LuckPermsService.convertTristate;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class DefaultsProcessor implements PermissionProcessor {
|
public class DefaultsProcessor implements PermissionProcessor {
|
||||||
private final LuckPermsService service;
|
private final LuckPermsService service;
|
||||||
@ -35,11 +38,16 @@ public class DefaultsProcessor implements PermissionProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public me.lucko.luckperms.api.Tristate hasPermission(String permission) {
|
public me.lucko.luckperms.api.Tristate hasPermission(String permission) {
|
||||||
org.spongepowered.api.util.Tristate t = service.getDefaults().getPermissionValue(contexts, permission);
|
Tristate t = service.getUserSubjects().getDefaults().getPermissionValue(contexts, permission);
|
||||||
if (t != org.spongepowered.api.util.Tristate.UNDEFINED) {
|
if (t != Tristate.UNDEFINED) {
|
||||||
return me.lucko.luckperms.api.Tristate.fromBoolean(t.asBoolean());
|
return convertTristate(Tristate.fromBoolean(t.asBoolean()));
|
||||||
} else {
|
|
||||||
return me.lucko.luckperms.api.Tristate.UNDEFINED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tristate t2 = service.getDefaults().getPermissionValue(contexts, permission);
|
||||||
|
if (t2 != Tristate.UNDEFINED) {
|
||||||
|
return convertTristate(Tristate.fromBoolean(t.asBoolean()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return me.lucko.luckperms.api.Tristate.UNDEFINED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,54 +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.LPSpongePlugin;
|
|
||||||
import me.lucko.luckperms.api.sponge.LuckPermsUserSubject;
|
|
||||||
import me.lucko.luckperms.api.sponge.collections.UserCollection;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
class SpongeUser extends User {
|
|
||||||
private final LPSpongePlugin plugin;
|
|
||||||
|
|
||||||
SpongeUser(UUID uuid, LPSpongePlugin plugin) {
|
|
||||||
super(uuid, plugin);
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
SpongeUser(UUID uuid, String username, LPSpongePlugin plugin) {
|
|
||||||
super(uuid, username, plugin);
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void refreshPermissions() {
|
|
||||||
UserCollection uc = plugin.getService().getUserSubjects();
|
|
||||||
if (!uc.getUsers().containsKey(getUuid())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LuckPermsUserSubject us = uc.getUsers().get(getUuid());
|
|
||||||
us.calculateActivePermissions(true);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +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.LPSpongePlugin;
|
|
||||||
import me.lucko.luckperms.api.context.ContextListener;
|
|
||||||
import org.spongepowered.api.entity.living.player.Player;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class SpongeUserManager extends UserManager implements ContextListener<Player> {
|
|
||||||
private final LPSpongePlugin plugin;
|
|
||||||
|
|
||||||
public SpongeUserManager(LPSpongePlugin plugin) {
|
|
||||||
super(plugin);
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cleanup(User user) {
|
|
||||||
if (!plugin.getGame().getServer().getPlayer(plugin.getUuidCache().getExternalUUID(user.getUuid())).isPresent()) {
|
|
||||||
unload(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void preUnload(User user) {
|
|
||||||
plugin.getService().getUserSubjects().unload(user.getUuid());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User apply(UserIdentifier id) {
|
|
||||||
SpongeUser user = id.getUsername() == null ?
|
|
||||||
new SpongeUser(id.getUuid(), plugin) :
|
|
||||||
new SpongeUser(id.getUuid(), id.getUsername(), plugin);
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateAllUsers() {
|
|
||||||
plugin.getGame().getServer().getOnlinePlayers().stream()
|
|
||||||
.map(p -> plugin.getUuidCache().getUUID(p.getUniqueId()))
|
|
||||||
.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 {
|
|
||||||
// Not needed on Sponge. The context is accumulated on each permission check.
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user