mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-11-24 03:25:19 +01:00
Apply PermissionAttachment permissions at a higher priority than normal nodes using the transient system (#515)
This commit is contained in:
parent
1baefaade4
commit
f109cb684a
@ -173,7 +173,7 @@ public class BukkitListener implements Listener {
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
plugin.refreshAutoOp(player);
|
||||
plugin.refreshAutoOp(user, player);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
@ -201,7 +201,7 @@ public class BukkitListener implements Listener {
|
||||
}
|
||||
|
||||
// everything is going well. login was processed ok, this is just to refresh auto-op status.
|
||||
plugin.refreshAutoOp(e.getPlayer());
|
||||
plugin.refreshAutoOp(plugin.getUserManager().getIfLoaded(e.getPlayer().getUniqueId()), e.getPlayer());
|
||||
}
|
||||
|
||||
// Wait until the last priority to unload, so plugins can still perform permission checks on this event
|
||||
@ -252,6 +252,6 @@ public class BukkitListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onWorldChange(PlayerChangedWorldEvent e) {
|
||||
plugin.getContextManager().invalidateCache(e.getPlayer());
|
||||
plugin.refreshAutoOp(e.getPlayer());
|
||||
plugin.refreshAutoOp(plugin.getUserManager().getIfLoaded(e.getPlayer().getUniqueId()), e.getPlayer());
|
||||
}
|
||||
}
|
||||
|
@ -402,23 +402,15 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshAutoOp(Player player) {
|
||||
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
try {
|
||||
LPPermissible permissible = Injector.getPermissible(player.getUniqueId());
|
||||
if (permissible == null || !permissible.getActive().get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
User user = permissible.getUser();
|
||||
public void refreshAutoOp(User user, Player player) {
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Boolean> backing = user.getUserData().getPermissionData(permissible.calculateContexts()).getImmutableBacking();
|
||||
if (getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
Map<String, Boolean> backing = user.getUserData().getPermissionData(contextManager.getApplicableContexts(player)).getImmutableBacking();
|
||||
boolean op = Optional.ofNullable(backing.get("luckperms.autoop")).orElse(false);
|
||||
player.setOp(op);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,6 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.bukkit.model.Injector;
|
||||
import me.lucko.luckperms.bukkit.model.LPPermissible;
|
||||
import me.lucko.luckperms.bukkit.processors.AttachmentProcessor;
|
||||
import me.lucko.luckperms.bukkit.processors.ChildProcessor;
|
||||
import me.lucko.luckperms.bukkit.processors.DefaultsProcessor;
|
||||
import me.lucko.luckperms.common.calculators.AbstractCalculatorFactory;
|
||||
@ -47,7 +44,6 @@ import me.lucko.luckperms.common.processors.RegexProcessor;
|
||||
import me.lucko.luckperms.common.processors.WildcardProcessor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
@ -63,14 +59,6 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory {
|
||||
processors.add(new ChildProcessor(plugin.getChildPermissionProvider()));
|
||||
}
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_ATTACHMENT_PERMISSIONS)) {
|
||||
final UUID uuid = plugin.getUuidCache().getExternalUUID(user.getUuid());
|
||||
processors.add(new AttachmentProcessor(() -> {
|
||||
LPPermissible permissible = Injector.getPermissible(uuid);
|
||||
return permissible == null ? null : permissible.getAttachmentPermissions();
|
||||
}));
|
||||
}
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) {
|
||||
processors.add(new RegexProcessor());
|
||||
}
|
||||
|
@ -45,63 +45,17 @@ public class DummyPermissible implements Permissible {
|
||||
onRefresh.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(String name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(Permission perm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Permission perm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttachment(PermissionAttachment attachment) {
|
||||
@Override public Set<PermissionAttachmentInfo> getEffectivePermissions() { return Collections.emptySet(); }
|
||||
@Override public boolean isPermissionSet(String name) { return false; }
|
||||
@Override public boolean isPermissionSet(Permission perm) { return false; }
|
||||
@Override public boolean hasPermission(String name) { return false; }
|
||||
@Override public boolean hasPermission(Permission perm) { return false; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, int ticks) { return null; }
|
||||
@Override public void removeAttachment(PermissionAttachment attachment) {}
|
||||
@Override public boolean isOp() { return false; }
|
||||
@Override public void setOp(boolean value) {}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOp(boolean value) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -35,77 +35,25 @@ import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class DummyPermissibleBase extends PermissibleBase {
|
||||
public DummyPermissibleBase() {
|
||||
public static final DummyPermissibleBase INSTANCE = new DummyPermissibleBase();
|
||||
|
||||
private DummyPermissibleBase() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOp(boolean value) {
|
||||
@Override public boolean isOp() { return false; }
|
||||
@Override public void setOp(boolean value) {}
|
||||
@Override public boolean isPermissionSet(String name) { return false; }
|
||||
@Override public boolean isPermissionSet(Permission perm) { return false; }
|
||||
@Override public boolean hasPermission(String inName) { return false; }
|
||||
@Override public boolean hasPermission(Permission perm) { return false; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin) { return null; }
|
||||
@Override public void removeAttachment(PermissionAttachment attachment) {}
|
||||
@Override public void recalculatePermissions() {}
|
||||
@Override public void clearPermissions() {}
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) { return null; }
|
||||
@Override public PermissionAttachment addAttachment(Plugin plugin, int ticks) { return null; }
|
||||
@Override public Set<PermissionAttachmentInfo> getEffectivePermissions() { return Collections.emptySet(); }
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(String name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermissionSet(Permission perm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String inName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Permission perm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttachment(PermissionAttachment attachment) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recalculatePermissions() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void clearPermissions() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Dummy plugin instance
|
||||
*/
|
||||
public class DummyPlugin implements Plugin {
|
||||
public static final DummyPlugin INSTANCE = new DummyPlugin();
|
||||
|
||||
private DummyPlugin() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public File getDataFolder() { return null; }
|
||||
@Override public PluginDescriptionFile getDescription() { return null; }
|
||||
@Override public FileConfiguration getConfig() { return null; }
|
||||
@Override public InputStream getResource(String s) { return null; }
|
||||
@Override public void saveConfig() {}
|
||||
@Override public void saveDefaultConfig() {}
|
||||
@Override public void saveResource(String s, boolean b) {}
|
||||
@Override public void reloadConfig() {}
|
||||
@Override public PluginLoader getPluginLoader() { return null; }
|
||||
@Override public Server getServer() { return null; }
|
||||
@Override public void onDisable() {}
|
||||
@Override public void onLoad() {}
|
||||
@Override public void onEnable() {}
|
||||
@Override public boolean isNaggable() { return false; }
|
||||
@Override public void setNaggable(boolean b) {}
|
||||
@Override public ChunkGenerator getDefaultWorldGenerator(String s, String s1) { return null; }
|
||||
@Override public Logger getLogger() { return null; }
|
||||
@Override public String getName() { return null; }
|
||||
@Override public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) { return false; }
|
||||
@Override public List<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] strings) { return null; }
|
||||
|
||||
}
|
@ -116,13 +116,12 @@ public class Injector {
|
||||
//noinspection unchecked
|
||||
List<PermissionAttachment> attachments = (List<PermissionAttachment>) PERMISSIBLE_BASE_ATTACHMENTS_FIELD.get(oldPermissible);
|
||||
|
||||
newPermissible.addAttachments(attachments);
|
||||
newPermissible.convertAndAddAttachments(attachments);
|
||||
attachments.clear();
|
||||
oldPermissible.clearPermissions();
|
||||
|
||||
// Setup the new permissible
|
||||
newPermissible.getActive().set(true);
|
||||
newPermissible.recalculatePermissions(false);
|
||||
newPermissible.setOldPermissible(oldPermissible);
|
||||
newPermissible.updateSubscriptionsAsync();
|
||||
|
||||
@ -164,23 +163,14 @@ public class Injector {
|
||||
// handle the replacement permissible.
|
||||
if (dummy) {
|
||||
// just inject a dummy class. this is used when we know the player is about to quit the server.
|
||||
HUMAN_ENTITY_PERMISSIBLE_FIELD.set(player, new DummyPermissibleBase());
|
||||
HUMAN_ENTITY_PERMISSIBLE_FIELD.set(player, DummyPermissibleBase.INSTANCE);
|
||||
|
||||
} else {
|
||||
// otherwise, inject the permissible they had when we first injected.
|
||||
|
||||
List<PermissionAttachment> lpAttachments = lpPermissible.getAttachments();
|
||||
|
||||
PermissibleBase newPb = lpPermissible.getOldPermissible();
|
||||
if (newPb == null) {
|
||||
newPb = new PermissibleBase(player);
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
List<PermissionAttachment> newPbAttachments = (List<PermissionAttachment>) PERMISSIBLE_BASE_ATTACHMENTS_FIELD.get(newPb);
|
||||
newPbAttachments.addAll(lpAttachments);
|
||||
lpAttachments.clear();
|
||||
|
||||
HUMAN_ENTITY_PERMISSIBLE_FIELD.set(player, newPb);
|
||||
}
|
||||
}
|
||||
|
@ -37,25 +37,19 @@ import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.permissions.PermissionRemovedExecutor;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -94,12 +88,9 @@ public class LPPermissible extends PermissibleBase {
|
||||
// if the permissible is currently active.
|
||||
private final AtomicBoolean active = new AtomicBoolean(false);
|
||||
|
||||
// the permissions registered by PermissionAttachments.
|
||||
// stored in this format, as that's what is used by #getEffectivePermissions
|
||||
private final Map<String, PermissionAttachmentInfo> attachmentPermissions = new ConcurrentHashMap<>();
|
||||
|
||||
// the attachments hooked onto the permissible.
|
||||
private final List<PermissionAttachment> attachments = Collections.synchronizedList(new ArrayList<>());
|
||||
// this collection is only modified by the attachments themselves
|
||||
final Set<LPPermissionAttachment> attachments = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public LPPermissible(@NonNull Player parent, @NonNull User user, @NonNull LPBukkitPlugin plugin) {
|
||||
super(parent);
|
||||
@ -204,8 +195,10 @@ public class LPPermissible extends PermissibleBase {
|
||||
*
|
||||
* @param attachments the attachments to add
|
||||
*/
|
||||
public void addAttachments(Collection<PermissionAttachment> attachments) {
|
||||
this.attachments.addAll(attachments);
|
||||
public void convertAndAddAttachments(Collection<PermissionAttachment> attachments) {
|
||||
for (PermissionAttachment attachment : attachments) {
|
||||
new LPPermissionAttachment(this, attachment).hook();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,135 +219,70 @@ public class LPPermissible extends PermissibleBase {
|
||||
@Override
|
||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
perms.addAll(attachmentPermissions.values());
|
||||
|
||||
perms.addAll(
|
||||
user.getUserData().getPermissionData(calculateContexts()).getImmutableBacking().entrySet().stream()
|
||||
.map(e -> new PermissionAttachmentInfo(parent, e.getKey(), null, e.getValue()))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String name, boolean value) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
|
||||
}
|
||||
|
||||
PermissionAttachment result = addAttachment(plugin);
|
||||
result.setPermission(name, value);
|
||||
|
||||
recalculatePermissions();
|
||||
|
||||
return result;
|
||||
public LPPermissionAttachment addAttachment(Plugin plugin) {
|
||||
LPPermissionAttachment ret = new LPPermissionAttachment(this, plugin);
|
||||
ret.hook();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(@NonNull Plugin plugin) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
|
||||
}
|
||||
|
||||
PermissionAttachment result = new PermissionAttachment(plugin, parent);
|
||||
|
||||
attachments.add(result);
|
||||
recalculatePermissions();
|
||||
|
||||
return result;
|
||||
public PermissionAttachment addAttachment(Plugin plugin, @NonNull String name, boolean value) {
|
||||
PermissionAttachment ret = addAttachment(plugin);
|
||||
ret.setPermission(name, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(@NonNull Plugin plugin, @NonNull String name, boolean value, int ticks) {
|
||||
public LPPermissionAttachment addAttachment(@NonNull Plugin plugin, int ticks) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
|
||||
}
|
||||
|
||||
PermissionAttachment result = addAttachment(plugin, ticks);
|
||||
if (result != null) {
|
||||
result.setPermission(name, value);
|
||||
LPPermissionAttachment ret = addAttachment(plugin);
|
||||
if (getPlugin().getServer().getScheduler().scheduleSyncDelayedTask(plugin, ret::remove, ticks) == -1) {
|
||||
ret.remove();
|
||||
throw new RuntimeException("Could not add PermissionAttachment to " + parent + " for plugin " + plugin.getDescription().getFullName() + ": Scheduler returned -1");
|
||||
}
|
||||
|
||||
return result;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionAttachment addAttachment(@NonNull Plugin plugin, int ticks) {
|
||||
if (!plugin.isEnabled()) {
|
||||
throw new IllegalArgumentException("Plugin " + plugin.getDescription().getFullName() + " is not enabled");
|
||||
}
|
||||
|
||||
PermissionAttachment result = addAttachment(plugin);
|
||||
if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, result::remove, ticks) == -1) {
|
||||
Bukkit.getServer().getLogger().log(Level.WARNING, "Could not add PermissionAttachment to " + parent + " for plugin " + plugin.getDescription().getFullName() + ": Scheduler returned -1");
|
||||
result.remove();
|
||||
return null;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
public LPPermissionAttachment addAttachment(Plugin plugin, @NonNull String name, boolean value, int ticks) {
|
||||
LPPermissionAttachment ret = addAttachment(plugin, ticks);
|
||||
ret.setPermission(name, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttachment(@NonNull PermissionAttachment attachment) {
|
||||
if (attachments.contains(attachment)) {
|
||||
attachments.remove(attachment);
|
||||
PermissionRemovedExecutor ex = attachment.getRemovalCallback();
|
||||
|
||||
if (ex != null) {
|
||||
ex.attachmentRemoved(attachment);
|
||||
if (!(attachment instanceof LPPermissionAttachment)) {
|
||||
throw new IllegalArgumentException("Given attachment is not a LPPermissionAttachment.");
|
||||
}
|
||||
|
||||
recalculatePermissions();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Given attachment is not part of Permissible object " + parent);
|
||||
LPPermissionAttachment a = ((LPPermissionAttachment) attachment);
|
||||
if (a.getPermissible() != this) {
|
||||
throw new IllegalArgumentException("Attachment does not belong to this permissible.");
|
||||
}
|
||||
|
||||
a.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recalculatePermissions() {
|
||||
recalculatePermissions(true);
|
||||
}
|
||||
|
||||
public void recalculatePermissions(boolean invalidate) {
|
||||
if (attachmentPermissions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
attachmentPermissions.clear();
|
||||
|
||||
for (PermissionAttachment attachment : attachments) {
|
||||
calculateChildPermissions(attachment.getPermissions(), false, attachment);
|
||||
}
|
||||
|
||||
if (invalidate) {
|
||||
user.getUserData().invalidatePermissionCalculators();
|
||||
}
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void clearPermissions() {
|
||||
Set<String> perms = attachmentPermissions.keySet();
|
||||
|
||||
for (String name : perms) {
|
||||
Bukkit.getServer().getPluginManager().unsubscribeFromPermission(name, parent);
|
||||
}
|
||||
|
||||
attachmentPermissions.clear();
|
||||
}
|
||||
|
||||
private void calculateChildPermissions(Map<String, Boolean> children, boolean invert, PermissionAttachment attachment) {
|
||||
for (Map.Entry<String, Boolean> e : children.entrySet()) {
|
||||
Permission perm = Bukkit.getServer().getPluginManager().getPermission(e.getKey());
|
||||
boolean value = e.getValue() ^ invert;
|
||||
String name = e.getKey().toLowerCase();
|
||||
|
||||
attachmentPermissions.put(name, new PermissionAttachmentInfo(parent, name, attachment, value));
|
||||
Bukkit.getServer().getPluginManager().subscribeToPermission(name, parent);
|
||||
|
||||
if (perm != null) {
|
||||
calculateChildPermissions(perm.getChildren(), !value, attachment);
|
||||
}
|
||||
}
|
||||
public void clearPermissions() {
|
||||
attachments.forEach(LPPermissionAttachment::remove);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.node.ImmutableTransientNode;
|
||||
import me.lucko.luckperms.common.node.NodeFactory;
|
||||
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.bukkit.permissions.PermissionRemovedExecutor;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* PermissionAttachment for LuckPerms.
|
||||
*
|
||||
* Applies all permissions directly to the backing user instance via transient nodes.
|
||||
*/
|
||||
public class LPPermissionAttachment extends PermissionAttachment {
|
||||
|
||||
/**
|
||||
* The parent LPPermissible
|
||||
*/
|
||||
@Getter
|
||||
private final LPPermissible permissible;
|
||||
|
||||
/**
|
||||
* The plugin which "owns" this attachment, may be null
|
||||
*/
|
||||
private final Plugin owner;
|
||||
|
||||
/**
|
||||
* The permissions being applied by this attachment
|
||||
*/
|
||||
private final Map<String, Boolean> perms = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
/**
|
||||
* If the attachment has been applied to the user
|
||||
*/
|
||||
private boolean hooked = false;
|
||||
|
||||
/**
|
||||
* Callback to run when the attachment is removed
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private PermissionRemovedExecutor removalCallback = null;
|
||||
|
||||
public LPPermissionAttachment(LPPermissible permissible, Plugin owner) {
|
||||
super(DummyPlugin.INSTANCE, null);
|
||||
this.permissible = permissible;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public LPPermissionAttachment(LPPermissible permissible, PermissionAttachment bukkit) {
|
||||
super(DummyPlugin.INSTANCE, null);
|
||||
this.permissible = permissible;
|
||||
this.owner = null;
|
||||
|
||||
// copy
|
||||
perms.putAll(bukkit.getPermissions());
|
||||
}
|
||||
|
||||
public void hook() {
|
||||
hooked = true;
|
||||
permissible.attachments.add(this);
|
||||
for (Map.Entry<String, Boolean> entry : perms.entrySet()) {
|
||||
setPermissionInternal(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void setPermissionInternal(String name, boolean value) {
|
||||
if (!permissible.getPlugin().getConfiguration().get(ConfigKeys.APPLY_BUKKIT_ATTACHMENT_PERMISSIONS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImmutableTransientNode node = ImmutableTransientNode.of(NodeFactory.make(name, value), this);
|
||||
if (permissible.getUser().setTransientPermission(node).asBoolean()) {
|
||||
permissible.getUser().getRefreshBuffer().request();
|
||||
}
|
||||
}
|
||||
|
||||
private void unsetPermissionInternal(String name) {
|
||||
if (!permissible.getPlugin().getConfiguration().get(ConfigKeys.APPLY_BUKKIT_ATTACHMENT_PERMISSIONS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (permissible.getUser().removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name))) {
|
||||
permissible.getUser().getRefreshBuffer().request();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove() {
|
||||
if (!hooked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissible.getUser().removeIfTransient(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this)) {
|
||||
permissible.getUser().getRefreshBuffer().request();
|
||||
}
|
||||
|
||||
if (removalCallback != null) {
|
||||
removalCallback.attachmentRemoved(this);
|
||||
}
|
||||
|
||||
hooked = false;
|
||||
permissible.attachments.remove(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(String name, boolean value) {
|
||||
Boolean previous = perms.put(name, value);
|
||||
if (previous != null && previous == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hooked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (previous != null) {
|
||||
unsetPermissionInternal(name);
|
||||
}
|
||||
|
||||
setPermissionInternal(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(String name) {
|
||||
Boolean previous = perms.remove(name);
|
||||
if (previous == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hooked) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsetPermissionInternal(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getPermissions() {
|
||||
return perms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plugin getPlugin() {
|
||||
return owner != null ? owner : permissible.getPlugin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
}
|
@ -23,42 +23,39 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.bukkit.processors;
|
||||
package me.lucko.luckperms.common.node;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Delegate;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.common.processors.PermissionProcessor;
|
||||
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
|
||||
/**
|
||||
* Permission Processor for permissions set to a player via permission attachments.
|
||||
* Holds a Node and plus an owning object. All calls are passed onto the contained Node instance.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class AttachmentProcessor implements PermissionProcessor {
|
||||
|
||||
@Getter
|
||||
private final Supplier<Map<String, PermissionAttachmentInfo>> map;
|
||||
|
||||
@Override
|
||||
public Tristate hasPermission(String permission) {
|
||||
Map<String, PermissionAttachmentInfo> m = map.get();
|
||||
if (m == null) {
|
||||
return Tristate.UNDEFINED;
|
||||
@ToString
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class ImmutableTransientNode implements Node {
|
||||
public static ImmutableTransientNode of(@NonNull Node node, @NonNull Object owner) {
|
||||
return new ImmutableTransientNode(node, owner);
|
||||
}
|
||||
|
||||
PermissionAttachmentInfo pai = m.get(permission);
|
||||
return pai == null ? Tristate.UNDEFINED : Tristate.fromBoolean(pai.getValue());
|
||||
@Delegate
|
||||
private final Node node;
|
||||
private final Object owner;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return node.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBacking(Map<String, Boolean> map) {
|
||||
// Do nothing, this doesn't use the backing
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj || node.equals(obj);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user