Add workaround for plugins adding/removing/modifying permission attachments via reflection (#1024)

who knows why they're doing it, it's not even beneficial for performance...
This commit is contained in:
Luck 2018-05-30 13:17:41 +01:00
parent c66622bd09
commit 644c53a074
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
11 changed files with 361 additions and 43 deletions

View File

@ -64,6 +64,19 @@ public class DummyPermissibleBase extends PermissibleBase {
} }
} }
public static void copyFields(PermissibleBase from, PermissibleBase to) {
try {
ATTACHMENTS_FIELD.set(to, ATTACHMENTS_FIELD.get(from));
} catch (Exception e) {
// ignore
}
try {
PERMISSIONS_FIELD.set(to, PERMISSIONS_FIELD.get(from));
} catch (Exception e) {
// ignore
}
}
public static final DummyPermissibleBase INSTANCE = new DummyPermissibleBase(); public static final DummyPermissibleBase INSTANCE = new DummyPermissibleBase();
private DummyPermissibleBase() { private DummyPermissibleBase() {

View File

@ -25,11 +25,14 @@
package me.lucko.luckperms.bukkit.model.permissible; package me.lucko.luckperms.bukkit.model.permissible;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.Tristate; import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.bukkit.LPBukkitPlugin; import me.lucko.luckperms.bukkit.LPBukkitPlugin;
import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.contexts.ContextsCache; import me.lucko.luckperms.common.contexts.ContextsCache;
import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.common.verbose.CheckOrigin; import me.lucko.luckperms.common.verbose.CheckOrigin;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -39,14 +42,18 @@ import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo; import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.lang.reflect.Field;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.Iterator;
import java.util.Map; import java.util.List;
import java.util.ListIterator;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nonnull;
/** /**
* PermissibleBase for LuckPerms. * PermissibleBase for LuckPerms.
* *
@ -63,6 +70,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/ */
public class LPPermissible extends PermissibleBase { public class LPPermissible extends PermissibleBase {
private static final Field ATTACHMENTS_FIELD;
static {
try {
ATTACHMENTS_FIELD = PermissibleBase.class.getDeclaredField("attachments");
ATTACHMENTS_FIELD.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new ExceptionInInitializerError(e);
}
}
// the LuckPerms user this permissible references. // the LuckPerms user this permissible references.
private final User user; private final User user;
@ -83,7 +101,7 @@ public class LPPermissible extends PermissibleBase {
// the attachments hooked onto the permissible. // the attachments hooked onto the permissible.
// this collection is only modified by the attachments themselves // this collection is only modified by the attachments themselves
final Set<LPPermissionAttachment> attachments = ConcurrentHashMap.newKeySet(); final Set<LPPermissionAttachment> lpAttachments = ConcurrentHashMap.newKeySet();
public LPPermissible(Player player, User user, LPBukkitPlugin plugin) { public LPPermissible(Player player, User user, LPBukkitPlugin plugin) {
super(player); super(player);
@ -91,6 +109,26 @@ public class LPPermissible extends PermissibleBase {
this.player = Objects.requireNonNull(player, "player"); this.player = Objects.requireNonNull(player, "player");
this.plugin = Objects.requireNonNull(plugin, "plugin"); this.plugin = Objects.requireNonNull(plugin, "plugin");
this.contextsCache = plugin.getContextManager().getCacheFor(player); this.contextsCache = plugin.getContextManager().getCacheFor(player);
injectFakeAttachmentsList();
}
/**
* Injects a fake 'attachments' list into the superclass, for dumb plugins
* which for some reason decided to add attachments via reflection.
*
* The fake list proxies (some) calls back to the proper methods on this permissible.
*/
private void injectFakeAttachmentsList() {
FakeAttachmentList fakeList = new FakeAttachmentList();
try {
// the field we need to modify is in the superclass - it has private
// and final modifiers so we have to use reflection to modify it.
ATTACHMENTS_FIELD.set(this, fakeList);
} catch (Exception e) {
e.printStackTrace();
}
} }
@Override @Override
@ -154,7 +192,7 @@ public class LPPermissible extends PermissibleBase {
* *
* @param attachments the attachments to add * @param attachments the attachments to add
*/ */
public void convertAndAddAttachments(Collection<PermissionAttachment> attachments) { void convertAndAddAttachments(Collection<PermissionAttachment> attachments) {
for (PermissionAttachment attachment : attachments) { for (PermissionAttachment attachment : attachments) {
new LPPermissionAttachment(this, attachment).hook(); new LPPermissionAttachment(this, attachment).hook();
} }
@ -167,14 +205,9 @@ public class LPPermissible extends PermissibleBase {
@Override @Override
public Set<PermissionAttachmentInfo> getEffectivePermissions() { public Set<PermissionAttachmentInfo> getEffectivePermissions() {
Set<Map.Entry<String, Boolean>> permissions = this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getImmutableBacking().entrySet(); return this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getImmutableBacking().entrySet().stream()
Set<PermissionAttachmentInfo> ret = new HashSet<>(permissions.size()); .map(entry -> new PermissionAttachmentInfo(this.player, entry.getKey(), null, entry.getValue()))
.collect(ImmutableCollectors.toSet());
for (Map.Entry<String, Boolean> entry : permissions) {
ret.add(new PermissionAttachmentInfo(this.player, entry.getKey(), null, entry.getValue()));
}
return ret;
} }
@Override @Override
@ -240,11 +273,20 @@ public class LPPermissible extends PermissibleBase {
throw new NullPointerException("attachment"); throw new NullPointerException("attachment");
} }
LPPermissionAttachment a;
if (!(attachment instanceof LPPermissionAttachment)) { if (!(attachment instanceof LPPermissionAttachment)) {
throw new IllegalArgumentException("Given attachment is not a LPPermissionAttachment."); // try to find a match
LPPermissionAttachment match = this.lpAttachments.stream().filter(at -> at.getSource() == attachment).findFirst().orElse(null);
if (match != null) {
a = match;
} else {
throw new IllegalArgumentException("Given attachment is not a LPPermissionAttachment.");
}
} else {
a = (LPPermissionAttachment) attachment;
} }
LPPermissionAttachment a = ((LPPermissionAttachment) attachment);
if (a.getPermissible() != this) { if (a.getPermissible() != this) {
throw new IllegalArgumentException("Attachment does not belong to this permissible."); throw new IllegalArgumentException("Attachment does not belong to this permissible.");
} }
@ -259,7 +301,7 @@ public class LPPermissible extends PermissibleBase {
@Override @Override
public void clearPermissions() { public void clearPermissions() {
this.attachments.forEach(LPPermissionAttachment::remove); this.lpAttachments.forEach(LPPermissionAttachment::remove);
} }
public User getUser() { public User getUser() {
@ -274,15 +316,102 @@ public class LPPermissible extends PermissibleBase {
return this.plugin; return this.plugin;
} }
public PermissibleBase getOldPermissible() { PermissibleBase getOldPermissible() {
return this.oldPermissible; return this.oldPermissible;
} }
public AtomicBoolean getActive() { AtomicBoolean getActive() {
return this.active; return this.active;
} }
public void setOldPermissible(PermissibleBase oldPermissible) { void setOldPermissible(PermissibleBase oldPermissible) {
this.oldPermissible = oldPermissible; this.oldPermissible = oldPermissible;
} }
/**
* A fake list to be injected into the superclass. This implementation simply
* proxies calls back to this permissible instance.
*
* Some (clever/dumb??) plugins attempt to add/remove/query attachments using reflection.
*
* An instance of this map is injected into the super instance so these plugins continue
* to work with LuckPerms.
*/
private final class FakeAttachmentList implements List<PermissionAttachment> {
@Override
public boolean add(PermissionAttachment attachment) {
if (LPPermissible.this.lpAttachments.stream().anyMatch(at -> at.getSource() == attachment)) {
return false;
}
new LPPermissionAttachment(LPPermissible.this, attachment).hook();
return true;
}
@Override
public boolean remove(Object o) {
removeAttachment((PermissionAttachment) o);
return true;
}
@Override
public void clear() {
clearPermissions();
}
@Override
public boolean addAll(@Nonnull Collection<? extends PermissionAttachment> c) {
boolean modified = false;
for (PermissionAttachment e : c) {
if (add(e)) {
modified = true;
}
}
return modified;
}
@Override
public boolean contains(Object o) {
PermissionAttachment attachment = (PermissionAttachment) o;
return LPPermissible.this.lpAttachments.stream().anyMatch(at -> at.getSource() == attachment);
}
@Override
public Iterator<PermissionAttachment> iterator() {
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).iterator();
}
@Override
public ListIterator<PermissionAttachment> listIterator() {
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).listIterator();
}
@Nonnull
@Override
public Object[] toArray() {
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).toArray();
}
@Nonnull
@Override
public <T> T[] toArray(@Nonnull T[] a) {
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).toArray(a);
}
@Override public int size() { throw new UnsupportedOperationException(); }
@Override public boolean isEmpty() { throw new UnsupportedOperationException(); }
@Override public boolean containsAll(@Nonnull Collection<?> c) { throw new UnsupportedOperationException(); }
@Override public boolean addAll(int index, @Nonnull Collection<? extends PermissionAttachment> c) { throw new UnsupportedOperationException(); }
@Override public boolean removeAll(@Nonnull Collection<?> c) { throw new UnsupportedOperationException(); }
@Override public boolean retainAll(@Nonnull Collection<?> c) { throw new UnsupportedOperationException(); }
@Override public PermissionAttachment get(int index) { throw new UnsupportedOperationException(); }
@Override public PermissionAttachment set(int index, PermissionAttachment element) { throw new UnsupportedOperationException(); }
@Override public void add(int index, PermissionAttachment element) { throw new UnsupportedOperationException(); }
@Override public PermissionAttachment remove(int index) { throw new UnsupportedOperationException(); }
@Override public int indexOf(Object o) { throw new UnsupportedOperationException(); }
@Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); }
@Nonnull @Override public ListIterator<PermissionAttachment> listIterator(int index) { throw new UnsupportedOperationException(); }
@Nonnull @Override public List<PermissionAttachment> subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); }
}
} }

View File

@ -94,6 +94,11 @@ public class LPPermissionAttachment extends PermissionAttachment {
*/ */
private PermissionRemovedExecutor removalCallback = null; private PermissionRemovedExecutor removalCallback = null;
/**
* Delegate attachment
*/
private PermissionAttachment source;
public LPPermissionAttachment(LPPermissible permissible, Plugin owner) { public LPPermissionAttachment(LPPermissible permissible, Plugin owner) {
super(DummyPlugin.INSTANCE, null); super(DummyPlugin.INSTANCE, null);
this.permissible = permissible; this.permissible = permissible;
@ -102,13 +107,14 @@ public class LPPermissionAttachment extends PermissionAttachment {
injectFakeMap(); injectFakeMap();
} }
public LPPermissionAttachment(LPPermissible permissible, PermissionAttachment bukkit) { public LPPermissionAttachment(LPPermissible permissible, PermissionAttachment source) {
super(DummyPlugin.INSTANCE, null); super(DummyPlugin.INSTANCE, null);
this.permissible = permissible; this.permissible = permissible;
this.owner = null; this.owner = null;
// copy // copy
this.perms.putAll(bukkit.getPermissions()); this.perms.putAll(source.getPermissions());
this.source = source;
injectFakeMap(); injectFakeMap();
} }
@ -148,12 +154,16 @@ public class LPPermissionAttachment extends PermissionAttachment {
this.removalCallback = removalCallback; this.removalCallback = removalCallback;
} }
PermissionAttachment getSource() {
return this.source;
}
/** /**
* Hooks this attachment with the parent {@link User} instance. * Hooks this attachment with the parent {@link User} instance.
*/ */
public void hook() { public void hook() {
this.hooked = true; this.hooked = true;
this.permissible.attachments.add(this); this.permissible.lpAttachments.add(this);
for (Map.Entry<String, Boolean> entry : this.perms.entrySet()) { for (Map.Entry<String, Boolean> entry : this.perms.entrySet()) {
if (entry.getKey() == null || entry.getKey().isEmpty()) { if (entry.getKey() == null || entry.getKey().isEmpty()) {
continue; continue;
@ -214,7 +224,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
// unhook from the permissible // unhook from the permissible
this.hooked = false; this.hooked = false;
this.permissible.attachments.remove(this); this.permissible.lpAttachments.remove(this);
return true; return true;
} }

View File

@ -58,7 +58,7 @@ public class MonitoredPermissibleBase extends PermissibleBase {
public MonitoredPermissibleBase(LuckPermsPlugin plugin, PermissibleBase delegate, String name) { public MonitoredPermissibleBase(LuckPermsPlugin plugin, PermissibleBase delegate, String name) {
super(null); super(null);
DummyPermissibleBase.nullFields(this); DummyPermissibleBase.copyFields(delegate, this);
this.plugin = plugin; this.plugin = plugin;
this.delegate = delegate; this.delegate = delegate;

View File

@ -64,6 +64,19 @@ public class DummyPermissibleBase extends PermissibleBase {
} }
} }
public static void copyFields(PermissibleBase from, PermissibleBase to) {
try {
ATTACHMENTS_FIELD.set(to, ATTACHMENTS_FIELD.get(from));
} catch (Exception e) {
// ignore
}
try {
PERMISSIONS_FIELD.set(to, PERMISSIONS_FIELD.get(from));
} catch (Exception e) {
// ignore
}
}
public static final DummyPermissibleBase INSTANCE = new DummyPermissibleBase(); public static final DummyPermissibleBase INSTANCE = new DummyPermissibleBase();
private DummyPermissibleBase() { private DummyPermissibleBase() {

View File

@ -25,10 +25,13 @@
package me.lucko.luckperms.nukkit.model.permissible; package me.lucko.luckperms.nukkit.model.permissible;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.Tristate; import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.contexts.ContextsCache; import me.lucko.luckperms.common.contexts.ContextsCache;
import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
import me.lucko.luckperms.common.verbose.CheckOrigin; import me.lucko.luckperms.common.verbose.CheckOrigin;
import me.lucko.luckperms.nukkit.LPNukkitPlugin; import me.lucko.luckperms.nukkit.LPNukkitPlugin;
import me.lucko.luckperms.nukkit.model.PermissionDefault; import me.lucko.luckperms.nukkit.model.PermissionDefault;
@ -40,14 +43,19 @@ import cn.nukkit.permission.PermissionAttachment;
import cn.nukkit.permission.PermissionAttachmentInfo; import cn.nukkit.permission.PermissionAttachmentInfo;
import cn.nukkit.plugin.Plugin; import cn.nukkit.plugin.Plugin;
import java.lang.reflect.Field;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nonnull;
/** /**
* PermissibleBase for LuckPerms. * PermissibleBase for LuckPerms.
* *
@ -64,6 +72,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/ */
public class LPPermissible extends PermissibleBase { public class LPPermissible extends PermissibleBase {
private static final Field ATTACHMENTS_FIELD;
static {
try {
ATTACHMENTS_FIELD = PermissibleBase.class.getDeclaredField("attachments");
ATTACHMENTS_FIELD.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new ExceptionInInitializerError(e);
}
}
// the LuckPerms user this permissible references. // the LuckPerms user this permissible references.
private final User user; private final User user;
@ -84,7 +103,7 @@ public class LPPermissible extends PermissibleBase {
// the attachments hooked onto the permissible. // the attachments hooked onto the permissible.
// this collection is only modified by the attachments themselves // this collection is only modified by the attachments themselves
final Set<LPPermissionAttachment> attachments = ConcurrentHashMap.newKeySet(); final Set<LPPermissionAttachment> lpAttachments = ConcurrentHashMap.newKeySet();
public LPPermissible(Player player, User user, LPNukkitPlugin plugin) { public LPPermissible(Player player, User user, LPNukkitPlugin plugin) {
super(player); super(player);
@ -92,6 +111,26 @@ public class LPPermissible extends PermissibleBase {
this.player = Objects.requireNonNull(player, "player"); this.player = Objects.requireNonNull(player, "player");
this.plugin = Objects.requireNonNull(plugin, "plugin"); this.plugin = Objects.requireNonNull(plugin, "plugin");
this.contextsCache = plugin.getContextManager().getCacheFor(player); this.contextsCache = plugin.getContextManager().getCacheFor(player);
injectFakeAttachmentsList();
}
/**
* Injects a fake 'attachments' list into the superclass, for dumb plugins
* which for some reason decided to add attachments via reflection.
*
* The fake list proxies (some) calls back to the proper methods on this permissible.
*/
private void injectFakeAttachmentsList() {
FakeAttachmentList fakeList = new FakeAttachmentList();
try {
// the field we need to modify is in the superclass - it has private
// and final modifiers so we have to use reflection to modify it.
ATTACHMENTS_FIELD.set(this, fakeList);
} catch (Exception e) {
e.printStackTrace();
}
} }
@Override @Override
@ -157,7 +196,7 @@ public class LPPermissible extends PermissibleBase {
* *
* @param attachments the attachments to add * @param attachments the attachments to add
*/ */
public void convertAndAddAttachments(Collection<PermissionAttachment> attachments) { void convertAndAddAttachments(Collection<PermissionAttachment> attachments) {
for (PermissionAttachment attachment : attachments) { for (PermissionAttachment attachment : attachments) {
new LPPermissionAttachment(this, attachment).hook(); new LPPermissionAttachment(this, attachment).hook();
} }
@ -170,14 +209,8 @@ public class LPPermissible extends PermissibleBase {
@Override @Override
public Map<String, PermissionAttachmentInfo> getEffectivePermissions() { public Map<String, PermissionAttachmentInfo> getEffectivePermissions() {
Set<Map.Entry<String, Boolean>> permissions = this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getImmutableBacking().entrySet(); return this.user.getCachedData().getPermissionData(this.contextsCache.getContexts()).getImmutableBacking().entrySet().stream()
Map<String, PermissionAttachmentInfo> ret = new HashMap<>(permissions.size()); .collect(ImmutableCollectors.toMap(Map.Entry::getKey, entry -> new PermissionAttachmentInfo(this.player, entry.getKey(), null, entry.getValue())));
for (Map.Entry<String, Boolean> entry : permissions) {
ret.put(entry.getKey(), new PermissionAttachmentInfo(this.player, entry.getKey(), null, entry.getValue()));
}
return ret;
} }
@Override @Override
@ -225,11 +258,20 @@ public class LPPermissible extends PermissibleBase {
throw new NullPointerException("attachment"); throw new NullPointerException("attachment");
} }
LPPermissionAttachment a;
if (!(attachment instanceof LPPermissionAttachment)) { if (!(attachment instanceof LPPermissionAttachment)) {
throw new IllegalArgumentException("Given attachment is not a LPPermissionAttachment."); // try to find a match
LPPermissionAttachment match = this.lpAttachments.stream().filter(at -> at.getSource() == attachment).findFirst().orElse(null);
if (match != null) {
a = match;
} else {
throw new IllegalArgumentException("Given attachment is not a LPPermissionAttachment.");
}
} else {
a = (LPPermissionAttachment) attachment;
} }
LPPermissionAttachment a = ((LPPermissionAttachment) attachment);
if (a.getPermissible() != this) { if (a.getPermissible() != this) {
throw new IllegalArgumentException("Attachment does not belong to this permissible."); throw new IllegalArgumentException("Attachment does not belong to this permissible.");
} }
@ -244,7 +286,7 @@ public class LPPermissible extends PermissibleBase {
@Override @Override
public void clearPermissions() { public void clearPermissions() {
this.attachments.forEach(LPPermissionAttachment::remove); this.lpAttachments.forEach(LPPermissionAttachment::remove);
} }
public User getUser() { public User getUser() {
@ -259,15 +301,102 @@ public class LPPermissible extends PermissibleBase {
return this.plugin; return this.plugin;
} }
public PermissibleBase getOldPermissible() { PermissibleBase getOldPermissible() {
return this.oldPermissible; return this.oldPermissible;
} }
public AtomicBoolean getActive() { AtomicBoolean getActive() {
return this.active; return this.active;
} }
public void setOldPermissible(PermissibleBase oldPermissible) { void setOldPermissible(PermissibleBase oldPermissible) {
this.oldPermissible = oldPermissible; this.oldPermissible = oldPermissible;
} }
/**
* A fake list to be injected into the superclass. This implementation simply
* proxies calls back to this permissible instance.
*
* Some (clever/dumb??) plugins attempt to add/remove/query attachments using reflection.
*
* An instance of this map is injected into the super instance so these plugins continue
* to work with LuckPerms.
*/
private final class FakeAttachmentList implements List<PermissionAttachment> {
@Override
public boolean add(PermissionAttachment attachment) {
if (LPPermissible.this.lpAttachments.stream().anyMatch(at -> at.getSource() == attachment)) {
return false;
}
new LPPermissionAttachment(LPPermissible.this, attachment).hook();
return true;
}
@Override
public boolean remove(Object o) {
removeAttachment((PermissionAttachment) o);
return true;
}
@Override
public void clear() {
clearPermissions();
}
@Override
public boolean addAll(@Nonnull Collection<? extends PermissionAttachment> c) {
boolean modified = false;
for (PermissionAttachment e : c) {
if (add(e)) {
modified = true;
}
}
return modified;
}
@Override
public boolean contains(Object o) {
PermissionAttachment attachment = (PermissionAttachment) o;
return LPPermissible.this.lpAttachments.stream().anyMatch(at -> at.getSource() == attachment);
}
@Override
public Iterator<PermissionAttachment> iterator() {
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).iterator();
}
@Override
public ListIterator<PermissionAttachment> listIterator() {
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).listIterator();
}
@Nonnull
@Override
public Object[] toArray() {
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).toArray();
}
@Nonnull
@Override
public <T> T[] toArray(@Nonnull T[] a) {
return ImmutableList.<PermissionAttachment>copyOf(LPPermissible.this.lpAttachments).toArray(a);
}
@Override public int size() { throw new UnsupportedOperationException(); }
@Override public boolean isEmpty() { throw new UnsupportedOperationException(); }
@Override public boolean containsAll(@Nonnull Collection<?> c) { throw new UnsupportedOperationException(); }
@Override public boolean addAll(int index, @Nonnull Collection<? extends PermissionAttachment> c) { throw new UnsupportedOperationException(); }
@Override public boolean removeAll(@Nonnull Collection<?> c) { throw new UnsupportedOperationException(); }
@Override public boolean retainAll(@Nonnull Collection<?> c) { throw new UnsupportedOperationException(); }
@Override public PermissionAttachment get(int index) { throw new UnsupportedOperationException(); }
@Override public PermissionAttachment set(int index, PermissionAttachment element) { throw new UnsupportedOperationException(); }
@Override public void add(int index, PermissionAttachment element) { throw new UnsupportedOperationException(); }
@Override public PermissionAttachment remove(int index) { throw new UnsupportedOperationException(); }
@Override public int indexOf(Object o) { throw new UnsupportedOperationException(); }
@Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); }
@Nonnull @Override public ListIterator<PermissionAttachment> listIterator(int index) { throw new UnsupportedOperationException(); }
@Nonnull @Override public List<PermissionAttachment> subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); }
}
} }

View File

@ -96,6 +96,11 @@ public class LPPermissionAttachment extends PermissionAttachment {
*/ */
private PermissionRemovedExecutor removalCallback = null; private PermissionRemovedExecutor removalCallback = null;
/**
* Delegate attachment
*/
private PermissionAttachment source;
public LPPermissionAttachment(LPPermissible permissible, Plugin owner) { public LPPermissionAttachment(LPPermissible permissible, Plugin owner) {
super(DummyPlugin.INSTANCE, null); super(DummyPlugin.INSTANCE, null);
this.permissible = permissible; this.permissible = permissible;
@ -111,6 +116,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
// copy // copy
this.perms.putAll(nukkit.getPermissions()); this.perms.putAll(nukkit.getPermissions());
this.source = source;
injectFakeMap(); injectFakeMap();
} }
@ -149,12 +155,16 @@ public class LPPermissionAttachment extends PermissionAttachment {
this.removalCallback = removalCallback; this.removalCallback = removalCallback;
} }
PermissionAttachment getSource() {
return this.source;
}
/** /**
* Hooks this attachment with the parent {@link User} instance. * Hooks this attachment with the parent {@link User} instance.
*/ */
public void hook() { public void hook() {
this.hooked = true; this.hooked = true;
this.permissible.attachments.add(this); this.permissible.lpAttachments.add(this);
for (Map.Entry<String, Boolean> entry : this.perms.entrySet()) { for (Map.Entry<String, Boolean> entry : this.perms.entrySet()) {
if (entry.getKey() == null || entry.getKey().isEmpty()) { if (entry.getKey() == null || entry.getKey().isEmpty()) {
continue; continue;
@ -215,7 +225,7 @@ public class LPPermissionAttachment extends PermissionAttachment {
// unhook from the permissible // unhook from the permissible
this.hooked = false; this.hooked = false;
this.permissible.attachments.remove(this); this.permissible.lpAttachments.remove(this);
} }
@Override @Override

View File

@ -58,7 +58,7 @@ public class MonitoredPermissibleBase extends PermissibleBase {
public MonitoredPermissibleBase(LuckPermsPlugin plugin, PermissibleBase delegate, String name) { public MonitoredPermissibleBase(LuckPermsPlugin plugin, PermissibleBase delegate, String name) {
super(null); super(null);
DummyPermissibleBase.nullFields(this); DummyPermissibleBase.copyFields(delegate, this);
this.plugin = plugin; this.plugin = plugin;
this.delegate = delegate; this.delegate = delegate;

View File

@ -173,6 +173,11 @@ public final class SubjectProxy implements Subject, ProxiedSubject {
return CompatibilityUtil.convertContexts(getContextsCache().getContextSet()); return CompatibilityUtil.convertContexts(getContextsCache().getContextSet());
} }
@Override
public ImmutableContextSet getActiveContextSet() {
return getContextsCache().getContextSet();
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o == this || o instanceof SubjectProxy && this.ref.equals(((SubjectProxy) o).ref); return o == this || o instanceof SubjectProxy && this.ref.equals(((SubjectProxy) o).ref);

View File

@ -174,6 +174,11 @@ public final class SubjectProxy implements Subject, ProxiedSubject {
return CompatibilityUtil.convertContexts(getContextsCache().getContextSet()); return CompatibilityUtil.convertContexts(getContextsCache().getContextSet());
} }
@Override
public ImmutableContextSet getActiveContextSet() {
return getContextsCache().getContextSet();
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o == this || o instanceof SubjectProxy && this.ref.equals(((SubjectProxy) o).ref); return o == this || o instanceof SubjectProxy && this.ref.equals(((SubjectProxy) o).ref);

View File

@ -25,6 +25,8 @@
package me.lucko.luckperms.sponge.service.model; package me.lucko.luckperms.sponge.service.model;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import org.spongepowered.api.service.permission.Subject; import org.spongepowered.api.service.permission.Subject;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -37,4 +39,6 @@ public interface ProxiedSubject {
@Nonnull @Nonnull
LPSubjectReference asSubjectReference(); LPSubjectReference asSubjectReference();
ImmutableContextSet getActiveContextSet();
} }