diff options
4 files changed, 113 insertions, 6 deletions
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c3f3c43..37f5295 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -63,7 +63,7 @@ runtime_optional = [ "freecammod", "sodium", "qolify", - "citresewn", +# "citresewn", "ncr", ] diff --git a/src/main/java/moe/nea/firmament/mixins/MixinCommandNode.java b/src/main/java/moe/nea/firmament/mixins/MixinCommandNode.java new file mode 100644 index 0000000..aa8e584 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/MixinCommandNode.java @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.mixins; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mojang.brigadier.tree.CommandNode; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import java.util.Locale; +import java.util.Map; + +@Mixin(value = CommandNode.class, remap = false) +public class MixinCommandNode<S> { + @WrapOperation(method = "getRelevantNodes", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;"), remap = false) + public Object modify(Map map, Object text, Operation<Object> op) { + var original = op.call(map, text); + if (original == null) { + return map.get(((String) text).toLowerCase(Locale.ROOT)); + } + return original; + } + +} diff --git a/src/main/kotlin/moe/nea/firmament/commands/CaseInsensitiveLiteralCommandNode.kt b/src/main/kotlin/moe/nea/firmament/commands/CaseInsensitiveLiteralCommandNode.kt new file mode 100644 index 0000000..b819a5a --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/commands/CaseInsensitiveLiteralCommandNode.kt @@ -0,0 +1,79 @@ +/* + * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.commands + +import com.mojang.brigadier.Command +import com.mojang.brigadier.RedirectModifier +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContextBuilder +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.tree.CommandNode +import com.mojang.brigadier.tree.LiteralCommandNode +import java.util.function.Predicate + +class CaseInsensitiveLiteralCommandNode<S>( + literal: String, command: Command<S>?, requirement: Predicate<S>?, + redirect: CommandNode<S>?, modifier: RedirectModifier<S>?, forks: Boolean +) : LiteralCommandNode<S>( + literal.lowercase(), command, requirement, redirect, modifier, forks +) { + class Builder<S>(literal: String) : LiteralArgumentBuilder<S>(literal) { + override fun build(): LiteralCommandNode<S> { + val result = CaseInsensitiveLiteralCommandNode( + literal, + command, requirement, redirect, redirectModifier, isFork + ) + for (argument in arguments) { + result.addChild(argument) + } + return result + } + } + + override fun createBuilder(): LiteralArgumentBuilder<S> { + return Builder<S>(literal).also { + it.requires(requirement) + it.forward(redirect, redirectModifier, isFork) + if (command != null) + it.executes(command) + } + } + + override fun parse(reader: StringReader, contextBuilder: CommandContextBuilder<S>) { + val start = reader.cursor + val end = parse0(reader) + if (end > -1) { + contextBuilder.withNode(this, StringRange.between(start, end)) + return + } + + throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.literalIncorrect().createWithContext(reader, literal) + } + + override fun toString(): String { + return "<iliteral $literal>" + } + + private fun parse0(reader: StringReader): Int { + val start = reader.cursor + if (reader.canRead(literal.length)) { + val end = start + literal.length + if (reader.string.substring(start, end).equals(literal, true)) { + reader.cursor = end + if (!reader.canRead() || reader.peek() == ' ') { + return end + } else { + reader.cursor = start + } + } + } + return -1 + } + +} diff --git a/src/main/kotlin/moe/nea/firmament/commands/dsl.kt b/src/main/kotlin/moe/nea/firmament/commands/dsl.kt index d6eaf85..551f560 100644 --- a/src/main/kotlin/moe/nea/firmament/commands/dsl.kt +++ b/src/main/kotlin/moe/nea/firmament/commands/dsl.kt @@ -8,7 +8,6 @@ package moe.nea.firmament.commands import com.mojang.brigadier.arguments.ArgumentType import com.mojang.brigadier.builder.ArgumentBuilder -import com.mojang.brigadier.builder.LiteralArgumentBuilder import com.mojang.brigadier.builder.RequiredArgumentBuilder import com.mojang.brigadier.context.CommandContext import com.mojang.brigadier.suggestion.SuggestionProvider @@ -32,9 +31,9 @@ operator fun <T : Any, C : CommandContext<*>> C.get(arg: TypeSafeArg<T>): T { fun literal( name: String, - block: LiteralArgumentBuilder<DefaultSource>.() -> Unit -): LiteralArgumentBuilder<DefaultSource> = - LiteralArgumentBuilder.literal<DefaultSource>(name).also(block) + block: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>.() -> Unit +): CaseInsensitiveLiteralCommandNode.Builder<DefaultSource> = + CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>(name).also(block) private fun normalizeGeneric(argument: Type): Class<*> { @@ -101,7 +100,7 @@ fun <T : RequiredArgumentBuilder<DefaultSource, String>> T.suggestsList(provider fun <T : ArgumentBuilder<DefaultSource, T>> T.thenLiteral( name: String, - block: LiteralArgumentBuilder<DefaultSource>.() -> Unit + block: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>.() -> Unit ): T = then(literal(name, block)) |