diff --git a/api/src/main/java/me/lucko/luckperms/api/context/IContextCalculator.java b/api/src/main/java/me/lucko/luckperms/api/context/IContextCalculator.java index 754483d4..20e0b687 100644 --- a/api/src/main/java/me/lucko/luckperms/api/context/IContextCalculator.java +++ b/api/src/main/java/me/lucko/luckperms/api/context/IContextCalculator.java @@ -22,7 +22,6 @@ package me.lucko.luckperms.api.context; -import java.util.HashMap; import java.util.Map; /** @@ -40,37 +39,9 @@ public interface IContextCalculator { * @param subject the subject to add contexts to * @param accumulator a map of contexts to add to * @return the map - * @deprecated in favour of {@link #giveApplicableContext(Object, MutableContextSet)}. Older implementations of this - * interface will still work, as the replacement method is given as a default, and falls back to using this method. - */ - @Deprecated - default Map giveApplicableContext(T subject, Map accumulator) { - MutableContextSet acc = new MutableContextSet(); - giveApplicableContext(subject, acc); - - accumulator.putAll(acc.toMap()); - return accumulator; - } - - /** - * Gives the subject all of the applicable contexts they meet - * - *

You MUST implement this method. The default is only provided for backwards compatibility with - * {@link #giveApplicableContext(Object, Map)}. - * - * @param subject the subject to add contexts to - * @param accumulator a map of contexts to add to - * @return the map * @since 2.13 */ - @SuppressWarnings("deprecation") - default MutableContextSet giveApplicableContext(T subject, MutableContextSet accumulator) { - Map acc = new HashMap<>(); - giveApplicableContext(subject, acc); - - accumulator.addAll(acc.entrySet()); - return accumulator; - } + MutableContextSet giveApplicableContext(T subject, MutableContextSet accumulator); /** * Checks to see if a context is applicable to a subject diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java index 5eaad0f5..dfc4148c 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -391,6 +391,14 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { } } + @Override + public void onUserRefresh(User user) { + LPPermissible lpp = Injector.getPermissible(uuidCache.getExternalUUID(user.getUuid())); + if (lpp != null) { + lpp.updateSubscriptions(); + } + } + @Override public void doAsync(Runnable r) { asyncExecutor.execute(r); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/inject/Injector.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/inject/Injector.java index 3a3562ec..1354f045 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/inject/Injector.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/inject/Injector.java @@ -77,6 +77,8 @@ public class Injector { lpPermissible.recalculatePermissions(); lpPermissible.setOldPermissible(existing); + lpPermissible.updateSubscriptionsAsync(); + HUMAN_ENTITY_FIELD.set(player, lpPermissible); INJECTED_PERMISSIBLES.put(player.getUniqueId(), lpPermissible); return true; @@ -90,6 +92,10 @@ public class Injector { try { PermissibleBase permissible = (PermissibleBase) HUMAN_ENTITY_FIELD.get(player); if (permissible instanceof LPPermissible) { + + permissible.clearPermissions(); + ((LPPermissible) permissible).unsubscribeFromAllAsync(); + if (dummy) { HUMAN_ENTITY_FIELD.set(player, new DummyPermissibleBase()); } else { @@ -104,7 +110,6 @@ public class Injector { List newAttachments = (List) PERMISSIBLEBASE_ATTACHMENTS.get(newPb); newAttachments.addAll(attachments); attachments.clear(); - lpp.clearPermissions(); HUMAN_ENTITY_FIELD.set(player, newPb); } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPPermissible.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPPermissible.java index 067b0711..63dc4b8f 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPPermissible.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/LPPermissible.java @@ -61,8 +61,12 @@ public class LPPermissible extends PermissibleBase { @Getter private final Player parent; + @Getter private final LPBukkitPlugin plugin; + @Getter + private final SubscriptionManager subscriptions; + @Getter @Setter private PermissibleBase oldPermissible = null; @@ -78,10 +82,28 @@ public class LPPermissible extends PermissibleBase { this.user = user; this.parent = parent; this.plugin = plugin; + this.subscriptions = new SubscriptionManager(this); recalculatePermissions(); } + public void updateSubscriptionsAsync() { + plugin.doAsync(this::updateSubscriptions); + } + + public void updateSubscriptions() { + Set ent = user.getUserData().getPermissionData(calculateContexts()).getImmutableBacking().keySet(); + subscriptions.subscribe(ent); + } + + public void unsubscribeFromAllAsync() { + plugin.doAsync(this::unsubscribeFromAll); + } + + public void unsubscribeFromAll() { + subscriptions.subscribe(Collections.emptySet()); + } + public void addAttachments(List attachments) { for (PermissionAttachment attachment : attachments) { this.attachments.add(attachment); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionManager.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionManager.java new file mode 100644 index 00000000..85cbd0e9 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/SubscriptionManager.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.bukkit.model; + +import lombok.RequiredArgsConstructor; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +@RequiredArgsConstructor +public class SubscriptionManager { + + private final LPPermissible permissible; + private Set currentSubscriptions = ImmutableSet.of(); + + public synchronized void subscribe(Set perms) { + Set newPerms = ImmutableSet.copyOf(perms); + + Map.Entry, Set> changes = compareSets(newPerms, currentSubscriptions); + + Set toAdd = changes.getKey(); + Set toRemove = changes.getValue(); + + permissible.getPlugin().doSync(() -> { + for (String s : toAdd) { + permissible.getPlugin().getServer().getPluginManager().subscribeToPermission(s, permissible.getParent()); + } + for (String s : toRemove) { + permissible.getPlugin().getServer().getPluginManager().unsubscribeFromPermission(s, permissible.getParent()); + } + }); + + this.currentSubscriptions = newPerms; + } + + /** + * Compares two sets + * @param local the local set + * @param remote the remote set + * @return the entries to add to remote, and the entries to remove from remote + */ + private static Map.Entry, Set> compareSets(Set local, Set remote) { + // entries in local but not remote need to be added + // entries in remote but not local need to be removed + + Set toAdd = new HashSet<>(local); + toAdd.removeAll(remote); + + Set toRemove = new HashSet<>(remote); + toRemove.removeAll(local); + + return Maps.immutableEntry(toAdd, toRemove); + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java index 85e2c5ea..44ae5006 100644 --- a/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java +++ b/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java @@ -394,4 +394,13 @@ public interface LuckPermsPlugin { } + /** + * Called when a users data is refreshed + * + * @param user the user + */ + default void onUserRefresh(User user) { + + } + } diff --git a/common/src/main/java/me/lucko/luckperms/common/core/model/User.java b/common/src/main/java/me/lucko/luckperms/common/core/model/User.java index 159d52ba..6c036d19 100644 --- a/common/src/main/java/me/lucko/luckperms/common/core/model/User.java +++ b/common/src/main/java/me/lucko/luckperms/common/core/model/User.java @@ -117,6 +117,7 @@ public class User extends PermissionHolder implements Identifiable