diff --git a/api/src/main/java/net/luckperms/api/context/DefaultContextKeys.java b/api/src/main/java/net/luckperms/api/context/DefaultContextKeys.java index 0097e3193..174b46c16 100644 --- a/api/src/main/java/net/luckperms/api/context/DefaultContextKeys.java +++ b/api/src/main/java/net/luckperms/api/context/DefaultContextKeys.java @@ -34,13 +34,31 @@ public final class DefaultContextKeys { } /** - * The context key used to denote the subjects server. + * The context key used to denote the name of the subjects server. */ public static final String SERVER_KEY = "server"; /** - * The context key used to denote the subjects world. + * The context key used to denote the name of the subjects world. */ public static final String WORLD_KEY = "world"; + /** + * The context key used to denote the dimension type of the subjects world. + * + *

Possible values: overworld, the_nether, the_end

+ * + * @since 5.3 + */ + public static final String DIMENSION_TYPE_KEY = "dimension-type"; + + /** + * The context key used to denote the subjects gamemode. + * + *

Possible values: survival, creative, adventure, spectator

+ * + * @since 5.3 + */ + public static final String GAMEMODE_KEY = "gamemode"; + } 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 ce36b47d6..ef2d01683 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -28,7 +28,7 @@ package me.lucko.luckperms.bukkit; import me.lucko.luckperms.bukkit.brigadier.LuckPermsBrigadier; import me.lucko.luckperms.bukkit.calculator.BukkitCalculatorFactory; import me.lucko.luckperms.bukkit.context.BukkitContextManager; -import me.lucko.luckperms.bukkit.context.WorldCalculator; +import me.lucko.luckperms.bukkit.context.BukkitPlayerCalculator; import me.lucko.luckperms.bukkit.inject.permissible.LuckPermsPermissible; import me.lucko.luckperms.bukkit.inject.permissible.PermissibleInjector; import me.lucko.luckperms.bukkit.inject.permissible.PermissibleMonitoringInjector; @@ -186,9 +186,9 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin { protected void setupContextManager() { this.contextManager = new BukkitContextManager(this); - WorldCalculator worldCalculator = new WorldCalculator(this); - this.bootstrap.getServer().getPluginManager().registerEvents(worldCalculator, this.bootstrap); - this.contextManager.registerCalculator(worldCalculator); + BukkitPlayerCalculator playerCalculator = new BukkitPlayerCalculator(this); + this.bootstrap.getServer().getPluginManager().registerEvents(playerCalculator, this.bootstrap); + this.contextManager.registerCalculator(playerCalculator); } @Override diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/context/WorldCalculator.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/context/BukkitPlayerCalculator.java similarity index 58% rename from bukkit/src/main/java/me/lucko/luckperms/bukkit/context/WorldCalculator.java rename to bukkit/src/main/java/me/lucko/luckperms/bukkit/context/BukkitPlayerCalculator.java index e4eae67de..1bdcfda2e 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/context/WorldCalculator.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/context/BukkitPlayerCalculator.java @@ -25,9 +25,12 @@ package me.lucko.luckperms.bukkit.context; +import com.google.common.collect.ImmutableMap; + import me.lucko.luckperms.bukkit.LPBukkitPlugin; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl; +import me.lucko.luckperms.common.util.EnumNamer; import net.luckperms.api.context.Context; import net.luckperms.api.context.ContextCalculator; @@ -36,42 +39,57 @@ import net.luckperms.api.context.ContextSet; import net.luckperms.api.context.DefaultContextKeys; import net.luckperms.api.context.ImmutableContextSet; +import org.bukkit.GameMode; import org.bukkit.World; +import org.bukkit.World.Environment; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.checkerframework.checker.nullness.qual.NonNull; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +public class BukkitPlayerCalculator implements ContextCalculator, Listener { + private static final EnumNamer GAMEMODE_NAMER = new EnumNamer<>( + GameMode.class, + EnumNamer.LOWER_CASE_NAME + ); + private static final EnumNamer DIMENSION_TYPE_NAMER = new EnumNamer<>( + Environment.class, + // use the namespaced keys used by the game + ImmutableMap.builder() + .put(Environment.NORMAL, "overworld") + .put(Environment.NETHER, "the_nether") + .put(Environment.THE_END, "the_end") + .build(), + EnumNamer.LOWER_CASE_NAME + ); -public class WorldCalculator implements ContextCalculator, Listener { private final LPBukkitPlugin plugin; - public WorldCalculator(LPBukkitPlugin plugin) { + public BukkitPlayerCalculator(LPBukkitPlugin plugin) { this.plugin = plugin; } @Override public void calculate(@NonNull Player subject, @NonNull ContextConsumer consumer) { - Set seen = new HashSet<>(); - String world = subject.getWorld().getName().toLowerCase(); - // seems like world names can sometimes be the empty string - // see: https://github.com/lucko/LuckPerms/issues/2119 - while (Context.isValidValue(world) && seen.add(world)) { - consumer.accept(DefaultContextKeys.WORLD_KEY, world); - world = this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(world, world).toLowerCase(); - } + World world = subject.getWorld(); + consumer.accept(DefaultContextKeys.GAMEMODE_KEY, GAMEMODE_NAMER.name(subject.getGameMode())); + consumer.accept(DefaultContextKeys.DIMENSION_TYPE_KEY, DIMENSION_TYPE_NAMER.name(world.getEnvironment())); + this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).rewriteAndSubmit(world.getName(), consumer); } @Override public ContextSet estimatePotentialContexts() { - List worlds = this.plugin.getBootstrap().getServer().getWorlds(); ImmutableContextSet.Builder builder = new ImmutableContextSetImpl.BuilderImpl(); - for (World world : worlds) { + for (GameMode mode : GameMode.values()) { + builder.add(DefaultContextKeys.GAMEMODE_KEY, GAMEMODE_NAMER.name(mode)); + } + for (Environment env : Environment.values()) { + builder.add(DefaultContextKeys.DIMENSION_TYPE_KEY, DIMENSION_TYPE_NAMER.name(env)); + } + for (World world : this.plugin.getBootstrap().getServer().getWorlds()) { String name = world.getName().toLowerCase(); if (Context.isValidValue(name)) { builder.add(DefaultContextKeys.WORLD_KEY, name); @@ -84,4 +102,9 @@ public class WorldCalculator implements ContextCalculator, Listener { public void onWorldChange(PlayerChangedWorldEvent e) { this.plugin.getContextManager().signalContextUpdate(e.getPlayer()); } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onGameModeChange(PlayerGameModeChangeEvent e) { + this.plugin.getContextManager().signalContextUpdate(e.getPlayer()); + } } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java index b227af8d1..fce7987e6 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java @@ -26,8 +26,8 @@ package me.lucko.luckperms.bungee; import me.lucko.luckperms.bungee.calculator.BungeeCalculatorFactory; -import me.lucko.luckperms.bungee.context.BackendServerCalculator; import me.lucko.luckperms.bungee.context.BungeeContextManager; +import me.lucko.luckperms.bungee.context.BungeePlayerCalculator; import me.lucko.luckperms.bungee.context.RedisBungeeCalculator; import me.lucko.luckperms.bungee.listeners.BungeeConnectionListener; import me.lucko.luckperms.bungee.listeners.BungeePermissionCheckListener; @@ -140,9 +140,9 @@ public class LPBungeePlugin extends AbstractLuckPermsPlugin { protected void setupContextManager() { this.contextManager = new BungeeContextManager(this); - BackendServerCalculator backendServerCalculator = new BackendServerCalculator(this); - this.bootstrap.getProxy().getPluginManager().registerListener(this.bootstrap, backendServerCalculator); - this.contextManager.registerCalculator(backendServerCalculator); + BungeePlayerCalculator playerCalculator = new BungeePlayerCalculator(this); + this.bootstrap.getProxy().getPluginManager().registerListener(this.bootstrap, playerCalculator); + this.contextManager.registerCalculator(playerCalculator); if (this.bootstrap.getProxy().getPluginManager().getPlugin("RedisBungee") != null) { this.contextManager.registerCalculator(new RedisBungeeCalculator()); diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/context/BackendServerCalculator.java b/bungee/src/main/java/me/lucko/luckperms/bungee/context/BungeePlayerCalculator.java similarity index 73% rename from bungee/src/main/java/me/lucko/luckperms/bungee/context/BackendServerCalculator.java rename to bungee/src/main/java/me/lucko/luckperms/bungee/context/BungeePlayerCalculator.java index 5331de953..7c12921bb 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/context/BackendServerCalculator.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/context/BungeePlayerCalculator.java @@ -36,49 +36,39 @@ import net.luckperms.api.context.DefaultContextKeys; import net.luckperms.api.context.ImmutableContextSet; import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.event.ServerSwitchEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.event.EventHandler; +import net.md_5.bungee.event.EventPriority; import org.checkerframework.checker.nullness.qual.NonNull; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -public class BackendServerCalculator implements ContextCalculator, Listener { - - private static String getServer(ProxiedPlayer player) { - return player.getServer() == null ? null : (player.getServer().getInfo() == null ? null : player.getServer().getInfo().getName().toLowerCase()); - } - +public class BungeePlayerCalculator implements ContextCalculator, Listener { private final LPBungeePlugin plugin; - public BackendServerCalculator(LPBungeePlugin plugin) { + public BungeePlayerCalculator(LPBungeePlugin plugin) { this.plugin = plugin; } @Override public void calculate(@NonNull ProxiedPlayer subject, @NonNull ContextConsumer consumer) { - Set seen = new HashSet<>(); - String server = getServer(subject); - while (server != null && seen.add(server)) { - consumer.accept(DefaultContextKeys.WORLD_KEY, server); - server = this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(server, server).toLowerCase(); + Server server = subject.getServer(); + if (server != null) { + this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).rewriteAndSubmit(server.getInfo().getName(), consumer); } } @Override public ContextSet estimatePotentialContexts() { - Collection servers = this.plugin.getBootstrap().getProxy().getServers().values(); ImmutableContextSet.Builder builder = new ImmutableContextSetImpl.BuilderImpl(); - for (ServerInfo server : servers) { + for (ServerInfo server : this.plugin.getBootstrap().getProxy().getServers().values()) { builder.add(DefaultContextKeys.WORLD_KEY, server.getName().toLowerCase()); } return builder.build(); } - @EventHandler + @EventHandler(priority = EventPriority.LOWEST) public void onServerSwitch(ServerSwitchEvent e) { this.plugin.getContextManager().signalContextUpdate(e.getPlayer()); } diff --git a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java index 07c2dbde0..e6625cfc9 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java @@ -33,6 +33,7 @@ import me.lucko.luckperms.common.cacheddata.type.SimpleMetaValueSelector; import me.lucko.luckperms.common.config.generic.KeyedConfiguration; import me.lucko.luckperms.common.config.generic.key.ConfigKey; import me.lucko.luckperms.common.config.generic.key.SimpleConfigKey; +import me.lucko.luckperms.common.context.WorldNameRewriter; import me.lucko.luckperms.common.graph.TraversalAlgorithm; import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition; import me.lucko.luckperms.common.metastacking.StandardStackElements; @@ -475,12 +476,12 @@ public final class ConfigKeys { /** * The world rewrites map */ - public static final ConfigKey> WORLD_REWRITES = key(c -> { - return c.getStringMap("world-rewrite", ImmutableMap.of()).entrySet().stream() + public static final ConfigKey WORLD_REWRITES = key(c -> { + return WorldNameRewriter.of(c.getStringMap("world-rewrite", ImmutableMap.of()).entrySet().stream() .collect(ImmutableCollectors.toMap( e -> e.getKey().toLowerCase(), e -> e.getValue().toLowerCase() - )); + ))); }); /** diff --git a/common/src/main/java/me/lucko/luckperms/common/context/WorldNameRewriter.java b/common/src/main/java/me/lucko/luckperms/common/context/WorldNameRewriter.java new file mode 100644 index 000000000..19a443cde --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/context/WorldNameRewriter.java @@ -0,0 +1,85 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * 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.common.context; + +import me.lucko.luckperms.common.config.ConfigKeys; + +import net.luckperms.api.context.Context; +import net.luckperms.api.context.ContextConsumer; +import net.luckperms.api.context.DefaultContextKeys; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Rewrites world names according to the {@link ConfigKeys#WORLD_REWRITES} option. + */ +public interface WorldNameRewriter { + + static WorldNameRewriter of(Map rewrites) { + if (rewrites.isEmpty()) { + return new Empty(); + } else { + return new NonEmpty(rewrites); + } + } + + void rewriteAndSubmit(String worldName, ContextConsumer consumer); + + class Empty implements WorldNameRewriter { + @Override + public void rewriteAndSubmit(String worldName, ContextConsumer consumer) { + if (Context.isValidValue(worldName)) { + consumer.accept(DefaultContextKeys.WORLD_KEY, worldName.toLowerCase()); + } + } + } + + class NonEmpty implements WorldNameRewriter { + private final Map rewrites; + + public NonEmpty(Map rewrites) { + this.rewrites = rewrites; + } + + @Override + public void rewriteAndSubmit(String worldName, ContextConsumer consumer) { + Set seen = new HashSet<>(); + worldName = worldName.toLowerCase(); + + while (Context.isValidValue(worldName) && seen.add(worldName)) { + consumer.accept(DefaultContextKeys.WORLD_KEY, worldName); + + worldName = this.rewrites.get(worldName); + if (worldName == null) { + break; + } + } + } + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/util/EnumNamer.java b/common/src/main/java/me/lucko/luckperms/common/util/EnumNamer.java new file mode 100644 index 000000000..183c056ac --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/util/EnumNamer.java @@ -0,0 +1,62 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * 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.common.util; + +import java.util.Collections; +import java.util.Map; +import java.util.function.Function; + +/** + * Small utility to cache custom name lookups for enum values. + * + * @param the enum type + */ +public class EnumNamer> { + public static final Function, String> LOWER_CASE_NAME = value -> value.name().toLowerCase(); + + private final String[] names; + + public EnumNamer(Class enumClass, Map definedNames, Function namingFunction) { + E[] values = enumClass.getEnumConstants(); + this.names = new String[values.length]; + for (E value : values) { + String name = definedNames.get(value); + if (name == null) { + name = namingFunction.apply(value); + } + this.names[value.ordinal()] = name; + } + } + + public EnumNamer(Class enumClass, Function namingFunction) { + this(enumClass, Collections.emptyMap(), namingFunction); + } + + public String name(E value) { + return this.names[value.ordinal()]; + } + +} diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java index 77155f325..ed7e28e3d 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java @@ -43,7 +43,7 @@ import me.lucko.luckperms.common.tasks.CacheHousekeepingTask; import me.lucko.luckperms.common.tasks.ExpireTemporaryTask; import me.lucko.luckperms.nukkit.calculator.NukkitCalculatorFactory; import me.lucko.luckperms.nukkit.context.NukkitContextManager; -import me.lucko.luckperms.nukkit.context.WorldCalculator; +import me.lucko.luckperms.nukkit.context.NukkitPlayerCalculator; import me.lucko.luckperms.nukkit.inject.PermissionDefault; import me.lucko.luckperms.nukkit.inject.permissible.LuckPermsPermissible; import me.lucko.luckperms.nukkit.inject.permissible.PermissibleInjector; @@ -145,9 +145,9 @@ public class LPNukkitPlugin extends AbstractLuckPermsPlugin { protected void setupContextManager() { this.contextManager = new NukkitContextManager(this); - WorldCalculator worldCalculator = new WorldCalculator(this); - this.bootstrap.getServer().getPluginManager().registerEvents(worldCalculator, this.bootstrap); - this.contextManager.registerCalculator(worldCalculator); + NukkitPlayerCalculator playerCalculator = new NukkitPlayerCalculator(this); + this.bootstrap.getServer().getPluginManager().registerEvents(playerCalculator, this.bootstrap); + this.contextManager.registerCalculator(playerCalculator); } @Override diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/context/WorldCalculator.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/context/NukkitPlayerCalculator.java similarity index 56% rename from nukkit/src/main/java/me/lucko/luckperms/nukkit/context/WorldCalculator.java rename to nukkit/src/main/java/me/lucko/luckperms/nukkit/context/NukkitPlayerCalculator.java index 9fd23cc63..2065823d0 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/context/WorldCalculator.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/context/NukkitPlayerCalculator.java @@ -38,43 +38,66 @@ import net.luckperms.api.context.ImmutableContextSet; import org.checkerframework.checker.nullness.qual.NonNull; import cn.nukkit.Player; +import cn.nukkit.Server; import cn.nukkit.event.EventHandler; import cn.nukkit.event.EventPriority; import cn.nukkit.event.Listener; import cn.nukkit.event.entity.EntityLevelChangeEvent; +import cn.nukkit.event.player.PlayerGameModeChangeEvent; import cn.nukkit.level.Level; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +public class NukkitPlayerCalculator implements ContextCalculator, Listener { + private static final int[] KNOWN_GAMEMODES = {Player.SURVIVAL, Player.CREATIVE, Player.ADVENTURE, Player.SPECTATOR}; + private static final int[] KNOWN_DIMENSION_TYPES = {Level.DIMENSION_OVERWORLD, Level.DIMENSION_NETHER}; -public class WorldCalculator implements ContextCalculator, Listener { private final LPNukkitPlugin plugin; - public WorldCalculator(LPNukkitPlugin plugin) { + public NukkitPlayerCalculator(LPNukkitPlugin plugin) { this.plugin = plugin; } @Override public void calculate(@NonNull Player subject, @NonNull ContextConsumer consumer) { - Set seen = new HashSet<>(); - String world = subject.getLevel().getName().toLowerCase(); - while (seen.add(world)) { - consumer.accept(DefaultContextKeys.WORLD_KEY, world); - world = this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(world, world).toLowerCase(); - } + Level level = subject.getLevel(); + consumer.accept(DefaultContextKeys.GAMEMODE_KEY, getGamemodeName(subject.getGamemode())); + consumer.accept(DefaultContextKeys.DIMENSION_TYPE_KEY, getDimensionName(level.getDimension())); + this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).rewriteAndSubmit(level.getName(), consumer); } @Override public ContextSet estimatePotentialContexts() { - Collection worlds = this.plugin.getBootstrap().getServer().getLevels().values(); ImmutableContextSet.Builder builder = new ImmutableContextSetImpl.BuilderImpl(); - for (Level world : worlds) { + for (int mode : KNOWN_GAMEMODES) { + builder.add(DefaultContextKeys.GAMEMODE_KEY, getGamemodeName(mode)); + } + for (int dim : KNOWN_DIMENSION_TYPES) { + builder.add(DefaultContextKeys.DIMENSION_TYPE_KEY, getDimensionName(dim)); + } + for (Level world : this.plugin.getBootstrap().getServer().getLevels().values()) { builder.add(DefaultContextKeys.WORLD_KEY, world.getName().toLowerCase()); } return builder.build(); } + private static String getGamemodeName(int mode) { + switch (mode) { + case Player.SURVIVAL: return "survival"; + case Player.CREATIVE: return "creative"; + case Player.ADVENTURE: return "adventure"; + case Player.SPECTATOR: return "spectator"; + default: return Server.getGamemodeString(mode, true).toLowerCase(); + } + } + + private static String getDimensionName(int dim) { + switch (dim) { + // use the namespaced keys used by the game + case Level.DIMENSION_OVERWORLD: return "overworld"; + case Level.DIMENSION_NETHER: return "the_nether"; + default: return "unknown" + dim; + } + } + @EventHandler(priority = EventPriority.LOWEST) public void onWorldChange(EntityLevelChangeEvent e) { if (e.getEntity() instanceof Player) { @@ -82,4 +105,9 @@ public class WorldCalculator implements ContextCalculator, Listener { this.plugin.getContextManager().signalContextUpdate(player); } } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onGameModeChange(PlayerGameModeChangeEvent e) { + this.plugin.getContextManager().signalContextUpdate(e.getPlayer()); + } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java index 25f530b45..38df1acf1 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java @@ -44,7 +44,7 @@ import me.lucko.luckperms.common.util.MoreFiles; import me.lucko.luckperms.sponge.calculator.SpongeCalculatorFactory; import me.lucko.luckperms.sponge.commands.SpongeParentCommand; import me.lucko.luckperms.sponge.context.SpongeContextManager; -import me.lucko.luckperms.sponge.context.WorldCalculator; +import me.lucko.luckperms.sponge.context.SpongePlayerCalculator; import me.lucko.luckperms.sponge.listeners.SpongeConnectionListener; import me.lucko.luckperms.sponge.listeners.SpongePlatformListener; import me.lucko.luckperms.sponge.messaging.SpongeMessagingFactory; @@ -161,9 +161,9 @@ public class LPSpongePlugin extends AbstractLuckPermsPlugin { protected void setupContextManager() { this.contextManager = new SpongeContextManager(this); - WorldCalculator worldCalculator = new WorldCalculator(this); - this.bootstrap.getGame().getEventManager().registerListeners(this.bootstrap, worldCalculator); - this.contextManager.registerCalculator(worldCalculator); + SpongePlayerCalculator playerCalculator = new SpongePlayerCalculator(this); + this.bootstrap.getGame().getEventManager().registerListeners(this.bootstrap, playerCalculator); + this.contextManager.registerCalculator(playerCalculator); } @Override diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/context/WorldCalculator.java b/sponge/src/main/java/me/lucko/luckperms/sponge/context/SpongePlayerCalculator.java similarity index 54% rename from sponge/src/main/java/me/lucko/luckperms/sponge/context/WorldCalculator.java rename to sponge/src/main/java/me/lucko/luckperms/sponge/context/SpongePlayerCalculator.java index 129305092..090a231f4 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/context/WorldCalculator.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/context/SpongePlayerCalculator.java @@ -36,63 +36,82 @@ import net.luckperms.api.context.DefaultContextKeys; import net.luckperms.api.context.ImmutableContextSet; import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.CatalogKey; +import org.spongepowered.api.CatalogTypes; import org.spongepowered.api.Game; import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.data.key.Keys; +import org.spongepowered.api.data.value.ValueContainer; import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.living.Humanoid; +import org.spongepowered.api.entity.living.player.gamemode.GameMode; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.Order; import org.spongepowered.api.event.entity.MoveEntityEvent; +import org.spongepowered.api.event.entity.living.humanoid.ChangeGameModeEvent; import org.spongepowered.api.service.permission.Subject; +import org.spongepowered.api.world.DimensionType; +import org.spongepowered.api.world.Locatable; import org.spongepowered.api.world.World; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -public class WorldCalculator implements ContextCalculator { +public class SpongePlayerCalculator implements ContextCalculator { private final LPSpongePlugin plugin; - public WorldCalculator(LPSpongePlugin plugin) { + public SpongePlayerCalculator(LPSpongePlugin plugin) { this.plugin = plugin; } @Override public void calculate(@NonNull Subject subject, @NonNull ContextConsumer consumer) { CommandSource source = subject.getCommandSource().orElse(null); - if (source == null || !(source instanceof Player)) { + if (source == null) { return; } - Player p = ((Player) source); + if (source instanceof Locatable) { + World world = ((Locatable) source).getWorld(); + consumer.accept(DefaultContextKeys.DIMENSION_TYPE_KEY, getCatalogKeyName(world.getDimension().getType().getKey())); + this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).rewriteAndSubmit(world.getName(), consumer); + } - Set seen = new HashSet<>(); - String world = p.getWorld().getName().toLowerCase(); - while (seen.add(world)) { - consumer.accept(DefaultContextKeys.WORLD_KEY, world); - world = this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(world, world).toLowerCase(); + if (source instanceof ValueContainer) { + ValueContainer valueContainer = (ValueContainer) source; + valueContainer.get(Keys.GAME_MODE).ifPresent(mode -> consumer.accept(DefaultContextKeys.GAMEMODE_KEY, getCatalogKeyName(mode.getKey()))); } } @Override public ContextSet estimatePotentialContexts() { + ImmutableContextSet.Builder builder = new ImmutableContextSetImpl.BuilderImpl(); Game game = this.plugin.getBootstrap().getGame(); - if (!game.isServerAvailable()) { - return ImmutableContextSetImpl.EMPTY; + + for (GameMode mode : game.getRegistry().getAllOf(CatalogTypes.GAME_MODE)) { + builder.add(DefaultContextKeys.GAMEMODE_KEY, getCatalogKeyName(mode.getKey())); + } + for (DimensionType dim : game.getRegistry().getAllOf(CatalogTypes.DIMENSION_TYPE)) { + builder.add(DefaultContextKeys.DIMENSION_TYPE_KEY, getCatalogKeyName(dim.getKey())); + } + if (game.isServerAvailable()) { + for (World world : game.getServer().getWorlds()) { + builder.add(DefaultContextKeys.WORLD_KEY, world.getName().toLowerCase()); + } } - Collection worlds = game.getServer().getWorlds(); - ImmutableContextSet.Builder builder = new ImmutableContextSetImpl.BuilderImpl(); - for (World world : worlds) { - builder.add(DefaultContextKeys.WORLD_KEY, world.getName().toLowerCase()); - } return builder.build(); } + private static String getCatalogKeyName(CatalogKey key) { + if (key.getNamespace().equals(CatalogKey.MINECRAFT_NAMESPACE)) { + return key.getValue(); + } else { + return key.toString(); + } + } + @Listener(order = Order.LAST) public void onWorldChange(MoveEntityEvent.Teleport e) { Entity targetEntity = e.getTargetEntity(); - if (!(targetEntity instanceof Player)) { + if (!(targetEntity instanceof Subject)) { return; } @@ -100,7 +119,14 @@ public class WorldCalculator implements ContextCalculator { return; } - Player player = (Player) targetEntity; - this.plugin.getContextManager().signalContextUpdate(player); + this.plugin.getContextManager().signalContextUpdate((Subject) targetEntity); + } + + @Listener(order = Order.LAST) + public void onGameModeChange(ChangeGameModeEvent e) { + Humanoid targetEntity = e.getTargetEntity(); + if (targetEntity instanceof Subject) { + this.plugin.getContextManager().signalContextUpdate((Subject) targetEntity); + } } } diff --git a/velocity/src/main/java/me/lucko/luckperms/velocity/LPVelocityPlugin.java b/velocity/src/main/java/me/lucko/luckperms/velocity/LPVelocityPlugin.java index 0a21de08d..d2d63e1e9 100644 --- a/velocity/src/main/java/me/lucko/luckperms/velocity/LPVelocityPlugin.java +++ b/velocity/src/main/java/me/lucko/luckperms/velocity/LPVelocityPlugin.java @@ -43,8 +43,8 @@ import me.lucko.luckperms.common.tasks.CacheHousekeepingTask; import me.lucko.luckperms.common.tasks.ExpireTemporaryTask; import me.lucko.luckperms.common.util.MoreFiles; import me.lucko.luckperms.velocity.calculator.VelocityCalculatorFactory; -import me.lucko.luckperms.velocity.context.BackendServerCalculator; import me.lucko.luckperms.velocity.context.VelocityContextManager; +import me.lucko.luckperms.velocity.context.VelocityPlayerCalculator; import me.lucko.luckperms.velocity.listeners.MonitoringPermissionCheckListener; import me.lucko.luckperms.velocity.listeners.VelocityConnectionListener; import me.lucko.luckperms.velocity.messaging.VelocityMessagingFactory; @@ -137,7 +137,10 @@ public class LPVelocityPlugin extends AbstractLuckPermsPlugin { @Override protected void setupContextManager() { this.contextManager = new VelocityContextManager(this); - this.contextManager.registerCalculator(new BackendServerCalculator(this)); + + VelocityPlayerCalculator playerCalculator = new VelocityPlayerCalculator(this); + this.bootstrap.getProxy().getEventManager().register(this.bootstrap, playerCalculator); + this.contextManager.registerCalculator(playerCalculator); } @Override diff --git a/velocity/src/main/java/me/lucko/luckperms/velocity/context/BackendServerCalculator.java b/velocity/src/main/java/me/lucko/luckperms/velocity/context/VelocityPlayerCalculator.java similarity index 74% rename from velocity/src/main/java/me/lucko/luckperms/velocity/context/BackendServerCalculator.java rename to velocity/src/main/java/me/lucko/luckperms/velocity/context/VelocityPlayerCalculator.java index 385528a0d..2a9435f94 100644 --- a/velocity/src/main/java/me/lucko/luckperms/velocity/context/BackendServerCalculator.java +++ b/velocity/src/main/java/me/lucko/luckperms/velocity/context/VelocityPlayerCalculator.java @@ -25,9 +25,11 @@ package me.lucko.luckperms.velocity.context; +import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.player.ServerConnectedEvent; import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.server.RegisteredServer; import me.lucko.luckperms.common.config.ConfigKeys; @@ -42,43 +44,32 @@ import net.luckperms.api.context.ImmutableContextSet; import org.checkerframework.checker.nullness.qual.NonNull; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -public class BackendServerCalculator implements ContextCalculator { - - private static String getServer(Player player) { - return player.getCurrentServer().isPresent() ? player.getCurrentServer().get().getServerInfo().getName().toLowerCase() : null; - } - +public class VelocityPlayerCalculator implements ContextCalculator { private final LPVelocityPlugin plugin; - public BackendServerCalculator(LPVelocityPlugin plugin) { + public VelocityPlayerCalculator(LPVelocityPlugin plugin) { this.plugin = plugin; } @Override public void calculate(@NonNull Player subject, @NonNull ContextConsumer consumer) { - Set seen = new HashSet<>(); - String server = getServer(subject); - while (server != null && seen.add(server)) { - consumer.accept(DefaultContextKeys.WORLD_KEY, server); - server = this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).getOrDefault(server, server).toLowerCase(); + ServerConnection server = subject.getCurrentServer().orElse(null); + if (server == null) { + return; } + this.plugin.getConfiguration().get(ConfigKeys.WORLD_REWRITES).rewriteAndSubmit(server.getServerInfo().getName(), consumer); } @Override public ContextSet estimatePotentialContexts() { - Collection servers = this.plugin.getBootstrap().getProxy().getAllServers(); ImmutableContextSet.Builder builder = new ImmutableContextSetImpl.BuilderImpl(); - for (RegisteredServer server : servers) { + for (RegisteredServer server : this.plugin.getBootstrap().getProxy().getAllServers()) { builder.add(DefaultContextKeys.WORLD_KEY, server.getServerInfo().getName().toLowerCase()); } return builder.build(); } - @Subscribe + @Subscribe(order = PostOrder.FIRST) public void onServerConnect(ServerConnectedEvent e) { this.plugin.getContextManager().signalContextUpdate(e.getPlayer()); }