diff --git a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionsEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionsEvent.java
index 2fcb12b6b..d5cdaccdb 100644
--- a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionsEvent.java
+++ b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserRegisterPermissionsEvent.java
@@ -32,8 +32,7 @@ import org.geysermc.geyser.api.util.TriState;
* Fired by anything that wishes to gather permission nodes and defaults.
*
* This event is not guaranteed to be fired, as certain Geyser platforms do not have a native permission system.
- * It can be expected to fire on Geyser-Spigot, Geyser-NeoForge and Geyser-Standalone. Note: NeoForge allows registering permissions,
- * but does so without registering default values.
+ * It can be expected to fire on Geyser-Spigot, Geyser-NeoForge and Geyser-Standalone.
* It may still be fired on other platforms due to a 3rd party.
*/
public interface GeyserRegisterPermissionsEvent extends Event {
diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeBootstrap.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeBootstrap.java
index d1978c4a7..591ef8673 100644
--- a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeBootstrap.java
+++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeBootstrap.java
@@ -28,6 +28,7 @@ package org.geysermc.geyser.platform.neoforge;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.world.entity.player.Player;
import net.neoforged.api.distmarker.Dist;
+import net.neoforged.bus.api.EventPriority;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.loading.FMLLoader;
import net.neoforged.neoforge.common.NeoForge;
@@ -35,7 +36,6 @@ import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.event.server.ServerStartedEvent;
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
import org.geysermc.geyser.GeyserImpl;
-import org.geysermc.geyser.command.CommandRegistry;
import org.geysermc.geyser.command.CommandSourceConverter;
import org.geysermc.geyser.command.GeyserCommandSource;
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
@@ -60,7 +60,7 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
NeoForge.EVENT_BUS.addListener(this::onPlayerJoin);
GeyserNeoForgePermissionHandler permissionHandler = new GeyserNeoForgePermissionHandler();
- NeoForge.EVENT_BUS.addListener(permissionHandler::onPermissionGather);
+ NeoForge.EVENT_BUS.addListener(EventPriority.HIGHEST, permissionHandler::onPermissionGather);
this.onGeyserInitialize();
@@ -75,7 +75,7 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
ExecutionCoordinator.simpleCoordinator(),
sourceConverter
);
- this.setCommandRegistry(new CommandRegistry(GeyserImpl.getInstance(), cloud));
+ this.setCommandRegistry(new GeyserNeoForgeCommandRegistry(GeyserImpl.getInstance(), cloud));
}
private void onServerStarted(ServerStartedEvent event) {
diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeCommandRegistry.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeCommandRegistry.java
new file mode 100644
index 000000000..e4af78abf
--- /dev/null
+++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeCommandRegistry.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
+ *
+ * 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.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.neoforge;
+
+import com.google.common.util.concurrent.UncheckedExecutionException;
+import org.geysermc.geyser.GeyserImpl;
+import org.geysermc.geyser.command.CommandRegistry;
+import org.geysermc.geyser.command.GeyserCommandSource;
+import org.incendo.cloud.CommandManager;
+
+public class GeyserNeoForgeCommandRegistry extends CommandRegistry {
+ public GeyserNeoForgeCommandRegistry(GeyserImpl geyser, CommandManager cloud) {
+ super(geyser, cloud);
+ }
+
+ // todo yeet once cloud enforced method contract here:
+ // https://github.com/Incendo/cloud/blob/master/cloud-core/src/main/java/org/incendo/cloud/CommandManager.java#L441-L449
+ @Override
+ public boolean hasPermission(GeyserCommandSource source, String permission) {
+ try {
+ return super.hasPermission(source, permission);
+ } catch (UncheckedExecutionException e) {
+ return false;
+ }
+ }
+}
diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePermissionHandler.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePermissionHandler.java
index 732687ae8..6fc334adb 100644
--- a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePermissionHandler.java
+++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePermissionHandler.java
@@ -30,9 +30,9 @@ import net.neoforged.neoforge.server.permission.nodes.PermissionDynamicContextKe
import net.neoforged.neoforge.server.permission.nodes.PermissionNode;
import net.neoforged.neoforge.server.permission.nodes.PermissionType;
import net.neoforged.neoforge.server.permission.nodes.PermissionTypes;
-import org.geysermc.geyser.Constants;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent;
+import org.geysermc.geyser.api.util.TriState;
import java.lang.reflect.Constructor;
@@ -57,22 +57,27 @@ public class GeyserNeoForgePermissionHandler {
}
public void onPermissionGather(PermissionGatherEvent.Nodes event) {
- this.registerNode(Constants.UPDATE_PERMISSION, event);
-
- GeyserImpl.getInstance().eventBus().fire((GeyserRegisterPermissionsEvent) (permission, defaultValue) -> this.registerNode(permission, event));
+ GeyserImpl.getInstance().eventBus().fire(
+ (GeyserRegisterPermissionsEvent) (permission, defaultValue) -> {
+ if (permission.isBlank()) {
+ return;
+ }
+ this.registerNode(permission, defaultValue, event);
+ }
+ );
}
- private void registerNode(String node, PermissionGatherEvent.Nodes event) {
- PermissionNode permissionNode = this.createNode(node);
+ private void registerNode(String node, TriState permissionDefault, PermissionGatherEvent.Nodes event) {
+ PermissionNode permissionNode = this.createNode(node, permissionDefault);
// NeoForge likes to crash if you try and register a duplicate node
- if (!event.getNodes().contains(permissionNode)) {
+ if (event.getNodes().stream().noneMatch(eventNode -> eventNode.getNodeName().equals(node))) {
event.addNodes(permissionNode);
}
}
@SuppressWarnings("unchecked")
- private PermissionNode createNode(String node) {
+ private PermissionNode createNode(String node, TriState permissionDefault) {
// The typical constructors in PermissionNode require a
// mod id, which means our permission nodes end up becoming
// geyser_neoforge. instead of just . We work around
@@ -82,7 +87,16 @@ public class GeyserNeoForgePermissionHandler {
return (PermissionNode) PERMISSION_NODE_CONSTRUCTOR.newInstance(
node,
PermissionTypes.BOOLEAN,
- (PermissionNode.PermissionResolver) (player, playerUUID, context) -> false,
+ (PermissionNode.PermissionResolver) (player, playerUUID, context) -> switch (permissionDefault) {
+ case TRUE -> true;
+ case FALSE -> false;
+ case NOT_SET -> {
+ if (player != null) {
+ yield player.createCommandSourceStack().hasPermission(player.server.getOperatorUserPermissionLevel());
+ }
+ yield false;
+ }
+ },
new PermissionDynamicContextKey[0]
);
} catch (Exception e) {
diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSource.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSource.java
index 9ba89b4dd..3612cb8b7 100644
--- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSource.java
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSource.java
@@ -88,7 +88,7 @@ public class ModCommandSource implements GeyserCommandSource {
// Unlike other bootstraps; we delegate to cloud here too:
// On NeoForge; we'd have to keep track of all PermissionNodes - cloud already does that
// For Fabric, we won't need to include the Fabric Permissions API anymore - cloud already does that too :p
- return GeyserImpl.getInstance().commandRegistry().cloud().hasPermission(this, permission);
+ return GeyserImpl.getInstance().commandRegistry().hasPermission(this, permission);
}
@Override
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java
index 7b4dec7cf..05baec501 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java
@@ -41,7 +41,6 @@ import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.checkerframework.checker.nullness.qual.NonNull;
-import org.geysermc.geyser.Constants;
import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
@@ -277,14 +276,13 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
geyserLogger.debug("Using default world manager.");
}
-
// Register permissions so they appear in, for example, LuckPerms' UI
// Re-registering permissions without removing it throws an error
-
PluginManager pluginManager = Bukkit.getPluginManager();
-
- // todo: this can probably always be run regardless if geyser has been initialized once or not, since we are removing the permission
geyser.eventBus().fire((GeyserRegisterPermissionsEvent) (permission, def) -> {
+ if (permission.isBlank()) {
+ return;
+ }
PermissionDefault permissionDefault = switch (def) {
case TRUE -> PermissionDefault.TRUE;
case FALSE -> PermissionDefault.FALSE;
@@ -302,9 +300,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
pluginManager.addPermission(new Permission(permission, permissionDefault));
});
- pluginManager.addPermission(new Permission(Constants.UPDATE_PERMISSION,
- "Whether update notifications can be seen", PermissionDefault.OP));
-
// Events cannot be unregistered - re-registering results in duplicate firings
GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(geyser, this.geyserWorldManager);
pluginManager.registerEvents(blockPlaceListener, this);
diff --git a/core/src/main/java/org/geysermc/geyser/Constants.java b/core/src/main/java/org/geysermc/geyser/Constants.java
index 5de8e6e6b..4c9c36e17 100644
--- a/core/src/main/java/org/geysermc/geyser/Constants.java
+++ b/core/src/main/java/org/geysermc/geyser/Constants.java
@@ -38,6 +38,8 @@ public final class Constants {
public static final String GEYSER_DOWNLOAD_LOCATION = "https://geysermc.org/download";
public static final String UPDATE_PERMISSION = "geyser.update";
+ public static final String SERVER_SETTINGS_PERMISSION = "geyser.settings.server";
+ public static final String SETTINGS_GAMERULES_PERMISSION = "geyser.settings.gamerules";
static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json";
diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java
index 1a60b746c..786433c0f 100644
--- a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java
+++ b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java
@@ -28,6 +28,7 @@ package org.geysermc.geyser.command;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import lombok.AllArgsConstructor;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.geysermc.geyser.Constants;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.api.command.Command;
@@ -112,7 +113,7 @@ public class CommandRegistry {
new GeyserExceptionHandler<>(NoSuchCommandException.class, (src, e) -> src.sendLocaleString("geyser.command.not_found")),
new GeyserExceptionHandler<>(ArgumentParseException.class, (src, e) -> src.sendLocaleString("geyser.command.invalid_argument", e.getCause().getMessage())),
new GeyserExceptionHandler<>(CommandExecutionException.class, (src, e) -> handleUnexpectedThrowable(src, e.getCause())),
- new GeyserExceptionHandler<>(RuntimeException.class, (src, e) -> handleUnexpectedThrowable(src, e.getCause()))
+ new GeyserExceptionHandler<>(Throwable.class, (src, e) -> handleUnexpectedThrowable(src, e.getCause()))
);
for (GeyserExceptionHandler> handler : exceptionHandlers) {
handler.register(cloud);
@@ -195,6 +196,10 @@ public class CommandRegistry {
register(command, this.extensionCommands.computeIfAbsent(extension, e -> new HashMap<>()));
}
+ public boolean hasPermission(GeyserCommandSource source, String permission) {
+ return cloud.hasPermission(source, permission);
+ }
+
private void register(GeyserCommand command, Map commands) {
command.register(cloud);
@@ -218,6 +223,11 @@ public class CommandRegistry {
for (Map.Entry permission : permissionDefaults.entrySet()) {
event.register(permission.getKey(), permission.getValue());
}
+
+ // Register other various Geyser permissions
+ event.register(Constants.UPDATE_PERMISSION, TriState.NOT_SET);
+ event.register(Constants.SERVER_SETTINGS_PERMISSION, TriState.NOT_SET);
+ event.register(Constants.SETTINGS_GAMERULES_PERMISSION, TriState.NOT_SET);
}
/**
@@ -277,7 +287,7 @@ public class CommandRegistry {
}
@AllArgsConstructor
- private static class GeyserExceptionHandler implements ExceptionHandler {
+ private static class GeyserExceptionHandler implements ExceptionHandler {
final Class type;
final BiConsumer handler;
diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java
index 939edebe7..b419dee30 100644
--- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java
+++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java
@@ -89,6 +89,9 @@ public abstract class GeyserCommand implements org.geysermc.geyser.api.command.C
if (name.isBlank()) {
throw new IllegalArgumentException("Command cannot be null or blank!");
}
+ if (permission.isBlank()) {
+ permissionDefault = null;
+ }
this.name = name;
this.description = description;
diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserPermission.java b/core/src/main/java/org/geysermc/geyser/command/GeyserPermission.java
index 7af32d570..2ba9b32e6 100644
--- a/core/src/main/java/org/geysermc/geyser/command/GeyserPermission.java
+++ b/core/src/main/java/org/geysermc/geyser/command/GeyserPermission.java
@@ -42,6 +42,9 @@ public class GeyserPermission implements PredicatePermission manager;
public Result check(GeyserCommandSource source) {
+ if (permission.isBlank()) {
+ return Result.ALLOWED;
+ }
if (bedrockOnly) {
if (source.connection() == null) {
return Result.NOT_BEDROCK;
diff --git a/core/src/main/java/org/geysermc/geyser/command/standalone/StandaloneCloudCommandManager.java b/core/src/main/java/org/geysermc/geyser/command/standalone/StandaloneCloudCommandManager.java
index 2788cb201..4a0e78a78 100644
--- a/core/src/main/java/org/geysermc/geyser/command/standalone/StandaloneCloudCommandManager.java
+++ b/core/src/main/java/org/geysermc/geyser/command/standalone/StandaloneCloudCommandManager.java
@@ -86,6 +86,9 @@ public class StandaloneCloudCommandManager extends CommandManager {
+ if (permission.isBlank()) {
+ return;
+ }
if (def == TriState.TRUE) {
basePermissions.add(permission);
}
diff --git a/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java b/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java
index 5613cba1b..f90045e9a 100644
--- a/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java
+++ b/core/src/main/java/org/geysermc/geyser/extension/command/GeyserExtensionCommand.java
@@ -27,7 +27,6 @@ package org.geysermc.geyser.extension.command;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
-import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.command.Command;
import org.geysermc.geyser.api.command.CommandExecutor;
import org.geysermc.geyser.api.command.CommandSource;
@@ -111,12 +110,6 @@ public abstract class GeyserExtensionCommand extends GeyserCommand {
@Override
public Builder permission(@NonNull String permission) {
this.permission = Objects.requireNonNull(permission, "command permission");
- if (!permission.contains(".") && !permission.isBlank()) {
- String newPermission = extension.description().id() + "." + permission;
- GeyserImpl.getInstance().getLogger().error("Extension " + extension.name() + " tried to register an invalid permission (" + permission + ")." +
- "Changing it to " + newPermission + "!");
- this.permission = newPermission;
- }
return this;
}
@@ -124,12 +117,6 @@ public abstract class GeyserExtensionCommand extends GeyserCommand {
public Builder permission(@NonNull String permission, @NonNull TriState defaultValue) {
this.permission = Objects.requireNonNull(permission, "command permission");
this.permissionDefault = Objects.requireNonNull(defaultValue, "command permission defaultValue");
- if (!permission.contains(".") && !permission.isBlank()) {
- String newPermission = extension.description().id() + "." + permission;
- GeyserImpl.getInstance().getLogger().error("Extension " + extension.name() + " tried to register an invalid permission (" + permission + ")." +
- "Changing it to " + newPermission + "!");
- this.permission = newPermission;
- }
return this;
}
diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
index 3eb2dc18c..fdff1cd19 100644
--- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
+++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
@@ -65,8 +65,6 @@ import io.netty.channel.Channel;
import io.netty.channel.EventLoop;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
@@ -1463,7 +1461,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
public boolean hasPermission(String permission) {
// for Geyser-Standalone, standalone's permission system will handle it.
// for server platforms, the session will be mapped to a server command sender, and the server's api will be used.
- return geyser.commandRegistry().cloud().hasPermission(this, permission);
+ return geyser.commandRegistry().hasPermission(this, permission);
}
/**
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java
index df28f7ca7..38e9e152b 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java
@@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import org.cloudburstmc.protocol.bedrock.packet.SetDefaultGameTypePacket;
import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket;
+import org.geysermc.geyser.Constants;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@@ -41,7 +42,7 @@ public class BedrockSetDefaultGameTypeTranslator extends PacketTranslator= 2 && session.hasPermission("geyser.settings.server")) {
+ if (session.getOpPermissionLevel() >= 2 && session.hasPermission(Constants.SERVER_SETTINGS_PERMISSION)) {
session.getGeyser().getWorldManager().setDefaultGameMode(session, GameMode.byId(packet.getGamemode()));
}
// Stop the client from updating their own Gamemode without telling the server
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java
index b996a96b1..0f68cf2df 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java
@@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
import org.cloudburstmc.protocol.bedrock.packet.SetDifficultyPacket;
+import org.geysermc.geyser.Constants;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@@ -39,7 +40,7 @@ public class BedrockSetDifficultyTranslator extends PacketTranslator= 2 && session.hasPermission("geyser.settings.server")) {
+ if (session.getOpPermissionLevel() >= 2 && session.hasPermission(Constants.SERVER_SETTINGS_PERMISSION)) {
if (packet.getDifficulty() != session.getWorldCache().getDifficulty().ordinal()) {
session.getGeyser().getWorldManager().setDifficulty(session, Difficulty.from(packet.getDifficulty()));
}
diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java
index 2d8d420f8..185cf576a 100644
--- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java
+++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java
@@ -27,6 +27,7 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket;
+import org.geysermc.geyser.Constants;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
@@ -45,7 +46,7 @@ public class BedrockSetPlayerGameTypeTranslator extends PacketTranslator= 2 && session.hasPermission("geyser.settings.server")) {
+ if (session.getOpPermissionLevel() >= 2 && session.hasPermission(Constants.SERVER_SETTINGS_PERMISSION)) {
if (packet.getGamemode() != session.getGameMode().ordinal()) {
// Bedrock has more Gamemodes than Java, leading to cases 5 (for "default") and 6 (for "spectator") being sent
// https://github.com/CloudburstMC/Protocol/blob/3.0/bedrock-codec/src/main/java/org/cloudburstmc/protocol/bedrock/data/GameType.java
diff --git a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java
index ed97408b9..0311c4834 100644
--- a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java
+++ b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java
@@ -27,6 +27,7 @@ package org.geysermc.geyser.util;
import org.geysermc.cumulus.component.DropdownComponent;
import org.geysermc.cumulus.form.CustomForm;
+import org.geysermc.geyser.Constants;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.GameRule;
import org.geysermc.geyser.level.WorldManager;
@@ -79,7 +80,7 @@ public class SettingsUtils {
}
}
- boolean showGamerules = session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.gamerules");
+ boolean showGamerules = session.getOpPermissionLevel() >= 2 || session.hasPermission(Constants.SETTINGS_GAMERULES_PERMISSION);
if (showGamerules) {
builder.label("geyser.settings.title.game_rules")
.translator(MinecraftLocale::getLocaleString); // we need translate gamerules next