diff --git a/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java b/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java index 5fcc0e7f..ff63beac 100644 --- a/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java +++ b/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java @@ -29,7 +29,6 @@ import lombok.NonNull; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; -import com.github.benmanes.caffeine.cache.RemovalListener; import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.api.context.ContextCalculator; @@ -40,56 +39,75 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; +/** + * Manages {@link ContextCalculator}s, and calculates applicable contexts for a + * given type. + * + * @param the calculator type + */ public abstract class ContextManager { private final List> calculators = new CopyOnWriteArrayList<>(); private final List> staticCalculators = new CopyOnWriteArrayList<>(); - private final LoadingCache activeContextCache = Caffeine.newBuilder() + // caches context lookups + private final LoadingCache lookupCache = Caffeine.newBuilder() .weakKeys() - .expireAfterWrite(50L, TimeUnit.MILLISECONDS) - .removalListener((RemovalListener) (t, contextSet, removalCause) -> { - if (t != null) { - invalidateContextsCache(t); - } - }) - .build(t -> calculateApplicableContext(t, MutableContextSet.create()).makeImmutable()); + .expireAfterWrite(50L, TimeUnit.MILLISECONDS) // expire roughly every tick + .build(subject -> { + MutableContextSet accumulator = MutableContextSet.create(); + calculateApplicableContext(subject, accumulator); - private final LoadingCache contextsCache = Caffeine.newBuilder() - .weakKeys() - .expireAfterWrite(100L, TimeUnit.MILLISECONDS) - .build(t -> formContexts(t, getApplicableContext(t))); + ImmutableContextSet ret = accumulator.makeImmutable(); + return formContexts(subject, ret); + }); + + /** + * Queries the ContextManager for current context values for the subject. + * + * @param subject the subject + * @return the applicable context for the subject + */ public ImmutableContextSet getApplicableContext(@NonNull T subject) { - return activeContextCache.get(subject); + // this is actually already immutable, but the Contexts method signature returns the interface. + return getApplicableContexts(subject).getContexts().makeImmutable(); } + /** + * Queries the ContextManager for current context values for the subject. + * + * @param subject the subject + * @return the applicable context for the subject + */ public Contexts getApplicableContexts(@NonNull T subject) { - return contextsCache.get(subject); + return lookupCache.get(subject); } - public abstract Contexts formContexts(T t, ImmutableContextSet contextSet); - - private MutableContextSet calculateApplicableContext(T subject, MutableContextSet accumulator) { - for (ContextCalculator calculator : calculators) { - try { - calculator.giveApplicableContext(subject, accumulator); - } catch (Exception e) { - new RuntimeException("Exception thrown by ContextCalculator: " + calculator.getClass().getName(), e).printStackTrace(); - } - - } - return accumulator; - } - - private void invalidateContextsCache(T t) { - contextsCache.invalidate(t); - } + /** + * Forms a {@link Contexts} instance from an {@link ImmutableContextSet}. + * + * @param subject the subject + * @param contextSet the context set + * @return a contexts instance + */ + public abstract Contexts formContexts(T subject, ImmutableContextSet contextSet); + /** + * Registers a context calculator with the manager. + * + * @param calculator the calculator + */ public void registerCalculator(ContextCalculator calculator) { registerCalculator(calculator, false); } + /** + * Registers a context calculator with the manager. + * + * @param calculator the calculator + * @param isStatic if the calculator is static. (if it allows a null subject parameter) + */ public void registerCalculator(ContextCalculator calculator, boolean isStatic) { // calculators registered first should have priority (and be checked last.) calculators.add(0, calculator); @@ -99,6 +117,11 @@ public abstract class ContextManager { } } + /** + * Gets the contexts from the static calculators in this manager. + * + * @return the current active static contexts + */ public ImmutableContextSet getStaticContexts() { MutableContextSet accumulator = MutableContextSet.create(); for (ContextCalculator calculator : staticCalculators) { @@ -107,11 +130,34 @@ public abstract class ContextManager { return accumulator.makeImmutable(); } + /** + * Invalidates the lookup cache for a given subject + * + * @param subject the subject + */ public void invalidateCache(@NonNull T subject){ - activeContextCache.invalidate(subject); + lookupCache.invalidate(subject); } + /** + * Gets the number of calculators registered with the manager. + * + * @return the number of calculators registered + */ public int getCalculatorsSize() { return calculators.size(); } + + // iterates the calculators in this manager and accumulates contexts from them all. + private void calculateApplicableContext(T subject, MutableContextSet accumulator) { + for (ContextCalculator calculator : calculators) { + try { + calculator.giveApplicableContext(subject, accumulator); + } catch (Exception e) { + new RuntimeException("Exception thrown by ContextCalculator: " + calculator.getClass().getName(), e).printStackTrace(); + } + + } + } + } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java index 10d73587..77af7963 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java @@ -93,7 +93,7 @@ public class SpongeConfig extends AbstractConfiguration { for (String s : paths) { node = node.getNode(s); - + if (node == null) { return SimpleConfigurationNode.root(); }