From a585fcad401e4fff2d78881ec05d5a0b36ba7d98 Mon Sep 17 00:00:00 2001 From: JohanVonElectrum Date: Tue, 6 Aug 2024 17:12:24 +0200 Subject: [PATCH 01/12] Reading mod metadata --- gradle.properties | 2 +- src/main/java/com/koralix/oneforall/OneForAll.java | 7 +++++++ .../koralix/oneforall/platform/ModMetadata.java | 9 +++++++++ .../com/koralix/oneforall/platform/Platform.java | 2 +- .../koralix/oneforall/platform/FabricPlatform.java | 14 +++++++++++++- 5 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/koralix/oneforall/platform/ModMetadata.java diff --git a/gradle.properties b/gradle.properties index c04e84e..de5f264 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ mod.id=oneforall mod.author=Koralix Studios mod.group=com.koralix.oneforall mod.description=One mod to replace them all -mod.version=5.8.2 +mod.version=0.1.0 fabric.loader=0.15.11 fabric.versions=1.20.1 diff --git a/src/main/java/com/koralix/oneforall/OneForAll.java b/src/main/java/com/koralix/oneforall/OneForAll.java index 3e49a96..328a74e 100644 --- a/src/main/java/com/koralix/oneforall/OneForAll.java +++ b/src/main/java/com/koralix/oneforall/OneForAll.java @@ -1,5 +1,6 @@ package com.koralix.oneforall; +import com.koralix.oneforall.platform.ModMetadata; import com.koralix.oneforall.platform.Platform; import com.koralix.oneforall.settings.SettingsManager; import org.slf4j.Logger; @@ -10,6 +11,7 @@ public abstract class OneForAll { private final Logger logger = LoggerFactory.getLogger("OneForAll"); private final Platform platform; + private final ModMetadata metadata; public static OneForAll getInstance() { return Initializer.instance; @@ -17,6 +19,7 @@ public static OneForAll getInstance() { public OneForAll(Platform platform) { this.platform = platform; + this.metadata = platform.getMetadata(MOD_ID); } abstract void onInitialize(); @@ -28,4 +31,8 @@ public Logger getLogger() { public Platform getPlatform() { return platform; } + + public ModMetadata getMetadata() { + return metadata; + } } diff --git a/src/main/java/com/koralix/oneforall/platform/ModMetadata.java b/src/main/java/com/koralix/oneforall/platform/ModMetadata.java new file mode 100644 index 0000000..cdf4d9e --- /dev/null +++ b/src/main/java/com/koralix/oneforall/platform/ModMetadata.java @@ -0,0 +1,9 @@ +package com.koralix.oneforall.platform; + +public record ModMetadata( + String id, + String name, + String version, + String description +) { +} diff --git a/src/main/java/com/koralix/oneforall/platform/Platform.java b/src/main/java/com/koralix/oneforall/platform/Platform.java index 018637c..ef2b0af 100644 --- a/src/main/java/com/koralix/oneforall/platform/Platform.java +++ b/src/main/java/com/koralix/oneforall/platform/Platform.java @@ -1,5 +1,5 @@ package com.koralix.oneforall.platform; public interface Platform { - + ModMetadata getMetadata(String modId); } diff --git a/versions/1.20.1-fabric/src/main/java/com/koralix/oneforall/platform/FabricPlatform.java b/versions/1.20.1-fabric/src/main/java/com/koralix/oneforall/platform/FabricPlatform.java index 10c5b8c..bd12076 100644 --- a/versions/1.20.1-fabric/src/main/java/com/koralix/oneforall/platform/FabricPlatform.java +++ b/versions/1.20.1-fabric/src/main/java/com/koralix/oneforall/platform/FabricPlatform.java @@ -1,5 +1,17 @@ package com.koralix.oneforall.platform; -public class FabricPlatform implements Platform { +import net.fabricmc.loader.api.FabricLoader; +public class FabricPlatform implements Platform { + @Override + public ModMetadata getMetadata(String modId) { + return FabricLoader.getInstance().getModContainer(modId) + .map(container -> new ModMetadata( + container.getMetadata().getId(), + container.getMetadata().getName(), + container.getMetadata().getVersion().getFriendlyString(), + container.getMetadata().getDescription() + )) + .orElse(null); + } } From c7ca729ce9e69ed0b5bbcdc8a0fa0eafbef06b82 Mon Sep 17 00:00:00 2001 From: Artik Date: Tue, 6 Aug 2024 21:07:25 +0200 Subject: [PATCH 02/12] Implemented OneForAll login protocol. --- .../koralix/oneforall/ClientOneForAll.java | 5 ++ .../oneforall/network/ClientLoginManager.java | 32 ++++++++ .../koralix/oneforall/ServerOneForAll.java | 3 + ...rverLoginNetworkAddonRegisterReceiver.java | 21 +++++ .../oneforall/network/ServerLoginManager.java | 81 +++++++++++++++++++ .../oneforall/settings/ServerSettings.java | 4 + src/main/resources/oneforall.mixins.json | 1 + 7 files changed, 147 insertions(+) create mode 100644 src/client/java/com/koralix/oneforall/network/ClientLoginManager.java create mode 100644 src/main/java/com/koralix/oneforall/mixin/fapi/FixServerLoginNetworkAddonRegisterReceiver.java create mode 100644 src/main/java/com/koralix/oneforall/network/ServerLoginManager.java diff --git a/src/client/java/com/koralix/oneforall/ClientOneForAll.java b/src/client/java/com/koralix/oneforall/ClientOneForAll.java index b0cd784..ce55ceb 100644 --- a/src/client/java/com/koralix/oneforall/ClientOneForAll.java +++ b/src/client/java/com/koralix/oneforall/ClientOneForAll.java @@ -3,7 +3,9 @@ import com.koralix.oneforall.input.ButtonEvent; import com.koralix.oneforall.input.hotkey.HotKey; import com.koralix.oneforall.input.InputManager; +import com.koralix.oneforall.network.ClientLoginManager; import com.koralix.oneforall.platform.Platform; +import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents; import org.lwjgl.glfw.GLFW; public class ClientOneForAll extends OneForAll { @@ -37,6 +39,9 @@ public void onInitializeClient() { .add(new ButtonEvent(GLFW.GLFW_KEY_A, GLFW.GLFW_PRESS, ButtonEvent.ButtonType.KEYBOARD))); inputManager.register(); + + + ClientLoginManager.init(); } public InputManager getInputManager() { diff --git a/src/client/java/com/koralix/oneforall/network/ClientLoginManager.java b/src/client/java/com/koralix/oneforall/network/ClientLoginManager.java new file mode 100644 index 0000000..271ebd9 --- /dev/null +++ b/src/client/java/com/koralix/oneforall/network/ClientLoginManager.java @@ -0,0 +1,32 @@ +package com.koralix.oneforall.network; + +import com.koralix.oneforall.OneForAll; +import com.koralix.oneforall.serde.Serde; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents; +import net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientLoginNetworkHandler; +import net.minecraft.network.PacketByteBuf; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +public class ClientLoginManager { + public static void init() { + ClientLoginConnectionEvents.QUERY_START.register((handler, client) -> { + ClientLoginNetworking.registerReceiver(ServerLoginManager.getChannel("hello"), ClientLoginManager::onHello); + }); + } + + private static CompletableFuture onHello(MinecraftClient client, ClientLoginNetworkHandler handler, PacketByteBuf buf, Consumer>> listenerAdder) { + PacketByteBuf response = PacketByteBufs.create(); + Serde.serialize(response, OneForAll.getInstance().getMetadata().version()); + + return CompletableFuture.completedFuture(response); + } + +} diff --git a/src/main/java/com/koralix/oneforall/ServerOneForAll.java b/src/main/java/com/koralix/oneforall/ServerOneForAll.java index c29553a..a8fed7e 100644 --- a/src/main/java/com/koralix/oneforall/ServerOneForAll.java +++ b/src/main/java/com/koralix/oneforall/ServerOneForAll.java @@ -1,5 +1,6 @@ package com.koralix.oneforall; +import com.koralix.oneforall.network.ServerLoginManager; import com.koralix.oneforall.platform.Platform; import com.koralix.oneforall.settings.ServerSettings; import com.koralix.oneforall.settings.SettingsManager; @@ -23,5 +24,7 @@ public void onInitialize() { public void onInitializeServer() { getLogger().info("Initializing OneForAll server..."); + + ServerLoginManager.init(); } } diff --git a/src/main/java/com/koralix/oneforall/mixin/fapi/FixServerLoginNetworkAddonRegisterReceiver.java b/src/main/java/com/koralix/oneforall/mixin/fapi/FixServerLoginNetworkAddonRegisterReceiver.java new file mode 100644 index 0000000..21e743b --- /dev/null +++ b/src/main/java/com/koralix/oneforall/mixin/fapi/FixServerLoginNetworkAddonRegisterReceiver.java @@ -0,0 +1,21 @@ +package com.koralix.oneforall.mixin.fapi; + +import net.fabricmc.fabric.impl.networking.GlobalReceiverRegistry; +import net.fabricmc.fabric.impl.networking.server.ServerLoginNetworkAddon; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ServerLoginNetworkAddon.class) +public class FixServerLoginNetworkAddonRegisterReceiver { + @Redirect( + method = "handle(ILnet/minecraft/network/PacketByteBuf;)Z", + at = @At( + value = "INVOKE", + target = "Lnet/fabricmc/fabric/impl/networking/GlobalReceiverRegistry;getHandler(Lnet/minecraft/util/Identifier;)Ljava/lang/Object;" + )) + private Object fix(GlobalReceiverRegistry instance, Identifier channelName) { + return ((ServerLoginNetworkAddon) (Object) this).getHandler(channelName); + } +} diff --git a/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java b/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java new file mode 100644 index 0000000..40302a2 --- /dev/null +++ b/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java @@ -0,0 +1,81 @@ +package com.koralix.oneforall.network; + +import com.koralix.oneforall.OneForAll; +import com.koralix.oneforall.serde.Serde; +import com.koralix.oneforall.settings.ServerSettings; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents; +import net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerLoginNetworkHandler; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +import java.util.concurrent.CompletableFuture; + +public class ServerLoginManager { + public static void init() { + ServerLoginConnectionEvents.QUERY_START.register(ServerLoginManager::onQueryStart); + } + + private static PacketByteBuf createHelloPacket() { + String modVersion = OneForAll.getInstance().getMetadata().version(); + boolean enforceProtocol = ServerSettings.ENFORCE_PROTOCOL.value(); + + PacketByteBuf buf = PacketByteBufs.create(); + Serde.serialize(buf, modVersion); + Serde.serialize(buf, enforceProtocol); + + return buf; + } + + public static Identifier getChannel(String name) { + return Identifier.of(OneForAll.MOD_ID, name); + } + + private static void onQueryStart( + ServerLoginNetworkHandler handler, + MinecraftServer server, + PacketSender sender, + ServerLoginNetworking.LoginSynchronizer synchronizer + ) { + // RECEIVE + CompletableFuture future = new CompletableFuture<>(); + + ServerLoginNetworking.registerReceiver(handler, getChannel("hello"), (server1, handler1, understood, buf, synchronizer1, responseSender) -> { + if (!onQueryResponse(server1, handler1, understood, buf, synchronizer1, responseSender)) { + handler.disconnect(Text.of("Disconnected by OneForAll")); + } + + future.complete(null); + }); + + // SEND + sender.sendPacket(getChannel("hello"), createHelloPacket()); + + synchronizer.waitFor(future); + } + + private static boolean onQueryResponse( + MinecraftServer server, + ServerLoginNetworkHandler handler, + boolean understood, + PacketByteBuf buf, + ServerLoginNetworking.LoginSynchronizer synchronizer, + PacketSender responseSender + ) { + if (!understood && ServerSettings.ENFORCE_PROTOCOL.value()) { + return false; + } + + if (understood) { + String version = buf.readString(); + OneForAll.getInstance().getLogger().debug("Client connected with version: {}", version); + } + + return true; + } +} \ No newline at end of file diff --git a/src/main/java/com/koralix/oneforall/settings/ServerSettings.java b/src/main/java/com/koralix/oneforall/settings/ServerSettings.java index 7e96002..366c22d 100644 --- a/src/main/java/com/koralix/oneforall/settings/ServerSettings.java +++ b/src/main/java/com/koralix/oneforall/settings/ServerSettings.java @@ -11,4 +11,8 @@ private ServerSettings() { public static final ConfigValue PROTOCOL_ENABLED = ConfigValue.of(true) .test(Objects::nonNull) .build(); + + public static final ConfigValue ENFORCE_PROTOCOL = ConfigValue.of(true) + .test(Objects::nonNull) + .build(); } diff --git a/src/main/resources/oneforall.mixins.json b/src/main/resources/oneforall.mixins.json index e270712..72f6cea 100644 --- a/src/main/resources/oneforall.mixins.json +++ b/src/main/resources/oneforall.mixins.json @@ -4,6 +4,7 @@ "package": "com.koralix.oneforall.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ + "fapi.FixServerLoginNetworkAddonRegisterReceiver" ], "injectors": { "defaultRequire": 1 From 9eee2e5e801427c64996b59a28e6640a7fd23955 Mon Sep 17 00:00:00 2001 From: JohanVonElectrum Date: Fri, 9 Aug 2024 22:50:35 +0200 Subject: [PATCH 03/12] Replaced permissions by a more general Predicate --- .../oneforall/permissions/PermissionSet.java | 173 ------------------ .../oneforall/permissions/Permissions.java | 19 -- .../oneforall/settings/ConfigValue.java | 21 ++- .../settings/ConfigValueBuilder.java | 10 +- .../settings/ConfigValueWrapper.java | 11 +- .../oneforall/settings/ServerSettings.java | 1 + 6 files changed, 40 insertions(+), 195 deletions(-) delete mode 100644 src/main/java/com/koralix/oneforall/permissions/PermissionSet.java delete mode 100644 src/main/java/com/koralix/oneforall/permissions/Permissions.java diff --git a/src/main/java/com/koralix/oneforall/permissions/PermissionSet.java b/src/main/java/com/koralix/oneforall/permissions/PermissionSet.java deleted file mode 100644 index 03fe8d1..0000000 --- a/src/main/java/com/koralix/oneforall/permissions/PermissionSet.java +++ /dev/null @@ -1,173 +0,0 @@ -package com.koralix.oneforall.permissions; - -import org.jetbrains.annotations.NotNull; - -import java.util.*; - -public class PermissionSet implements Set { - private final Map children = new HashMap<>(); - - @Override - public int size() { - int size = children.size(); - for (PermissionSet child : children.values()) { - size += child.size(); - } - return size; - } - - @Override - public boolean isEmpty() { - return children.isEmpty(); - } - - @Override - public boolean contains(Object o) { - if (!(o instanceof String str)) return false; - if (children.containsKey(str) || children.containsKey("*")) return true; - for (PermissionSet child : children.values()) { - if (child.contains(str)) return true; - } - return false; - } - - @NotNull - @Override - public Iterator iterator() { - return new Iterator<>() { - private final Stack>> stack; - private final Stack pathStack; - private String nextPath; - - { - stack = new Stack<>(); - pathStack = new Stack<>(); - stack.push(children.entrySet().iterator()); - advance(); - } - - private void advance() { - nextPath = null; - while (!stack.isEmpty()) { - Iterator> iterator = stack.peek(); - if (!iterator.hasNext()) { - stack.pop(); - if (!pathStack.isEmpty()) { - pathStack.pop(); - } - continue; - } - - Map.Entry entry = iterator.next(); - String key = entry.getKey(); - - if (!pathStack.isEmpty()) { - pathStack.push(pathStack.peek() + "." + key); - } else { - pathStack.push(key); - } - - nextPath = pathStack.peek(); - stack.push(entry.getValue().children.entrySet().iterator()); - return; - } - } - - @Override - public boolean hasNext() { - return nextPath != null; - } - - @Override - public String next() { - if (!hasNext()) throw new NoSuchElementException("No more elements"); - String path = nextPath; - advance(); - return path; - } - }; - } - - @NotNull - @Override - public Object @NotNull [] toArray() { - return children.keySet().toArray(); - } - - @NotNull - @Override - public T @NotNull [] toArray(@NotNull T @NotNull [] a) { - return children.keySet().toArray(a); - } - - @Override - public boolean add(String s) { - if (s.isEmpty()) return false; - String[] parts = s.split("\\.", 2); - if (parts.length == 1) { - return children.putIfAbsent(parts[0], new PermissionSet()) == null; - } else { - PermissionSet child = children.computeIfAbsent(parts[0], k -> new PermissionSet()); - return child.add(parts[1]); - } - } - - @Override - public boolean remove(Object o) { - if (!(o instanceof String str)) return false; - String[] parts = str.split("\\.", 2); - if (parts.length == 1) { - return children.remove(parts[0]) != null; - } else { - PermissionSet child = children.get(parts[0]); - if (child == null) return false; - boolean removed = child.remove(parts[1]); - if (child.isEmpty()) { - children.remove(parts[0]); - } - return removed; - } - } - - @Override - public boolean containsAll(@NotNull Collection c) { - for (Object o : c) { - if (!contains(o)) return false; - } - return true; - } - - @Override - public boolean addAll(@NotNull Collection c) { - boolean modified = false; - for (String s : c) { - modified |= add(s); - } - return modified; - } - - @Override - public boolean retainAll(@NotNull Collection c) { - List toRemove = new ArrayList<>(); - for (String s : this) { - if (!c.contains(s)) { - toRemove.add(s); - } - } - return removeAll(toRemove); - } - - @Override - public boolean removeAll(@NotNull Collection c) { - boolean modified = false; - for (Object o : c) { - modified |= remove(o); - } - return modified; - } - - @Override - public void clear() { - children.clear(); - } -} diff --git a/src/main/java/com/koralix/oneforall/permissions/Permissions.java b/src/main/java/com/koralix/oneforall/permissions/Permissions.java deleted file mode 100644 index 36cf7b7..0000000 --- a/src/main/java/com/koralix/oneforall/permissions/Permissions.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.koralix.oneforall.permissions; - -import net.minecraft.server.command.ServerCommandSource; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.function.Predicate; - -public class Permissions { - private static final Map permissions = new HashMap<>(); - - public static Predicate hasPermission(String permission) { - return commandSource -> commandSource.hasPermissionLevel(4) - || (commandSource.isExecutedByPlayer() - && commandSource.getPlayer() != null - && permissions.get(commandSource.getPlayer().getUuid()).contains(permission)); - } -} diff --git a/src/main/java/com/koralix/oneforall/settings/ConfigValue.java b/src/main/java/com/koralix/oneforall/settings/ConfigValue.java index f1fef2f..42a0067 100644 --- a/src/main/java/com/koralix/oneforall/settings/ConfigValue.java +++ b/src/main/java/com/koralix/oneforall/settings/ConfigValue.java @@ -4,10 +4,13 @@ import com.koralix.oneforall.serde.Serde; import com.koralix.oneforall.serde.Serialize; import net.minecraft.network.PacketByteBuf; +import net.minecraft.server.command.ServerCommandSource; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import java.util.function.Predicate; + public interface ConfigValue extends Serialize, Deserialize { @Contract(value = "_ -> new", pure = true) static @NotNull ConfigValueBuilder of(@NotNull T value) { @@ -21,18 +24,28 @@ public interface ConfigValue extends Serialize, Deserialize { /** * Get the registry of the config value + * * @return the registry of the config value */ Identifier registry(); /** * Get the identifier of the config value + * * @return the identifier of the config value */ Identifier id(); + /** + * Test if the user satisfies the permission predicate + * + * @return whether the user satisfies the permission predicate + */ + boolean permission(ServerCommandSource source); + /** * Reset the config value to the default value + * * @return if the config value was reset successfully */ default boolean reset() { @@ -41,6 +54,7 @@ default boolean reset() { /** * Restore the config value to standard settings + * * @return if the config value was restored successfully */ default boolean restore() { @@ -49,26 +63,29 @@ default boolean restore() { /** * Get the nominal value of the config value + * * @return the nominal value */ T nominalValue(); /** * Get the default value of the config value + * * @return the default value */ T defaultValue(); /** * Set the default value of the config value + * * @param value the new default value * @return if the default value was set successfully */ - boolean defaultValue(T value); /** * Get the current value of the config value + * * @return the current value */ T value(); @@ -76,6 +93,7 @@ default boolean restore() { /** * Set the current value of the config value + * * @param value the new value * @return if the value was set successfully */ @@ -83,6 +101,7 @@ default boolean restore() { /** * Get the class of the config value + * * @return the class of the config value */ Class clazz(); diff --git a/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java b/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java index c4843e6..c557283 100644 --- a/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java +++ b/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java @@ -1,5 +1,6 @@ package com.koralix.oneforall.settings; +import net.minecraft.server.command.ServerCommandSource; import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; @@ -9,6 +10,7 @@ public class ConfigValueBuilder { private final Class clazz; private final T value; private Predicate validator = null; + private Predicate permission = null; private Identifier registry = null; private Identifier id = null; @@ -35,6 +37,11 @@ public ConfigValueBuilder test(Predicate validator) { return this; } + public ConfigValueBuilder permission(Predicate permission) { + this.permission = permission; + return this; + } + public ConfigValueBuilder registry(@NotNull Identifier registry) { this.registry = registry; return this; @@ -51,7 +58,8 @@ public ConfigValue build() { id, clazz, value, - validator == null ? t -> true : validator + validator == null ? t -> true : validator, + permission == null ? t -> true : permission ); } } diff --git a/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java b/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java index 45c474a..5538d51 100644 --- a/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java +++ b/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java @@ -1,5 +1,6 @@ package com.koralix.oneforall.settings; +import net.minecraft.server.command.ServerCommandSource; import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; @@ -16,6 +17,7 @@ public class ConfigValueWrapper implements ConfigValue { private final Class clazz; private final T nominalValue; private final Predicate validator; + private final Predicate permission; Identifier registry; Identifier id; @@ -28,13 +30,15 @@ public class ConfigValueWrapper implements ConfigValue { @NotNull Identifier id, @NotNull Class clazz, T nominalValue, - @NotNull Predicate validator + @NotNull Predicate validator, + @NotNull Predicate permission ) { if (!validator.test(nominalValue)) throw new IllegalArgumentException("Invalid nominal value"); this.clazz = clazz; this.nominalValue = nominalValue; this.validator = validator; + this.permission = permission; this.registry = registry; this.id = id; @@ -53,6 +57,11 @@ public Identifier id() { return this.id; } + @Override + public boolean permission(ServerCommandSource source) { + return this.permission.test(source); + } + @Override public T nominalValue() { return this.nominalValue; diff --git a/src/main/java/com/koralix/oneforall/settings/ServerSettings.java b/src/main/java/com/koralix/oneforall/settings/ServerSettings.java index 7e96002..f751aa2 100644 --- a/src/main/java/com/koralix/oneforall/settings/ServerSettings.java +++ b/src/main/java/com/koralix/oneforall/settings/ServerSettings.java @@ -10,5 +10,6 @@ private ServerSettings() { public static final ConfigValue PROTOCOL_ENABLED = ConfigValue.of(true) .test(Objects::nonNull) + .permission(source -> source.hasPermissionLevel(4)) .build(); } From cf7532d25fa76368f97653ab693750f490d406db Mon Sep 17 00:00:00 2001 From: Artik Date: Fri, 9 Aug 2024 23:43:03 +0200 Subject: [PATCH 04/12] Implemented client protocol settings. --- .../oneforall/network/ClientLoginManager.java | 21 +++++++++++++++++- .../oneforall/settings/ClientSettings.java | 9 ++++++++ .../settings/ProtocolUsageConditions.java | 7 ++++++ .../oneforall/network/ServerLoginManager.java | 22 ++++++++++--------- 4 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 src/client/java/com/koralix/oneforall/settings/ClientSettings.java create mode 100644 src/client/java/com/koralix/oneforall/settings/ProtocolUsageConditions.java diff --git a/src/client/java/com/koralix/oneforall/network/ClientLoginManager.java b/src/client/java/com/koralix/oneforall/network/ClientLoginManager.java index 271ebd9..746fbf9 100644 --- a/src/client/java/com/koralix/oneforall/network/ClientLoginManager.java +++ b/src/client/java/com/koralix/oneforall/network/ClientLoginManager.java @@ -2,6 +2,8 @@ import com.koralix.oneforall.OneForAll; import com.koralix.oneforall.serde.Serde; +import com.koralix.oneforall.settings.ClientSettings; +import com.koralix.oneforall.settings.ProtocolUsageConditions; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents; @@ -22,10 +24,27 @@ public static void init() { }); } + private static boolean doesClientEnableProtocol(boolean enforceProtocol) { + ProtocolUsageConditions usageConditions = ClientSettings.PROTOCOL_USAGE_CONDITIONS.value(); + + return switch (usageConditions) { + case Always -> true; + case OnlyEnforced -> enforceProtocol; + case Never -> false; + }; + } + private static CompletableFuture onHello(MinecraftClient client, ClientLoginNetworkHandler handler, PacketByteBuf buf, Consumer>> listenerAdder) { + String version = Serde.deserialize(buf, String.class); + boolean enforceProtocol = Serde.deserialize(buf, Boolean.class); + + boolean enablesProtocol = doesClientEnableProtocol(enforceProtocol); + if (!enablesProtocol) { + return CompletableFuture.completedFuture(null); + } + PacketByteBuf response = PacketByteBufs.create(); Serde.serialize(response, OneForAll.getInstance().getMetadata().version()); - return CompletableFuture.completedFuture(response); } diff --git a/src/client/java/com/koralix/oneforall/settings/ClientSettings.java b/src/client/java/com/koralix/oneforall/settings/ClientSettings.java new file mode 100644 index 0000000..0b6a1ca --- /dev/null +++ b/src/client/java/com/koralix/oneforall/settings/ClientSettings.java @@ -0,0 +1,9 @@ +package com.koralix.oneforall.settings; + +import java.util.Objects; + +public class ClientSettings { + public static final ConfigValue PROTOCOL_USAGE_CONDITIONS = ConfigValue.of(ProtocolUsageConditions.Always) + .test(Objects::nonNull) + .build(); +} diff --git a/src/client/java/com/koralix/oneforall/settings/ProtocolUsageConditions.java b/src/client/java/com/koralix/oneforall/settings/ProtocolUsageConditions.java new file mode 100644 index 0000000..933c4a4 --- /dev/null +++ b/src/client/java/com/koralix/oneforall/settings/ProtocolUsageConditions.java @@ -0,0 +1,7 @@ +package com.koralix.oneforall.settings; + +public enum ProtocolUsageConditions { + Always, + OnlyEnforced, + Never +} diff --git a/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java b/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java index 40302a2..c0497c9 100644 --- a/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java +++ b/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java @@ -14,8 +14,10 @@ import net.minecraft.text.Text; import net.minecraft.util.Identifier; +import java.util.Optional; import java.util.concurrent.CompletableFuture; + public class ServerLoginManager { public static void init() { ServerLoginConnectionEvents.QUERY_START.register(ServerLoginManager::onQueryStart); @@ -46,9 +48,8 @@ private static void onQueryStart( CompletableFuture future = new CompletableFuture<>(); ServerLoginNetworking.registerReceiver(handler, getChannel("hello"), (server1, handler1, understood, buf, synchronizer1, responseSender) -> { - if (!onQueryResponse(server1, handler1, understood, buf, synchronizer1, responseSender)) { - handler.disconnect(Text.of("Disconnected by OneForAll")); - } + Optional errorMessage = onQueryResponse(server1, handler1, understood, buf, synchronizer1, responseSender); + errorMessage.ifPresent(s -> handler.disconnect(Text.of("Disconnected by OneForAll\n\nReason: " + s))); future.complete(null); }); @@ -59,7 +60,7 @@ private static void onQueryStart( synchronizer.waitFor(future); } - private static boolean onQueryResponse( + private static Optional onQueryResponse( MinecraftServer server, ServerLoginNetworkHandler handler, boolean understood, @@ -68,14 +69,15 @@ private static boolean onQueryResponse( PacketSender responseSender ) { if (!understood && ServerSettings.ENFORCE_PROTOCOL.value()) { - return false; + return Optional.of("One-For-All Mod Protocol is required to connect to the server."); + } else if (!understood) { + return Optional.empty(); } - if (understood) { - String version = buf.readString(); - OneForAll.getInstance().getLogger().debug("Client connected with version: {}", version); - } + // If understood + String version = buf.readString(); + OneForAll.getInstance().getLogger().debug("Client connected with version: {}", version); - return true; + return Optional.empty(); } } \ No newline at end of file From 1653cb7c0b4f5ed8c2ef25069fa13dda90c6eba5 Mon Sep 17 00:00:00 2001 From: Artik Date: Sat, 10 Aug 2024 00:03:03 +0200 Subject: [PATCH 05/12] Add permission level 4 to the ENFORCE_PROTOCOL rule. --- src/main/java/com/koralix/oneforall/settings/ServerSettings.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/koralix/oneforall/settings/ServerSettings.java b/src/main/java/com/koralix/oneforall/settings/ServerSettings.java index bc60ca1..b8454a7 100644 --- a/src/main/java/com/koralix/oneforall/settings/ServerSettings.java +++ b/src/main/java/com/koralix/oneforall/settings/ServerSettings.java @@ -15,5 +15,6 @@ private ServerSettings() { public static final ConfigValue ENFORCE_PROTOCOL = ConfigValue.of(true) .test(Objects::nonNull) + .permission(source -> source.hasPermissionLevel(4)) .build(); } From 9d23d461cad9a61f2d53d585450f5bb417cd591d Mon Sep 17 00:00:00 2001 From: JohanVonElectrum Date: Sun, 11 Aug 2024 21:17:38 +0200 Subject: [PATCH 06/12] Added command /ofa minimal impl --- .../koralix/oneforall/ClientOneForAll.java | 4 + .../oneforall/settings/ClientSettings.java | 1 + .../java/com/koralix/oneforall/OneForAll.java | 9 +- .../koralix/oneforall/commands/Commands.java | 45 ++++++ .../commands/DynEnumArgumentType.java | 26 ++++ .../oneforall/commands/OfaCommand.java | 142 ++++++++++++++++++ .../oneforall/network/ServerLoginManager.java | 2 + .../oneforall/settings/ConfigValue.java | 7 +- .../settings/ConfigValueBuilder.java | 14 -- .../settings/ConfigValueWrapper.java | 17 +-- .../oneforall/settings/ServerSettings.java | 4 +- .../oneforall/settings/SettingEntry.java | 50 ++++++ .../oneforall/settings/SettingsManager.java | 78 +++++++--- .../oneforall/settings/SettingsRegistry.java | 24 +++ .../com/koralix/oneforall/Initializer.java | 2 +- 15 files changed, 365 insertions(+), 60 deletions(-) create mode 100644 src/main/java/com/koralix/oneforall/commands/Commands.java create mode 100644 src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java create mode 100644 src/main/java/com/koralix/oneforall/commands/OfaCommand.java create mode 100644 src/main/java/com/koralix/oneforall/settings/SettingEntry.java diff --git a/src/client/java/com/koralix/oneforall/ClientOneForAll.java b/src/client/java/com/koralix/oneforall/ClientOneForAll.java index ce55ceb..4fe95e1 100644 --- a/src/client/java/com/koralix/oneforall/ClientOneForAll.java +++ b/src/client/java/com/koralix/oneforall/ClientOneForAll.java @@ -5,6 +5,8 @@ import com.koralix.oneforall.input.InputManager; import com.koralix.oneforall.network.ClientLoginManager; import com.koralix.oneforall.platform.Platform; +import com.koralix.oneforall.settings.ClientSettings; +import com.koralix.oneforall.settings.SettingsManager; import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents; import org.lwjgl.glfw.GLFW; @@ -22,6 +24,8 @@ public static ClientOneForAll getInstance() { @Override public void onInitialize() { getLogger().info("Initializing OneForAll..."); + + SettingsManager.register(ClientSettings.class); } public void onInitializeClient() { diff --git a/src/client/java/com/koralix/oneforall/settings/ClientSettings.java b/src/client/java/com/koralix/oneforall/settings/ClientSettings.java index 0b6a1ca..1db5444 100644 --- a/src/client/java/com/koralix/oneforall/settings/ClientSettings.java +++ b/src/client/java/com/koralix/oneforall/settings/ClientSettings.java @@ -2,6 +2,7 @@ import java.util.Objects; +@SettingsRegistry(id = "client_settings", env = SettingsRegistry.Env.CLIENT) public class ClientSettings { public static final ConfigValue PROTOCOL_USAGE_CONDITIONS = ConfigValue.of(ProtocolUsageConditions.Always) .test(Objects::nonNull) diff --git a/src/main/java/com/koralix/oneforall/OneForAll.java b/src/main/java/com/koralix/oneforall/OneForAll.java index 328a74e..14f464e 100644 --- a/src/main/java/com/koralix/oneforall/OneForAll.java +++ b/src/main/java/com/koralix/oneforall/OneForAll.java @@ -1,8 +1,9 @@ package com.koralix.oneforall; +import com.koralix.oneforall.commands.Commands; import com.koralix.oneforall.platform.ModMetadata; import com.koralix.oneforall.platform.Platform; -import com.koralix.oneforall.settings.SettingsManager; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,6 +23,12 @@ public OneForAll(Platform platform) { this.metadata = platform.getMetadata(MOD_ID); } + public final void initialize() { + CommandRegistrationCallback.EVENT.register(Commands::register); + + onInitialize(); + } + abstract void onInitialize(); public Logger getLogger() { diff --git a/src/main/java/com/koralix/oneforall/commands/Commands.java b/src/main/java/com/koralix/oneforall/commands/Commands.java new file mode 100644 index 0000000..07fdee3 --- /dev/null +++ b/src/main/java/com/koralix/oneforall/commands/Commands.java @@ -0,0 +1,45 @@ +package com.koralix.oneforall.commands; + +import com.mojang.brigadier.CommandDispatcher; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; + +public final class Commands { + private Commands() { + throw new UnsupportedOperationException("This class cannot be instantiated"); + } + + public static void register( + CommandDispatcher dispatcher, + CommandRegistryAccess registryAccess, + CommandManager.RegistrationEnvironment environment + ) { + common(dispatcher, registryAccess, environment); + if (environment.integrated) integrated(dispatcher, registryAccess); + else if (environment.dedicated) dedicated(dispatcher, registryAccess); + else throw new UnsupportedOperationException("Unknown environment"); + } + + private static void integrated( + CommandDispatcher dispatcher, + CommandRegistryAccess registryAccess + ) { + // Register integrated commands here + } + + private static void dedicated( + CommandDispatcher dispatcher, + CommandRegistryAccess registryAccess + ) { + // Register dedicated commands here + } + + private static void common( + CommandDispatcher dispatcher, + CommandRegistryAccess registryAccess, + CommandManager.RegistrationEnvironment environment + ) { + OfaCommand.register(dispatcher, registryAccess, environment); + } +} diff --git a/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java b/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java new file mode 100644 index 0000000..d5eff9f --- /dev/null +++ b/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java @@ -0,0 +1,26 @@ +package com.koralix.oneforall.commands; + +import com.mojang.brigadier.arguments.ArgumentType; +import net.minecraft.command.argument.EnumArgumentType; +import net.minecraft.util.StringIdentifiable; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Supplier; + +public class DynEnumArgumentType & StringIdentifiable> extends EnumArgumentType { + protected DynEnumArgumentType(Supplier valuesSupplier) { + super(StringIdentifiable.createCodec(valuesSupplier), valuesSupplier); + } + + @Contract("_ -> new") + public static & StringIdentifiable> @NotNull DynEnumArgumentType create(T[] values) { + return new DynEnumArgumentType<>(() -> values); + } + + @Contract("_ -> new") + @SuppressWarnings("unchecked") + public static & StringIdentifiable> @NotNull DynEnumArgumentType create(@NotNull Class clazz) { + return new DynEnumArgumentType<>(() -> (T[]) clazz.getEnumConstants()); + } +} diff --git a/src/main/java/com/koralix/oneforall/commands/OfaCommand.java b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java new file mode 100644 index 0000000..ba9a313 --- /dev/null +++ b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java @@ -0,0 +1,142 @@ +package com.koralix.oneforall.commands; + +import com.koralix.oneforall.settings.ConfigValue; +import com.koralix.oneforall.settings.SettingEntry; +import com.koralix.oneforall.settings.SettingsManager; +import com.koralix.oneforall.settings.SettingsRegistry; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.*; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.NotNull; + +import static net.minecraft.server.command.CommandManager.argument; +import static net.minecraft.server.command.CommandManager.literal; + +public final class OfaCommand { + private OfaCommand() { + throw new UnsupportedOperationException("This class cannot be instantiated"); + } + + public static void register( + CommandDispatcher dispatcher, + CommandRegistryAccess registryAccess, + CommandManager.RegistrationEnvironment environment + ) { + LiteralArgumentBuilder ofa = literal("ofa"); + ofa.then(settings()); + dispatcher.register(ofa); + } + + private static LiteralArgumentBuilder settings() { + LiteralArgumentBuilder settings = literal("settings").executes(OfaCommand::listSettings); + SettingsManager.forEach(SettingsRegistry.Env.SERVER, (entry, configValue) -> + settings.then(setting(entry)) + ); + return settings; + } + + private static LiteralArgumentBuilder setting(@NotNull SettingEntry entry) { + return literal(entry.id().toString()) + .executes(context -> getSetting(context, entry)) + .then(settingArgument(entry.setting()) + .executes(context -> setSetting(context, entry))) + .then(literal("default").then(settingArgument(entry.setting()) + .executes(context -> setDefaultSetting(context, entry)))) + .then(literal("reset") + .executes(context -> setSetting(context, entry))) + .then(literal("restore") + .executes(context -> setDefaultSetting(context, entry))); + } + + private static int listSettings(@NotNull CommandContext context) { + int[] result = {0}; // int* result; + SettingsManager.forEach(SettingsRegistry.Env.SERVER, (entry, configValue) -> + result[0] += getSetting(context, entry) + ); + return result[0]; + } + + private static int getSetting( + @NotNull CommandContext context, + @NotNull SettingEntry entry + ) { + context.getSource().sendFeedback( + () -> Text.translatable(entry.translation()) + .append(":\n") + .append("Value: ") + .append(entry.setting().value().toString()) + .append("\n") + .append("Default: ") + .append(entry.setting().defaultValue().toString()) + .append("\n") + .append("Nominal: ") + .append(entry.setting().nominalValue().toString()), + false + ); + return 1; + } + + private static int setSetting( + @NotNull CommandContext context, + @NotNull SettingEntry entry + ) { + try { + T value = context.getArgument("value", entry.setting().clazz()); + entry.setting().value(value); + } catch (IllegalArgumentException e) { + entry.setting().reset(); + } + + return 1; + } + + private static int setDefaultSetting( + @NotNull CommandContext context, + @NotNull SettingEntry entry + ) { + try { + T value = context.getArgument("value", entry.setting().clazz()); + entry.setting().defaultValue(value); + } catch (IllegalArgumentException e) { + entry.setting().restore(); + } + + return 1; + } + + private static @NotNull RequiredArgumentBuilder settingArgument( + @NotNull ConfigValue setting + ) { + return argument("value", settingArgumentType(setting.clazz())); + } + + @SuppressWarnings("unchecked") + private static @NotNull ArgumentType settingArgumentType(@NotNull Class clazz) { + if (clazz.isEnum()) + return (ArgumentType) DynEnumArgumentType.create(clazz); + if (clazz == Boolean.class) + return (ArgumentType) BoolArgumentType.bool(); + if (clazz == String.class) + return (ArgumentType) StringArgumentType.string(); + if (clazz == Byte.class) + return (ArgumentType) IntegerArgumentType.integer(Byte.MIN_VALUE, Byte.MAX_VALUE); + if (clazz == Short.class) + return (ArgumentType) IntegerArgumentType.integer(Short.MIN_VALUE, Short.MAX_VALUE); + if (clazz == Integer.class) + return (ArgumentType) IntegerArgumentType.integer(); + if (clazz == Long.class) + return (ArgumentType) LongArgumentType.longArg(); + if (clazz == Float.class) + return (ArgumentType) FloatArgumentType.floatArg(); + if (clazz == Double.class) + return (ArgumentType) DoubleArgumentType.doubleArg(); + throw new UnsupportedOperationException("Unsupported setting type: " + clazz); + } +} diff --git a/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java b/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java index c0497c9..8a8291b 100644 --- a/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java +++ b/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java @@ -44,6 +44,8 @@ private static void onQueryStart( PacketSender sender, ServerLoginNetworking.LoginSynchronizer synchronizer ) { + if (!ServerSettings.PROTOCOL_ENABLED.value()) return; + // RECEIVE CompletableFuture future = new CompletableFuture<>(); diff --git a/src/main/java/com/koralix/oneforall/settings/ConfigValue.java b/src/main/java/com/koralix/oneforall/settings/ConfigValue.java index 42a0067..2f71b73 100644 --- a/src/main/java/com/koralix/oneforall/settings/ConfigValue.java +++ b/src/main/java/com/koralix/oneforall/settings/ConfigValue.java @@ -5,12 +5,9 @@ import com.koralix.oneforall.serde.Serialize; import net.minecraft.network.PacketByteBuf; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.util.Identifier; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import java.util.function.Predicate; - public interface ConfigValue extends Serialize, Deserialize { @Contract(value = "_ -> new", pure = true) static @NotNull ConfigValueBuilder of(@NotNull T value) { @@ -27,14 +24,14 @@ public interface ConfigValue extends Serialize, Deserialize { * * @return the registry of the config value */ - Identifier registry(); + SettingsRegistry registry(); /** * Get the identifier of the config value * * @return the identifier of the config value */ - Identifier id(); + SettingEntry entry(); /** * Test if the user satisfies the permission predicate diff --git a/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java b/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java index c557283..899c2db 100644 --- a/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java +++ b/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java @@ -11,8 +11,6 @@ public class ConfigValueBuilder { private final T value; private Predicate validator = null; private Predicate permission = null; - private Identifier registry = null; - private Identifier id = null; @SuppressWarnings("unchecked") ConfigValueBuilder(@NotNull T value) { @@ -42,20 +40,8 @@ public ConfigValueBuilder permission(Predicate permissio return this; } - public ConfigValueBuilder registry(@NotNull Identifier registry) { - this.registry = registry; - return this; - } - - public ConfigValueBuilder id(@NotNull Identifier id) { - this.id = id; - return this; - } - public ConfigValue build() { return new ConfigValueWrapper<>( - registry, - id, clazz, value, validator == null ? t -> true : validator, diff --git a/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java b/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java index 5538d51..429da26 100644 --- a/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java +++ b/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java @@ -1,7 +1,6 @@ package com.koralix.oneforall.settings; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; import java.util.function.Predicate; @@ -19,15 +18,12 @@ public class ConfigValueWrapper implements ConfigValue { private final Predicate validator; private final Predicate permission; - Identifier registry; - Identifier id; + SettingEntry entry = null; private T defaultValue; private T value; ConfigValueWrapper( - @NotNull Identifier registry, - @NotNull Identifier id, @NotNull Class clazz, T nominalValue, @NotNull Predicate validator, @@ -40,21 +36,18 @@ public class ConfigValueWrapper implements ConfigValue { this.validator = validator; this.permission = permission; - this.registry = registry; - this.id = id; - this.defaultValue = nominalValue; this.value = nominalValue; } @Override - public Identifier registry() { - return this.registry; + public SettingsRegistry registry() { + return this.entry.registry(); } @Override - public Identifier id() { - return this.id; + public SettingEntry entry() { + return this.entry; } @Override diff --git a/src/main/java/com/koralix/oneforall/settings/ServerSettings.java b/src/main/java/com/koralix/oneforall/settings/ServerSettings.java index b8454a7..73ad5b6 100644 --- a/src/main/java/com/koralix/oneforall/settings/ServerSettings.java +++ b/src/main/java/com/koralix/oneforall/settings/ServerSettings.java @@ -2,7 +2,7 @@ import java.util.Objects; -@SettingsRegistry(id = "server_settings") +@SettingsRegistry(id = "server_settings", env = SettingsRegistry.Env.SERVER) public final class ServerSettings { private ServerSettings() { throw new UnsupportedOperationException("This class cannot be instantiated"); @@ -13,7 +13,7 @@ private ServerSettings() { .permission(source -> source.hasPermissionLevel(4)) .build(); - public static final ConfigValue ENFORCE_PROTOCOL = ConfigValue.of(true) + public static final ConfigValue ENFORCE_PROTOCOL = ConfigValue.of(false) .test(Objects::nonNull) .permission(source -> source.hasPermissionLevel(4)) .build(); diff --git a/src/main/java/com/koralix/oneforall/settings/SettingEntry.java b/src/main/java/com/koralix/oneforall/settings/SettingEntry.java new file mode 100644 index 0000000..1b4dee2 --- /dev/null +++ b/src/main/java/com/koralix/oneforall/settings/SettingEntry.java @@ -0,0 +1,50 @@ +package com.koralix.oneforall.settings; + +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.NotNull; + +public class SettingEntry { + private final SettingsRegistry registry; + private final ConfigValue setting; + private final Identifier settingId; + + public SettingEntry( + @NotNull SettingsRegistry registry, + @NotNull Identifier settingId, + @NotNull ConfigValue setting + ) { + this.registry = registry; + this.setting = setting; + this.settingId = Identifier.of( + SettingsManager.identifier(registry).toTranslationKey(), + settingId.getNamespace().equals(SettingsManager.identifier(registry).getNamespace()) + ? settingId.getPath() + : settingId.toTranslationKey() + ); + } + + public SettingsRegistry registry() { + return registry; + } + + public ConfigValue setting() { + return setting; + } + + public Identifier registryId() { + return SettingsManager.identifier(registry); + } + + public Identifier id() { + return settingId; + } + + public String translation() { + return settingId.toTranslationKey("settings"); + } + + @Override + public String toString() { + return settingId.toString(); + } +} diff --git a/src/main/java/com/koralix/oneforall/settings/SettingsManager.java b/src/main/java/com/koralix/oneforall/settings/SettingsManager.java index d6f0266..9978bdc 100644 --- a/src/main/java/com/koralix/oneforall/settings/SettingsManager.java +++ b/src/main/java/com/koralix/oneforall/settings/SettingsManager.java @@ -1,31 +1,45 @@ package com.koralix.oneforall.settings; -import com.koralix.oneforall.OneForAll; import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; public final class SettingsManager { - private static final Map> CLASSES = new HashMap<>(); - private static final Map>> SETTINGS = new HashMap<>(); + private static final Map> REGISTRIES = new HashMap<>(); + private static final Map, ConfigValue>> SETTINGS = new HashMap<>(); private SettingsManager() { throw new UnsupportedOperationException("This class cannot be instantiated"); } + public static @NotNull SettingsRegistry registry(@NotNull Class clazz) { + SettingsRegistry registry = clazz.getAnnotation(SettingsRegistry.class); + if (registry == null) throw new IllegalArgumentException("Class is not annotated with @SettingsRegistry"); + return registry; + } + + public static Identifier identifier(@NotNull SettingsRegistry registry) { + return Identifier.of(registry.namespace(), registry.id()); + } + + public static Identifier identifier(@NotNull Class clazz) { + return identifier(registry(clazz)); + } + /** * Register an instance of a class with settings * @param clazz the class to register * @param the type of the class */ public static void register(@NotNull Class clazz) { - SettingsRegistry registry = clazz.getAnnotation(SettingsRegistry.class); - if (registry == null) throw new IllegalArgumentException("Class is not annotated with @SettingsRegistry"); - - Identifier registryId = Identifier.of(OneForAll.MOD_ID, registry.id()); - CLASSES.put(registryId, clazz); + SettingsRegistry registry = registry(clazz); + Identifier registryId = identifier(registry); + REGISTRIES.computeIfAbsent(registry.env(), k -> new HashSet<>()).add(registryId); for (var field : clazz.getDeclaredFields()) { if (!ConfigValue.class.isAssignableFrom(field.getType())) continue; @@ -33,38 +47,52 @@ public static void register(@NotNull Class clazz) { try { @SuppressWarnings("unchecked") ConfigValue value = (ConfigValue) field.get(null); - register(registryId, Identifier.of(OneForAll.MOD_ID, field.getName().toLowerCase()), value); + SettingEntry entry = new SettingEntry<>(registry, registryId.withPath(field.getName().toLowerCase()), value); + if (value instanceof ConfigValueWrapper wrapper) { + if (wrapper.entry == null) wrapper.entry = entry; + entry = wrapper.entry; + } + register(entry); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Field '" + field.getName() + "' is not static"); } } } - private static void register(Identifier registryId, Identifier id, ConfigValue value) { - if (value instanceof ConfigValueWrapper wrapper) { - if (wrapper.registry == null) wrapper.registry = registryId; - if (wrapper.id == null) wrapper.id = id; - } - if (SETTINGS.computeIfAbsent(registryId, k -> new HashMap<>()).putIfAbsent(id, value) == null) return; - throw new IllegalArgumentException("Setting with id " + id + " is already registered"); + private static void register(SettingEntry entry) { + if (SETTINGS.computeIfAbsent(entry.registryId(), k -> new HashMap<>()).putIfAbsent(entry, entry.setting()) == null) return; + throw new IllegalArgumentException("Setting with id " + entry + " is already registered"); } /** - * Get a setting by its registry and id + * Get a setting by its registry and entry * @param registry the registry of the setting - * @param id the id of the setting + * @param entry the entry of the setting * @return the setting */ - public static ConfigValue get(Identifier registry, Identifier id) { - return SETTINGS.getOrDefault(registry, Map.of()).get(id); + @SuppressWarnings("unchecked") + public static ConfigValue get(Identifier registry, SettingEntry entry) { + return (ConfigValue) SETTINGS.getOrDefault(registry, Map.of()).get(entry); + } + + /** + * Iterate over all settings + */ + public static void forEach(BiConsumer, ConfigValue> action) { + SETTINGS.forEach((registry, settings) -> settings.forEach(action)); + } + + /** + * Iterate over all settings in a registry + */ + public static void forEach(Identifier registry, BiConsumer, ConfigValue> action) { + SETTINGS.getOrDefault(registry, Map.of()).forEach(action); } /** - * Get a registry by its identifier - * @param registry the identifier of the registry - * @return the registry + * Iterate over all settings of a specific environment */ - public static Class registry(Identifier registry) { - return CLASSES.get(registry); + public static void forEach(SettingsRegistry.Env env, BiConsumer, ConfigValue> action) { + REGISTRIES.getOrDefault(env, Set.of()).forEach(registry -> forEach(registry, action)); } } diff --git a/src/main/java/com/koralix/oneforall/settings/SettingsRegistry.java b/src/main/java/com/koralix/oneforall/settings/SettingsRegistry.java index 838ba96..f7c359e 100644 --- a/src/main/java/com/koralix/oneforall/settings/SettingsRegistry.java +++ b/src/main/java/com/koralix/oneforall/settings/SettingsRegistry.java @@ -1,5 +1,8 @@ package com.koralix.oneforall.settings; +import com.koralix.oneforall.OneForAll; +import net.minecraft.util.Identifier; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -14,4 +17,25 @@ @Target(ElementType.TYPE) public @interface SettingsRegistry { String id(); + String namespace() default OneForAll.MOD_ID; + Env env() default Env.SERVER; + + enum Env { + /** + * The settings registry is for the client + */ + CLIENT, + /** + * The settings registry is for any server + */ + SERVER, + /** + * The settings registry is for an integrated server + */ + INTEGRATED, + /** + * The settings registry is for a dedicated server + */ + DEDICATED + } } diff --git a/versions/1.20.1-fabric/src/main/java/com/koralix/oneforall/Initializer.java b/versions/1.20.1-fabric/src/main/java/com/koralix/oneforall/Initializer.java index 8b06aac..f143738 100644 --- a/versions/1.20.1-fabric/src/main/java/com/koralix/oneforall/Initializer.java +++ b/versions/1.20.1-fabric/src/main/java/com/koralix/oneforall/Initializer.java @@ -25,6 +25,6 @@ private static OneForAll createInstance() { @Override public void onInitialize() { - instance.onInitialize(); + instance.initialize(); } } From f47e7b64ff11a8946abfdf6cd9e5e56f0d53595d Mon Sep 17 00:00:00 2001 From: JohanVonElectrum Date: Sun, 11 Aug 2024 21:18:29 +0200 Subject: [PATCH 07/12] Optimized imports --- src/client/java/com/koralix/oneforall/ClientOneForAll.java | 3 +-- .../java/com/koralix/oneforall/network/ClientLoginManager.java | 1 - .../com/koralix/oneforall/commands/DynEnumArgumentType.java | 1 - src/main/java/com/koralix/oneforall/commands/OfaCommand.java | 1 - .../java/com/koralix/oneforall/network/ServerLoginManager.java | 1 - .../com/koralix/oneforall/settings/ConfigValueBuilder.java | 1 - .../java/com/koralix/oneforall/settings/SettingsRegistry.java | 1 - 7 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/client/java/com/koralix/oneforall/ClientOneForAll.java b/src/client/java/com/koralix/oneforall/ClientOneForAll.java index 4fe95e1..38dce5d 100644 --- a/src/client/java/com/koralix/oneforall/ClientOneForAll.java +++ b/src/client/java/com/koralix/oneforall/ClientOneForAll.java @@ -1,13 +1,12 @@ package com.koralix.oneforall; import com.koralix.oneforall.input.ButtonEvent; -import com.koralix.oneforall.input.hotkey.HotKey; import com.koralix.oneforall.input.InputManager; +import com.koralix.oneforall.input.hotkey.HotKey; import com.koralix.oneforall.network.ClientLoginManager; import com.koralix.oneforall.platform.Platform; import com.koralix.oneforall.settings.ClientSettings; import com.koralix.oneforall.settings.SettingsManager; -import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents; import org.lwjgl.glfw.GLFW; public class ClientOneForAll extends OneForAll { diff --git a/src/client/java/com/koralix/oneforall/network/ClientLoginManager.java b/src/client/java/com/koralix/oneforall/network/ClientLoginManager.java index 746fbf9..a75ff9a 100644 --- a/src/client/java/com/koralix/oneforall/network/ClientLoginManager.java +++ b/src/client/java/com/koralix/oneforall/network/ClientLoginManager.java @@ -12,7 +12,6 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientLoginNetworkHandler; import net.minecraft.network.PacketByteBuf; -import org.jetbrains.annotations.Nullable; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; diff --git a/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java b/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java index d5eff9f..2644e70 100644 --- a/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java +++ b/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java @@ -1,6 +1,5 @@ package com.koralix.oneforall.commands; -import com.mojang.brigadier.arguments.ArgumentType; import net.minecraft.command.argument.EnumArgumentType; import net.minecraft.util.StringIdentifiable; import org.jetbrains.annotations.Contract; diff --git a/src/main/java/com/koralix/oneforall/commands/OfaCommand.java b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java index ba9a313..036a2c5 100644 --- a/src/main/java/com/koralix/oneforall/commands/OfaCommand.java +++ b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java @@ -13,7 +13,6 @@ import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; -import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; import static net.minecraft.server.command.CommandManager.argument; diff --git a/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java b/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java index 8a8291b..7c15aff 100644 --- a/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java +++ b/src/main/java/com/koralix/oneforall/network/ServerLoginManager.java @@ -7,7 +7,6 @@ import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking; -import net.minecraft.network.ClientConnection; import net.minecraft.network.PacketByteBuf; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerLoginNetworkHandler; diff --git a/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java b/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java index 899c2db..f087189 100644 --- a/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java +++ b/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java @@ -1,7 +1,6 @@ package com.koralix.oneforall.settings; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; import java.util.function.Predicate; diff --git a/src/main/java/com/koralix/oneforall/settings/SettingsRegistry.java b/src/main/java/com/koralix/oneforall/settings/SettingsRegistry.java index f7c359e..987fafe 100644 --- a/src/main/java/com/koralix/oneforall/settings/SettingsRegistry.java +++ b/src/main/java/com/koralix/oneforall/settings/SettingsRegistry.java @@ -1,7 +1,6 @@ package com.koralix.oneforall.settings; import com.koralix.oneforall.OneForAll; -import net.minecraft.util.Identifier; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; From 3781bd1e4abad71ab6f6af8911bb5ddb76c6d0b4 Mon Sep 17 00:00:00 2001 From: JohanVonElectrum Date: Mon, 12 Aug 2024 16:54:01 +0200 Subject: [PATCH 08/12] Added /cofa command --- .../koralix/oneforall/ClientOneForAll.java | 5 +- .../oneforall/commands/ClientCommands.java | 16 +++ .../oneforall/commands/ClientOfaCommand.java | 27 +++++ .../settings/ProtocolUsageConditions.java | 14 ++- .../oneforall/commands/OfaCommand.java | 106 +++++++++++------- .../oneforall/settings/SettingsManager.java | 2 +- 6 files changed, 128 insertions(+), 42 deletions(-) create mode 100644 src/client/java/com/koralix/oneforall/commands/ClientCommands.java create mode 100644 src/client/java/com/koralix/oneforall/commands/ClientOfaCommand.java diff --git a/src/client/java/com/koralix/oneforall/ClientOneForAll.java b/src/client/java/com/koralix/oneforall/ClientOneForAll.java index 38dce5d..f3f2516 100644 --- a/src/client/java/com/koralix/oneforall/ClientOneForAll.java +++ b/src/client/java/com/koralix/oneforall/ClientOneForAll.java @@ -1,5 +1,6 @@ package com.koralix.oneforall; +import com.koralix.oneforall.commands.ClientCommands; import com.koralix.oneforall.input.ButtonEvent; import com.koralix.oneforall.input.InputManager; import com.koralix.oneforall.input.hotkey.HotKey; @@ -7,6 +8,7 @@ import com.koralix.oneforall.platform.Platform; import com.koralix.oneforall.settings.ClientSettings; import com.koralix.oneforall.settings.SettingsManager; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import org.lwjgl.glfw.GLFW; public class ClientOneForAll extends OneForAll { @@ -25,6 +27,8 @@ public void onInitialize() { getLogger().info("Initializing OneForAll..."); SettingsManager.register(ClientSettings.class); + + ClientCommandRegistrationCallback.EVENT.register(ClientCommands::register); } public void onInitializeClient() { @@ -43,7 +47,6 @@ public void onInitializeClient() { inputManager.register(); - ClientLoginManager.init(); } diff --git a/src/client/java/com/koralix/oneforall/commands/ClientCommands.java b/src/client/java/com/koralix/oneforall/commands/ClientCommands.java new file mode 100644 index 0000000..a30a9ec --- /dev/null +++ b/src/client/java/com/koralix/oneforall/commands/ClientCommands.java @@ -0,0 +1,16 @@ +package com.koralix.oneforall.commands; + +import com.mojang.brigadier.CommandDispatcher; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.command.CommandRegistryAccess; + +public final class ClientCommands { + private ClientCommands() { + throw new UnsupportedOperationException("This class cannot be instantiated"); + } + + + public static void register(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess) { + ClientOfaCommand.register(dispatcher, registryAccess); + } +} diff --git a/src/client/java/com/koralix/oneforall/commands/ClientOfaCommand.java b/src/client/java/com/koralix/oneforall/commands/ClientOfaCommand.java new file mode 100644 index 0000000..894779f --- /dev/null +++ b/src/client/java/com/koralix/oneforall/commands/ClientOfaCommand.java @@ -0,0 +1,27 @@ +package com.koralix.oneforall.commands; + +import com.koralix.oneforall.settings.SettingsRegistry; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.command.CommandRegistryAccess; +import org.jetbrains.annotations.NotNull; + +import static com.koralix.oneforall.commands.OfaCommand.settings; + +public final class ClientOfaCommand { + private ClientOfaCommand() { + throw new UnsupportedOperationException("This class cannot be instantiated"); + } + + + public static void register( + @NotNull CommandDispatcher dispatcher, + CommandRegistryAccess registryAccess + ) { + LiteralArgumentBuilder cofa = ClientCommandManager.literal("cofa"); + cofa.then(settings(ClientCommandManager::literal, ClientCommandManager::argument, SettingsRegistry.Env.CLIENT)); + dispatcher.register(cofa); + } +} diff --git a/src/client/java/com/koralix/oneforall/settings/ProtocolUsageConditions.java b/src/client/java/com/koralix/oneforall/settings/ProtocolUsageConditions.java index 933c4a4..cba7d9a 100644 --- a/src/client/java/com/koralix/oneforall/settings/ProtocolUsageConditions.java +++ b/src/client/java/com/koralix/oneforall/settings/ProtocolUsageConditions.java @@ -1,7 +1,17 @@ package com.koralix.oneforall.settings; -public enum ProtocolUsageConditions { +import net.minecraft.util.StringIdentifiable; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public enum ProtocolUsageConditions implements StringIdentifiable { Always, OnlyEnforced, - Never + Never; + + @Contract(pure = true) + @Override + public @NotNull String asString() { + return name(); + } } diff --git a/src/main/java/com/koralix/oneforall/commands/OfaCommand.java b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java index 036a2c5..fb7c146 100644 --- a/src/main/java/com/koralix/oneforall/commands/OfaCommand.java +++ b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java @@ -10,13 +10,17 @@ import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.command.CommandSource; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; import org.jetbrains.annotations.NotNull; -import static net.minecraft.server.command.CommandManager.argument; -import static net.minecraft.server.command.CommandManager.literal; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; public final class OfaCommand { private OfaCommand() { @@ -24,37 +28,45 @@ private OfaCommand() { } public static void register( - CommandDispatcher dispatcher, + @NotNull CommandDispatcher dispatcher, CommandRegistryAccess registryAccess, CommandManager.RegistrationEnvironment environment ) { - LiteralArgumentBuilder ofa = literal("ofa"); - ofa.then(settings()); + LiteralArgumentBuilder ofa = CommandManager.literal("ofa"); + ofa.then(settings(CommandManager::literal, CommandManager::argument, SettingsRegistry.Env.SERVER)); dispatcher.register(ofa); } - private static LiteralArgumentBuilder settings() { - LiteralArgumentBuilder settings = literal("settings").executes(OfaCommand::listSettings); - SettingsManager.forEach(SettingsRegistry.Env.SERVER, (entry, configValue) -> - settings.then(setting(entry)) - ); + public static LiteralArgumentBuilder settings( + @NotNull Function> ofaLiteral, + @NotNull BiFunction, RequiredArgumentBuilder> ofaArgument, + SettingsRegistry.Env @NotNull ... envs + ) { + LiteralArgumentBuilder settings = ofaLiteral.apply("settings").executes(OfaCommand::listSettings); + for (SettingsRegistry.Env env : envs) { + SettingsManager.forEach(env, (entry, configValue) -> settings.then(setting(ofaLiteral, ofaArgument, entry))); + } return settings; } - private static LiteralArgumentBuilder setting(@NotNull SettingEntry entry) { - return literal(entry.id().toString()) + private static LiteralArgumentBuilder setting( + @NotNull Function> ofaLiteral, + @NotNull BiFunction, RequiredArgumentBuilder> ofaArgument, + @NotNull SettingEntry entry + ) { + return ofaLiteral.apply(entry.id().toString()) .executes(context -> getSetting(context, entry)) - .then(settingArgument(entry.setting()) + .then(settingArgument(ofaArgument, entry.setting()) .executes(context -> setSetting(context, entry))) - .then(literal("default").then(settingArgument(entry.setting()) + .then(ofaLiteral.apply("default").then(settingArgument(ofaArgument, entry.setting()) .executes(context -> setDefaultSetting(context, entry)))) - .then(literal("reset") + .then(ofaLiteral.apply("reset") .executes(context -> setSetting(context, entry))) - .then(literal("restore") + .then(ofaLiteral.apply("restore") .executes(context -> setDefaultSetting(context, entry))); } - private static int listSettings(@NotNull CommandContext context) { + private static int listSettings(@NotNull CommandContext context) { int[] result = {0}; // int* result; SettingsManager.forEach(SettingsRegistry.Env.SERVER, (entry, configValue) -> result[0] += getSetting(context, entry) @@ -62,28 +74,44 @@ private static int listSettings(@NotNull CommandContext con return result[0]; } - private static int getSetting( - @NotNull CommandContext context, + private static int getSetting( + @NotNull CommandContext context, @NotNull SettingEntry entry ) { - context.getSource().sendFeedback( - () -> Text.translatable(entry.translation()) - .append(":\n") - .append("Value: ") - .append(entry.setting().value().toString()) - .append("\n") - .append("Default: ") - .append(entry.setting().defaultValue().toString()) - .append("\n") - .append("Nominal: ") - .append(entry.setting().nominalValue().toString()), - false - ); + Method method; + final Text text = Text.translatable(entry.translation()) + .append(":\n") + .append("Value: ") + .append(entry.setting().value().toString()) + .append("\n") + .append("Default: ") + .append(entry.setting().defaultValue().toString()) + .append("\n") + .append("Nominal: ") + .append(entry.setting().nominalValue().toString()); + Object arg1 = text; + try { + method = context.getSource().getClass().getDeclaredMethod("sendFeedback", Supplier.class, boolean.class); + arg1 = (Supplier) () -> text; + } catch (NoSuchMethodException e) { + try { + method = context.getSource().getClass().getDeclaredMethod("sendFeedback", Text.class, boolean.class); + } catch (NoSuchMethodException ex) { + throw new UnsupportedOperationException("Unsupported command source: " + context.getSource().getClass().getName()); + } + } + + try { + method.invoke(context.getSource(), arg1, false); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new UnsupportedOperationException("Failed to invoke method: " + method.getName()); + } + return 1; } - private static int setSetting( - @NotNull CommandContext context, + private static int setSetting( + @NotNull CommandContext context, @NotNull SettingEntry entry ) { try { @@ -96,8 +124,8 @@ private static int setSetting( return 1; } - private static int setDefaultSetting( - @NotNull CommandContext context, + private static int setDefaultSetting( + @NotNull CommandContext context, @NotNull SettingEntry entry ) { try { @@ -110,10 +138,12 @@ private static int setDefaultSetting( return 1; } - private static @NotNull RequiredArgumentBuilder settingArgument( + @SuppressWarnings("unchecked") + private static @NotNull RequiredArgumentBuilder settingArgument( + @NotNull BiFunction, RequiredArgumentBuilder> ofaArgument, @NotNull ConfigValue setting ) { - return argument("value", settingArgumentType(setting.clazz())); + return (RequiredArgumentBuilder) ofaArgument.apply("value", settingArgumentType(setting.clazz())); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/koralix/oneforall/settings/SettingsManager.java b/src/main/java/com/koralix/oneforall/settings/SettingsManager.java index 9978bdc..fe0c7ab 100644 --- a/src/main/java/com/koralix/oneforall/settings/SettingsManager.java +++ b/src/main/java/com/koralix/oneforall/settings/SettingsManager.java @@ -59,7 +59,7 @@ public static void register(@NotNull Class clazz) { } } - private static void register(SettingEntry entry) { + private static void register(@NotNull SettingEntry entry) { if (SETTINGS.computeIfAbsent(entry.registryId(), k -> new HashMap<>()).putIfAbsent(entry, entry.setting()) == null) return; throw new IllegalArgumentException("Setting with id " + entry + " is already registered"); } From 55868da54c5c75b871f7f9e86ef41d525f0cea09 Mon Sep 17 00:00:00 2001 From: JohanVonElectrum Date: Mon, 12 Aug 2024 17:55:46 +0200 Subject: [PATCH 09/12] Better OfaCommand literal order --- .../oneforall/commands/OfaCommand.java | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/koralix/oneforall/commands/OfaCommand.java b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java index fb7c146..c535d3f 100644 --- a/src/main/java/com/koralix/oneforall/commands/OfaCommand.java +++ b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java @@ -43,27 +43,34 @@ public static LiteralArgumentBuilder settings( SettingsRegistry.Env @NotNull ... envs ) { LiteralArgumentBuilder settings = ofaLiteral.apply("settings").executes(OfaCommand::listSettings); + LiteralArgumentBuilder def = ofaLiteral.apply("default"); + LiteralArgumentBuilder restore = ofaLiteral.apply("restore"); for (SettingsRegistry.Env env : envs) { - SettingsManager.forEach(env, (entry, configValue) -> settings.then(setting(ofaLiteral, ofaArgument, entry))); + SettingsManager.forEach(env, (entry, configValue) -> { + settings.then(setting(ofaLiteral, ofaArgument, entry, def, restore)); + }); } + settings.then(def); + settings.then(restore); return settings; } private static LiteralArgumentBuilder setting( @NotNull Function> ofaLiteral, @NotNull BiFunction, RequiredArgumentBuilder> ofaArgument, - @NotNull SettingEntry entry + @NotNull SettingEntry entry, + @NotNull LiteralArgumentBuilder def, + @NotNull LiteralArgumentBuilder restore ) { + def.then(ofaLiteral.apply(entry.id().toString()) + .executes(context -> setSetting(context, entry)) + .then(settingArgument(ofaArgument, entry.setting()) + .executes(context -> setDefaultSetting(context, entry)))); + restore.executes(context -> setDefaultSetting(context, entry)); return ofaLiteral.apply(entry.id().toString()) .executes(context -> getSetting(context, entry)) .then(settingArgument(ofaArgument, entry.setting()) - .executes(context -> setSetting(context, entry))) - .then(ofaLiteral.apply("default").then(settingArgument(ofaArgument, entry.setting()) - .executes(context -> setDefaultSetting(context, entry)))) - .then(ofaLiteral.apply("reset") - .executes(context -> setSetting(context, entry))) - .then(ofaLiteral.apply("restore") - .executes(context -> setDefaultSetting(context, entry))); + .executes(context -> setSetting(context, entry))); } private static int listSettings(@NotNull CommandContext context) { @@ -78,7 +85,7 @@ private static int getSetting( @NotNull CommandContext context, @NotNull SettingEntry entry ) { - Method method; + Method method = null; final Text text = Text.translatable(entry.translation()) .append(":\n") .append("Value: ") @@ -93,16 +100,14 @@ private static int getSetting( try { method = context.getSource().getClass().getDeclaredMethod("sendFeedback", Supplier.class, boolean.class); arg1 = (Supplier) () -> text; - } catch (NoSuchMethodException e) { + method.invoke(context.getSource(), arg1, false); + } catch (NoSuchMethodException e1) { try { - method = context.getSource().getClass().getDeclaredMethod("sendFeedback", Text.class, boolean.class); - } catch (NoSuchMethodException ex) { + method = context.getSource().getClass().getDeclaredMethod("sendFeedback", Text.class); + method.invoke(context.getSource(), arg1); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e2) { throw new UnsupportedOperationException("Unsupported command source: " + context.getSource().getClass().getName()); } - } - - try { - method.invoke(context.getSource(), arg1, false); } catch (IllegalAccessException | InvocationTargetException e) { throw new UnsupportedOperationException("Failed to invoke method: " + method.getName()); } From 631d05ec0bd2a3fef76819a8f06cb3556d8533a4 Mon Sep 17 00:00:00 2001 From: JohanVonElectrum Date: Mon, 26 Aug 2024 17:13:41 +0200 Subject: [PATCH 10/12] better config validators (untested but should work...) --- .../oneforall/commands/OfaCommand.java | 19 +++++++++++-- .../oneforall/settings/ConfigValidator.java | 25 +++++++++++++++++ .../oneforall/settings/ConfigValue.java | 14 ++++++---- .../settings/ConfigValueBuilder.java | 16 +++++++++-- .../settings/ConfigValueWrapper.java | 28 ++++++++++--------- 5 files changed, 77 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/koralix/oneforall/settings/ConfigValidator.java diff --git a/src/main/java/com/koralix/oneforall/commands/OfaCommand.java b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java index c535d3f..e91fb58 100644 --- a/src/main/java/com/koralix/oneforall/commands/OfaCommand.java +++ b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java @@ -63,10 +63,13 @@ private static LiteralArgumentBuilder setting( @NotNull LiteralArgumentBuilder restore ) { def.then(ofaLiteral.apply(entry.id().toString()) + .requires(source -> !(source instanceof ServerCommandSource scs) || entry.setting().permission(scs)) .executes(context -> setSetting(context, entry)) .then(settingArgument(ofaArgument, entry.setting()) .executes(context -> setDefaultSetting(context, entry)))); - restore.executes(context -> setDefaultSetting(context, entry)); + restore + .requires(source -> !(source instanceof ServerCommandSource scs) || entry.setting().permission(scs)) + .executes(context -> setDefaultSetting(context, entry)); return ofaLiteral.apply(entry.id().toString()) .executes(context -> getSetting(context, entry)) .then(settingArgument(ofaArgument, entry.setting()) @@ -85,6 +88,8 @@ private static int getSetting( @NotNull CommandContext context, @NotNull SettingEntry entry ) { + if (context.getSource() instanceof ServerCommandSource scs && !entry.setting().permission(scs)) return 0; + Method method = null; final Text text = Text.translatable(entry.translation()) .append(":\n") @@ -121,7 +126,11 @@ private static int setSetting( ) { try { T value = context.getArgument("value", entry.setting().clazz()); - entry.setting().value(value); + Text text = entry.setting().value(value); + if (text != null && context.getSource() instanceof ServerCommandSource scs) { + scs.sendError(text); + return 0; + } } catch (IllegalArgumentException e) { entry.setting().reset(); } @@ -135,7 +144,11 @@ private static int setDefaultSetting( ) { try { T value = context.getArgument("value", entry.setting().clazz()); - entry.setting().defaultValue(value); + Text text = entry.setting().defaultValue(value); + if (text != null && context.getSource() instanceof ServerCommandSource scs) { + scs.sendError(text); + return 0; + } } catch (IllegalArgumentException e) { entry.setting().restore(); } diff --git a/src/main/java/com/koralix/oneforall/settings/ConfigValidator.java b/src/main/java/com/koralix/oneforall/settings/ConfigValidator.java new file mode 100644 index 0000000..b9c52a1 --- /dev/null +++ b/src/main/java/com/koralix/oneforall/settings/ConfigValidator.java @@ -0,0 +1,25 @@ +package com.koralix.oneforall.settings; + +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; + +@FunctionalInterface +public interface ConfigValidator { + Text test(T value); + + default ConfigValidator and(@NotNull ConfigValidator other) { + return value -> { + Text result = test(value); + return result == null ? other.test(value) : result; + }; + } + + default ConfigValidator or(@NotNull ConfigValidator other) { + return value -> { + Text a = test(value); + if (a == null) return null; + Text b = other.test(value); + return b == null ? null : Text.literal("- ").append(a).append("\n- ").append(b); + }; + } +} diff --git a/src/main/java/com/koralix/oneforall/settings/ConfigValue.java b/src/main/java/com/koralix/oneforall/settings/ConfigValue.java index 2f71b73..99fead5 100644 --- a/src/main/java/com/koralix/oneforall/settings/ConfigValue.java +++ b/src/main/java/com/koralix/oneforall/settings/ConfigValue.java @@ -5,6 +5,7 @@ import com.koralix.oneforall.serde.Serialize; import net.minecraft.network.PacketByteBuf; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -45,8 +46,8 @@ public interface ConfigValue extends Serialize, Deserialize { * * @return if the config value was reset successfully */ - default boolean reset() { - return value(defaultValue()); + default void reset() { + value(defaultValue()); } /** @@ -54,8 +55,9 @@ default boolean reset() { * * @return if the config value was restored successfully */ - default boolean restore() { - return defaultValue(nominalValue()) && reset(); + default void restore() { + defaultValue(nominalValue()); + reset(); } /** @@ -78,7 +80,7 @@ default boolean restore() { * @param value the new default value * @return if the default value was set successfully */ - boolean defaultValue(T value); + Text defaultValue(T value); /** * Get the current value of the config value @@ -94,7 +96,7 @@ default boolean restore() { * @param value the new value * @return if the value was set successfully */ - boolean value(T value); + Text value(T value); /** * Get the class of the config value diff --git a/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java b/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java index f087189..880cbce 100644 --- a/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java +++ b/src/main/java/com/koralix/oneforall/settings/ConfigValueBuilder.java @@ -1,6 +1,7 @@ package com.koralix.oneforall.settings; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; import org.jetbrains.annotations.NotNull; import java.util.function.Predicate; @@ -8,7 +9,7 @@ public class ConfigValueBuilder { private final Class clazz; private final T value; - private Predicate validator = null; + private ConfigValidator validator = null; private Predicate permission = null; @SuppressWarnings("unchecked") @@ -22,7 +23,7 @@ public class ConfigValueBuilder { this.value = null; } - public ConfigValueBuilder test(Predicate validator) { + public ConfigValueBuilder test(ConfigValidator validator) { if (validator == null) return this; if (this.validator == null) { @@ -34,6 +35,15 @@ public ConfigValueBuilder test(Predicate validator) { return this; } + public ConfigValueBuilder test(Predicate validator, Text message) { + ConfigValidator test = value -> validator.test(value) ? null : message; + return test(test); + } + + public ConfigValueBuilder test(Predicate validator) { + return test(validator, Text.of("Invalid value")); + } + public ConfigValueBuilder permission(Predicate permission) { this.permission = permission; return this; @@ -43,7 +53,7 @@ public ConfigValue build() { return new ConfigValueWrapper<>( clazz, value, - validator == null ? t -> true : validator, + validator == null ? t -> null : validator, permission == null ? t -> true : permission ); } diff --git a/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java b/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java index 429da26..492e1c5 100644 --- a/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java +++ b/src/main/java/com/koralix/oneforall/settings/ConfigValueWrapper.java @@ -1,7 +1,9 @@ package com.koralix.oneforall.settings; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.function.Predicate; @@ -15,7 +17,7 @@ public class ConfigValueWrapper implements ConfigValue { private final Class clazz; private final T nominalValue; - private final Predicate validator; + private final ConfigValidator validator; private final Predicate permission; SettingEntry entry = null; @@ -26,10 +28,11 @@ public class ConfigValueWrapper implements ConfigValue { ConfigValueWrapper( @NotNull Class clazz, T nominalValue, - @NotNull Predicate validator, + @NotNull ConfigValidator validator, @NotNull Predicate permission ) { - if (!validator.test(nominalValue)) throw new IllegalArgumentException("Invalid nominal value"); + Text err = validator.test(nominalValue); + if (err != null) throw new IllegalArgumentException(err.getString()); this.clazz = clazz; this.nominalValue = nominalValue; @@ -66,10 +69,8 @@ public T defaultValue() { } @Override - public boolean defaultValue(T value) { - if (!this.test(value)) return false; - this.defaultValue = value; - return true; + public Text defaultValue(T value) { + return this.tested(value, () -> this.defaultValue = value); } @Override @@ -78,10 +79,8 @@ public T value() { } @Override - public boolean value(T value) { - if (!this.test(value)) return false; - this.value = value; - return true; + public Text value(T value) { + return this.tested(value, () -> this.value = value); } @Override @@ -89,7 +88,10 @@ public Class clazz() { return this.clazz; } - private boolean test(T value) { - return this.validator.test(value); + private @Nullable Text tested(T value, Runnable action) { + Text err = this.validator.test(value); + if (err != null) return err; + action.run(); + return null; } } From c8ade27054f0bc3a3fec7855fc14c75e8fe5b8b4 Mon Sep 17 00:00:00 2001 From: JohanVonElectrum Date: Sun, 1 Sep 2024 16:34:34 +0200 Subject: [PATCH 11/12] Probably a fix for enum arg types --- build.gradle.kts | 2 ++ .../oneforall/commands/DynEnumArgumentType.java | 15 ++++++--------- src/main/resources/fabric.mod.json | 1 + src/main/resources/oneforall.accesswidener | 3 +++ 4 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 src/main/resources/oneforall.accesswidener diff --git a/build.gradle.kts b/build.gradle.kts index 0111ee3..4810104 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -66,6 +66,8 @@ tasks.named("test") { } loom { + accessWidenerPath = file("../../src/main/resources/${mod.id}.accesswidener") + splitEnvironmentSourceSets() mods { diff --git a/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java b/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java index 2644e70..15c1a94 100644 --- a/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java +++ b/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java @@ -7,19 +7,16 @@ import java.util.function.Supplier; -public class DynEnumArgumentType & StringIdentifiable> extends EnumArgumentType { - protected DynEnumArgumentType(Supplier valuesSupplier) { - super(StringIdentifiable.createCodec(valuesSupplier), valuesSupplier); - } - +public class DynEnumArgumentType { @Contract("_ -> new") - public static & StringIdentifiable> @NotNull DynEnumArgumentType create(T[] values) { - return new DynEnumArgumentType<>(() -> values); + public static & StringIdentifiable> @NotNull EnumArgumentType create(T[] values) { + Supplier supplier = () -> values; + return new EnumArgumentType<>(StringIdentifiable.createCodec(supplier), supplier); } @Contract("_ -> new") @SuppressWarnings("unchecked") - public static & StringIdentifiable> @NotNull DynEnumArgumentType create(@NotNull Class clazz) { - return new DynEnumArgumentType<>(() -> (T[]) clazz.getEnumConstants()); + public static & StringIdentifiable> @NotNull EnumArgumentType create(@NotNull Class clazz) { + return create((T[]) clazz.getEnumConstants()); } } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index e991e2c..44d8d38 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -26,6 +26,7 @@ "environment": "client" } ], + "accessWidener": "${id}.accesswidener", "depends": { "fabricloader": ">=0.15.0", "minecraft": "${minecraft_dependency}" diff --git a/src/main/resources/oneforall.accesswidener b/src/main/resources/oneforall.accesswidener new file mode 100644 index 0000000..9e91673 --- /dev/null +++ b/src/main/resources/oneforall.accesswidener @@ -0,0 +1,3 @@ +accessWidener v2 named + +accessible method net/minecraft/command/argument/EnumArgumentType (Lcom/mojang/serialization/Codec;Ljava/util/function/Supplier;)V \ No newline at end of file From 049494a3f9f8e2f894e100909cc49e9e1613d814 Mon Sep 17 00:00:00 2001 From: JohanVonElectrum Date: Sun, 1 Sep 2024 17:44:27 +0200 Subject: [PATCH 12/12] The real fix --- .../commands/ArgumentTypeHelper.java | 88 +++++++++++++++++++ .../commands/DynEnumArgumentType.java | 22 ----- .../oneforall/commands/OfaCommand.java | 40 +-------- 3 files changed, 92 insertions(+), 58 deletions(-) create mode 100644 src/main/java/com/koralix/oneforall/commands/ArgumentTypeHelper.java delete mode 100644 src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java diff --git a/src/main/java/com/koralix/oneforall/commands/ArgumentTypeHelper.java b/src/main/java/com/koralix/oneforall/commands/ArgumentTypeHelper.java new file mode 100644 index 0000000..4898f78 --- /dev/null +++ b/src/main/java/com/koralix/oneforall/commands/ArgumentTypeHelper.java @@ -0,0 +1,88 @@ +package com.koralix.oneforall.commands; + +import com.koralix.oneforall.settings.ConfigValue; +import com.mojang.brigadier.arguments.*; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import net.minecraft.command.CommandSource; +import org.jetbrains.annotations.NotNull; + +import java.util.function.BiFunction; + +public class ArgumentTypeHelper { + @SuppressWarnings("unchecked") + public static , S extends CommandSource> RequiredArgumentBuilder createEnumArg( + @NotNull BiFunction, RequiredArgumentBuilder> argument, + String name, + T[] values + ) { + return (RequiredArgumentBuilder) argument.apply(name, StringArgumentType.word()).suggests((context, builder) -> { + for (T value : values) { + builder.suggest(value.name().toLowerCase()); + } + return builder.buildFuture(); + }); + } + + @SuppressWarnings("unchecked") + public static , S extends CommandSource> @NotNull RequiredArgumentBuilder createEnumArg( + @NotNull BiFunction, RequiredArgumentBuilder> argument, + String name, + @NotNull Class clazz + ) { + return createEnumArg(argument, name, (T[]) clazz.getEnumConstants()); + } + + public static , S extends CommandSource> T getEnumValue( + @NotNull CommandContext context, + @NotNull String name, + @NotNull Class clazz + ) { + return Enum.valueOf(clazz, StringArgumentType.getString(context, name).toUpperCase()); + } + + @SuppressWarnings("unchecked") + public static @NotNull RequiredArgumentBuilder createSettingArg( + @NotNull BiFunction, RequiredArgumentBuilder> ofaArgument, + @NotNull ConfigValue setting + ) { + if (setting.clazz().isEnum()) + return (RequiredArgumentBuilder) createEnumArg(ofaArgument, "value", setting.clazz()); + + return (RequiredArgumentBuilder) ofaArgument.apply("value", settingArgumentType(setting.clazz())); + } + + public static T getSettingValue( + @NotNull CommandContext context, + @NotNull String name, + @NotNull ConfigValue setting + ) { + if (setting.clazz().isEnum()) { + Class clazz = setting.clazz().asSubclass(Enum.class); + return (T) getEnumValue(context, name, clazz); + } + + return context.getArgument(name, setting.clazz()); + } + + @SuppressWarnings("unchecked") + private static @NotNull ArgumentType settingArgumentType(@NotNull Class clazz) { + if (clazz == Boolean.class) + return (ArgumentType) BoolArgumentType.bool(); + if (clazz == String.class) + return (ArgumentType) StringArgumentType.string(); + if (clazz == Byte.class) + return (ArgumentType) IntegerArgumentType.integer(Byte.MIN_VALUE, Byte.MAX_VALUE); + if (clazz == Short.class) + return (ArgumentType) IntegerArgumentType.integer(Short.MIN_VALUE, Short.MAX_VALUE); + if (clazz == Integer.class) + return (ArgumentType) IntegerArgumentType.integer(); + if (clazz == Long.class) + return (ArgumentType) LongArgumentType.longArg(); + if (clazz == Float.class) + return (ArgumentType) FloatArgumentType.floatArg(); + if (clazz == Double.class) + return (ArgumentType) DoubleArgumentType.doubleArg(); + throw new UnsupportedOperationException("Unsupported setting type: " + clazz); + } +} diff --git a/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java b/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java deleted file mode 100644 index 15c1a94..0000000 --- a/src/main/java/com/koralix/oneforall/commands/DynEnumArgumentType.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.koralix.oneforall.commands; - -import net.minecraft.command.argument.EnumArgumentType; -import net.minecraft.util.StringIdentifiable; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Supplier; - -public class DynEnumArgumentType { - @Contract("_ -> new") - public static & StringIdentifiable> @NotNull EnumArgumentType create(T[] values) { - Supplier supplier = () -> values; - return new EnumArgumentType<>(StringIdentifiable.createCodec(supplier), supplier); - } - - @Contract("_ -> new") - @SuppressWarnings("unchecked") - public static & StringIdentifiable> @NotNull EnumArgumentType create(@NotNull Class clazz) { - return create((T[]) clazz.getEnumConstants()); - } -} diff --git a/src/main/java/com/koralix/oneforall/commands/OfaCommand.java b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java index e91fb58..9d959ee 100644 --- a/src/main/java/com/koralix/oneforall/commands/OfaCommand.java +++ b/src/main/java/com/koralix/oneforall/commands/OfaCommand.java @@ -1,6 +1,5 @@ package com.koralix.oneforall.commands; -import com.koralix.oneforall.settings.ConfigValue; import com.koralix.oneforall.settings.SettingEntry; import com.koralix.oneforall.settings.SettingsManager; import com.koralix.oneforall.settings.SettingsRegistry; @@ -65,14 +64,14 @@ private static LiteralArgumentBuilder setting( def.then(ofaLiteral.apply(entry.id().toString()) .requires(source -> !(source instanceof ServerCommandSource scs) || entry.setting().permission(scs)) .executes(context -> setSetting(context, entry)) - .then(settingArgument(ofaArgument, entry.setting()) + .then(ArgumentTypeHelper.createSettingArg(ofaArgument, entry.setting()) .executes(context -> setDefaultSetting(context, entry)))); restore .requires(source -> !(source instanceof ServerCommandSource scs) || entry.setting().permission(scs)) .executes(context -> setDefaultSetting(context, entry)); return ofaLiteral.apply(entry.id().toString()) .executes(context -> getSetting(context, entry)) - .then(settingArgument(ofaArgument, entry.setting()) + .then(ArgumentTypeHelper.createSettingArg(ofaArgument, entry.setting()) .executes(context -> setSetting(context, entry))); } @@ -125,7 +124,7 @@ private static int setSetting( @NotNull SettingEntry entry ) { try { - T value = context.getArgument("value", entry.setting().clazz()); + T value = ArgumentTypeHelper.getSettingValue(context, "value", entry.setting()); Text text = entry.setting().value(value); if (text != null && context.getSource() instanceof ServerCommandSource scs) { scs.sendError(text); @@ -143,7 +142,7 @@ private static int setDefaultSetting( @NotNull SettingEntry entry ) { try { - T value = context.getArgument("value", entry.setting().clazz()); + T value = ArgumentTypeHelper.getSettingValue(context, "value", entry.setting()); Text text = entry.setting().defaultValue(value); if (text != null && context.getSource() instanceof ServerCommandSource scs) { scs.sendError(text); @@ -155,35 +154,4 @@ private static int setDefaultSetting( return 1; } - - @SuppressWarnings("unchecked") - private static @NotNull RequiredArgumentBuilder settingArgument( - @NotNull BiFunction, RequiredArgumentBuilder> ofaArgument, - @NotNull ConfigValue setting - ) { - return (RequiredArgumentBuilder) ofaArgument.apply("value", settingArgumentType(setting.clazz())); - } - - @SuppressWarnings("unchecked") - private static @NotNull ArgumentType settingArgumentType(@NotNull Class clazz) { - if (clazz.isEnum()) - return (ArgumentType) DynEnumArgumentType.create(clazz); - if (clazz == Boolean.class) - return (ArgumentType) BoolArgumentType.bool(); - if (clazz == String.class) - return (ArgumentType) StringArgumentType.string(); - if (clazz == Byte.class) - return (ArgumentType) IntegerArgumentType.integer(Byte.MIN_VALUE, Byte.MAX_VALUE); - if (clazz == Short.class) - return (ArgumentType) IntegerArgumentType.integer(Short.MIN_VALUE, Short.MAX_VALUE); - if (clazz == Integer.class) - return (ArgumentType) IntegerArgumentType.integer(); - if (clazz == Long.class) - return (ArgumentType) LongArgumentType.longArg(); - if (clazz == Float.class) - return (ArgumentType) FloatArgumentType.floatArg(); - if (clazz == Double.class) - return (ArgumentType) DoubleArgumentType.doubleArg(); - throw new UnsupportedOperationException("Unsupported setting type: " + clazz); - } }