From 4bd1b3c09f1b76682bfa287c5c20184ef8597289 Mon Sep 17 00:00:00 2001 From: lucko Date: Sun, 27 Mar 2022 14:07:36 +0100 Subject: [PATCH] Reduce user lookups for LuckPerms contexts (#4869) --- .../essentials/perm/IPermissionsHandler.java | 6 +- .../essentials/perm/PermissionsHandler.java | 19 +++-- .../perm/impl/ConfigPermissionsHandler.java | 3 +- .../perm/impl/GenericVaultHandler.java | 4 +- .../perm/impl/LuckPermsHandler.java | 84 ++++++++++++++----- .../perm/impl/ModernVaultHandler.java | 4 +- .../perm/impl/SuperpermsHandler.java | 6 +- 7 files changed, 87 insertions(+), 39 deletions(-) diff --git a/Essentials/src/main/java/com/earth2me/essentials/perm/IPermissionsHandler.java b/Essentials/src/main/java/com/earth2me/essentials/perm/IPermissionsHandler.java index 8b02383bf..707be09c8 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/perm/IPermissionsHandler.java +++ b/Essentials/src/main/java/com/earth2me/essentials/perm/IPermissionsHandler.java @@ -1,5 +1,7 @@ package com.earth2me.essentials.perm; +import com.earth2me.essentials.Essentials; +import com.earth2me.essentials.User; import com.earth2me.essentials.utils.TriState; import org.bukkit.entity.Player; @@ -27,11 +29,11 @@ public interface IPermissionsHandler { String getSuffix(Player base); - void registerContext(String context, Function> calculator, Supplier> suggestions); + void registerContext(String context, Function> calculator, Supplier> suggestions); void unregisterContexts(); String getBackendName(); - boolean tryProvider(); + boolean tryProvider(Essentials ess); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/perm/PermissionsHandler.java b/Essentials/src/main/java/com/earth2me/essentials/perm/PermissionsHandler.java index e1e83870b..722c55a9a 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/perm/PermissionsHandler.java +++ b/Essentials/src/main/java/com/earth2me/essentials/perm/PermissionsHandler.java @@ -1,6 +1,7 @@ package com.earth2me.essentials.perm; import com.earth2me.essentials.Essentials; +import com.earth2me.essentials.User; import com.earth2me.essentials.perm.impl.AbstractVaultHandler; import com.earth2me.essentials.perm.impl.ConfigPermissionsHandler; import com.earth2me.essentials.perm.impl.GenericVaultHandler; @@ -105,7 +106,7 @@ public class PermissionsHandler implements IPermissionsHandler { } @Override - public void registerContext(final String context, final Function> calculator, final Supplier> suggestions) { + public void registerContext(final String context, final Function> calculator, final Supplier> suggestions) { handler.registerContext(context, calculator, suggestions); } @@ -120,7 +121,7 @@ public class PermissionsHandler implements IPermissionsHandler { } @Override - public boolean tryProvider() { + public boolean tryProvider(Essentials ess) { return true; } @@ -135,7 +136,7 @@ public class PermissionsHandler implements IPermissionsHandler { for (final Class providerClass : providerClazz) { try { final IPermissionsHandler provider = providerClass.newInstance(); - if (provider.tryProvider()) { + if (provider.tryProvider(ess)) { if (provider.getClass().isInstance(this.handler)) { return; } @@ -170,7 +171,7 @@ public class PermissionsHandler implements IPermissionsHandler { if (enabledPermsPlugin == null) enabledPermsPlugin = "generic"; ess.getLogger().info("Using Vault based permissions (" + enabledPermsPlugin + ")"); } else if (handler.getClass() == SuperpermsHandler.class) { - if (handler.tryProvider()) { + if (handler.tryProvider(ess)) { ess.getLogger().warning("Detected supported permissions plugin " + ((SuperpermsHandler) handler).getEnabledPermsPlugin() + " without Vault installed."); ess.getLogger().warning("Features such as chat prefixes/suffixes and group-related functionality will not " + @@ -199,11 +200,11 @@ public class PermissionsHandler implements IPermissionsHandler { } private void initContexts() { - registerContext("essentials:afk", player -> Collections.singleton(String.valueOf(ess.getUser(player).isAfk())), () -> ImmutableSet.of("true", "false")); - registerContext("essentials:muted", player -> Collections.singleton(String.valueOf(ess.getUser(player).isMuted())), () -> ImmutableSet.of("true", "false")); - registerContext("essentials:vanished", player -> Collections.singleton(String.valueOf(ess.getUser(player).isHidden())), () -> ImmutableSet.of("true", "false")); - registerContext("essentials:jailed", player -> Collections.singleton(String.valueOf(ess.getUser(player).isJailed())), () -> ImmutableSet.of("true", "false")); - registerContext("essentials:jail", player -> Optional.ofNullable(ess.getUser(player).getJail()).map(Arrays::asList).orElse(Collections.emptyList()), () -> { + registerContext("essentials:afk", user -> Collections.singleton(String.valueOf(user.isAfk())), () -> ImmutableSet.of("true", "false")); + registerContext("essentials:muted", user -> Collections.singleton(String.valueOf(user.isMuted())), () -> ImmutableSet.of("true", "false")); + registerContext("essentials:vanished", user -> Collections.singleton(String.valueOf(user.isHidden())), () -> ImmutableSet.of("true", "false")); + registerContext("essentials:jailed", user -> Collections.singleton(String.valueOf(user.isJailed())), () -> ImmutableSet.of("true", "false")); + registerContext("essentials:jail", user -> Optional.ofNullable(user.getJail()).map(Arrays::asList).orElse(Collections.emptyList()), () -> { try { return ess.getJails().getList(); } catch (final Exception e) { diff --git a/Essentials/src/main/java/com/earth2me/essentials/perm/impl/ConfigPermissionsHandler.java b/Essentials/src/main/java/com/earth2me/essentials/perm/impl/ConfigPermissionsHandler.java index 730591369..6b80b8a2a 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/perm/impl/ConfigPermissionsHandler.java +++ b/Essentials/src/main/java/com/earth2me/essentials/perm/impl/ConfigPermissionsHandler.java @@ -1,5 +1,6 @@ package com.earth2me.essentials.perm.impl; +import com.earth2me.essentials.Essentials; import com.earth2me.essentials.utils.TriState; import net.ess3.api.IEssentials; import org.bukkit.entity.Player; @@ -35,7 +36,7 @@ public class ConfigPermissionsHandler extends SuperpermsHandler { } @Override - public boolean tryProvider() { + public boolean tryProvider(Essentials ess) { return true; } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/perm/impl/GenericVaultHandler.java b/Essentials/src/main/java/com/earth2me/essentials/perm/impl/GenericVaultHandler.java index 7d707b39c..ff63ab9db 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/perm/impl/GenericVaultHandler.java +++ b/Essentials/src/main/java/com/earth2me/essentials/perm/impl/GenericVaultHandler.java @@ -1,8 +1,10 @@ package com.earth2me.essentials.perm.impl; +import com.earth2me.essentials.Essentials; + public class GenericVaultHandler extends AbstractVaultHandler { @Override - public boolean tryProvider() { + public boolean tryProvider(Essentials ess) { return super.canLoad(); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/perm/impl/LuckPermsHandler.java b/Essentials/src/main/java/com/earth2me/essentials/perm/impl/LuckPermsHandler.java index 44a51493d..77fff460f 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/perm/impl/LuckPermsHandler.java +++ b/Essentials/src/main/java/com/earth2me/essentials/perm/impl/LuckPermsHandler.java @@ -1,5 +1,8 @@ package com.earth2me.essentials.perm.impl; +import com.earth2me.essentials.Essentials; +import com.earth2me.essentials.User; + import net.luckperms.api.LuckPerms; import net.luckperms.api.context.ContextCalculator; import net.luckperms.api.context.ContextConsumer; @@ -16,40 +19,75 @@ import java.util.function.Supplier; public class LuckPermsHandler extends ModernVaultHandler { private LuckPerms luckPerms; - private Set> contextCalculators; + private Essentials ess; + private CombinedCalculator calculator; @Override - public void registerContext(final String context, final Function> calculator, final Supplier> suggestions) { - final ContextCalculator contextCalculator = new ContextCalculator() { - @Override - public void calculate(final Player target, final ContextConsumer consumer) { - calculator.apply(target).forEach(value -> consumer.accept(context, value)); - } - - @Override - public ContextSet estimatePotentialContexts() { - final ImmutableContextSet.Builder builder = ImmutableContextSet.builder(); - suggestions.get().forEach(value -> builder.add(context, value)); - return builder.build(); - } - }; - luckPerms.getContextManager().registerCalculator(contextCalculator); - contextCalculators.add(contextCalculator); + public void registerContext(final String context, final Function> calculator, final Supplier> suggestions) { + if (this.calculator == null) { + this.calculator = new CombinedCalculator(); + this.luckPerms.getContextManager().registerCalculator(this.calculator); + } + this.calculator.calculators.add(new Calculator(context, calculator, suggestions)); } @Override public void unregisterContexts() { - contextCalculators.forEach(contextCalculator -> luckPerms.getContextManager().unregisterCalculator(contextCalculator)); - contextCalculators.clear(); + if (this.calculator != null) { + this.luckPerms.getContextManager().unregisterCalculator(this.calculator); + this.calculator = null; + } } @Override - public boolean tryProvider() { + public boolean tryProvider(Essentials ess) { final RegisteredServiceProvider provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class); if (provider != null) { - luckPerms = provider.getProvider(); - contextCalculators = new HashSet<>(); + this.luckPerms = provider.getProvider(); + this.ess = ess; + } + return luckPerms != null && super.tryProvider(ess); + } + + private static final class Calculator { + private final String id; + private final Function> function; + private final Supplier> suggestions; + + private Calculator(String id, Function> function, Supplier> suggestions) { + this.id = id; + this.function = function; + this.suggestions = suggestions; + } + } + + // By combining all calculators into one, we only need to make one call to ess.getUser(). + private class CombinedCalculator implements ContextCalculator { + private final Set calculators = new HashSet<>(); + + @Override + public void calculate(final Player target, final ContextConsumer consumer) { + // If the player doesn't exist in the UserMap, just skip + // Ess will cause performance problems for permissions checks if it attempts to + // perform i/o to load the user data otherwise. + if (!ess.getUserMap().userExists(target.getUniqueId())) { + return; + } + + final User user = ess.getUser(target); + for (Calculator calculator : this.calculators) { + calculator.function.apply(user).forEach(value -> consumer.accept(calculator.id, value)); + } + } + + @Override + public ContextSet estimatePotentialContexts() { + final ImmutableContextSet.Builder builder = ImmutableContextSet.builder(); + for (Calculator calculator : this.calculators) { + calculator.suggestions.get().forEach(value -> builder.add(calculator.id, value)); + } + + return builder.build(); } - return luckPerms != null && super.tryProvider(); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/perm/impl/ModernVaultHandler.java b/Essentials/src/main/java/com/earth2me/essentials/perm/impl/ModernVaultHandler.java index adddc6f48..5d4a87c49 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/perm/impl/ModernVaultHandler.java +++ b/Essentials/src/main/java/com/earth2me/essentials/perm/impl/ModernVaultHandler.java @@ -1,5 +1,7 @@ package com.earth2me.essentials.perm.impl; +import com.earth2me.essentials.Essentials; + import org.bukkit.entity.Player; import java.util.Arrays; @@ -21,7 +23,7 @@ public class ModernVaultHandler extends AbstractVaultHandler { } @Override - public boolean tryProvider() { + public boolean tryProvider(Essentials ess) { return super.canLoad() && supportedPlugins.contains(getEnabledPermsPlugin()); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/perm/impl/SuperpermsHandler.java b/Essentials/src/main/java/com/earth2me/essentials/perm/impl/SuperpermsHandler.java index db1b59e2d..1e285b8bb 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/perm/impl/SuperpermsHandler.java +++ b/Essentials/src/main/java/com/earth2me/essentials/perm/impl/SuperpermsHandler.java @@ -1,5 +1,7 @@ package com.earth2me.essentials.perm.impl; +import com.earth2me.essentials.Essentials; +import com.earth2me.essentials.User; import com.earth2me.essentials.perm.IPermissionsHandler; import com.earth2me.essentials.utils.TriState; import org.bukkit.Bukkit; @@ -124,7 +126,7 @@ public class SuperpermsHandler implements IPermissionsHandler { } @Override - public void registerContext(final String context, final Function> calculator, final Supplier> suggestions) { + public void registerContext(final String context, final Function> calculator, final Supplier> suggestions) { } @Override @@ -137,7 +139,7 @@ public class SuperpermsHandler implements IPermissionsHandler { } @Override - public boolean tryProvider() { + public boolean tryProvider(Essentials ess) { return getEnabledPermsPlugin() != null; }