aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorCommandHandler.java33
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/brigadier/NEUBrigadierHook.kt92
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/events/RegisterBrigadierCommandEvent.kt45
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/brigadier/BrigadierRoot.kt (renamed from src/main/kotlin/io/github/moulberry/notenoughupdates/util/brigadier/Rome.kt)73
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/brigadier/dsl.kt21
-rw-r--r--src/main/resources/mixins.notenoughupdates.json1
6 files changed, 205 insertions, 60 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorCommandHandler.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorCommandHandler.java
new file mode 100644
index 00000000..73d31196
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorCommandHandler.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.command.CommandHandler;
+import net.minecraft.command.ICommand;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import java.util.Set;
+
+@Mixin(CommandHandler.class)
+public interface AccessorCommandHandler {
+ @Accessor("commandSet")
+ Set<ICommand> neuGetClientCommands();
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/brigadier/NEUBrigadierHook.kt b/src/main/java/io/github/moulberry/notenoughupdates/util/brigadier/NEUBrigadierHook.kt
new file mode 100644
index 00000000..b8ba7b48
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/brigadier/NEUBrigadierHook.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 Linnea Gräf
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util.brigadier
+
+import com.mojang.brigadier.ParseResults
+import com.mojang.brigadier.exceptions.CommandSyntaxException
+import com.mojang.brigadier.suggestion.Suggestions
+import com.mojang.brigadier.tree.CommandNode
+import net.minecraft.command.CommandBase
+import net.minecraft.command.ICommandSender
+import net.minecraft.util.BlockPos
+import net.minecraft.util.ChatComponentText
+import net.minecraft.util.EnumChatFormatting
+import java.util.concurrent.CompletableFuture
+import java.util.function.Predicate
+
+/**
+ * Hook for converting brigadier commands to normal legacy Minecraft commands (string array style).
+ */
+class NEUBrigadierHook(val brigadierRoot: BrigadierRoot, val commandNode: CommandNode<DefaultSource>) : CommandBase() {
+ /**
+ * Runs before the command gets executed. Return false to prevent execution.
+ */
+ var beforeCommand: Predicate<ParseResults<DefaultSource>>? = null
+
+ override fun getCommandName(): String {
+ return commandNode.name
+ }
+
+ override fun getCommandUsage(sender: ICommandSender): String {
+ return brigadierRoot.dispatcher.getAllUsage(commandNode, sender, true).joinToString("\n")
+ }
+
+ private fun getText(args: Array<out String>) = "${commandNode.name} ${args.joinToString(" ")}"
+
+ override fun processCommand(sender: ICommandSender, args: Array<out String>) {
+ val results = brigadierRoot.parseText.apply(sender to getText(args).trim())
+ if (beforeCommand?.test(results) == false)
+ return
+ try {
+ brigadierRoot.dispatcher.execute(results)
+ } catch (syntax: CommandSyntaxException) {
+ sender.addChatMessage(ChatComponentText("${EnumChatFormatting.RED}${syntax.message}"))
+ }
+ }
+
+ // We love async tab completion (may end up requiring pressing tab multiple times, but uhhhhh .get() bad)
+ private var lastCompletionText: String? = null
+ private var lastCompletion: CompletableFuture<Suggestions>? = null
+ override fun addTabCompletionOptions(
+ sender: ICommandSender,
+ args: Array<out String>,
+ pos: BlockPos
+ ): List<String> {
+ val originalText = getText(args)
+ var lc: CompletableFuture<Suggestions>? = null
+ if (lastCompletionText == originalText) {
+ lc = lastCompletion
+ }
+ if (lc == null) {
+ lastCompletion?.cancel(true)
+ val results = brigadierRoot.parseText.apply(sender to originalText)
+ lc = brigadierRoot.dispatcher.getCompletionSuggestions(results)
+ }
+ lastCompletion = lc
+ lastCompletionText = originalText
+ val suggestions = lastCompletion?.getNow(null) ?: return emptyList()
+ return suggestions.list.map { it.text }
+ }
+
+ override fun canCommandSenderUseCommand(sender: ICommandSender): Boolean {
+ return true // Permissions are checked by brigadier instead (or by the beforeCommand hook)
+ }
+
+}
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/events/RegisterBrigadierCommandEvent.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/events/RegisterBrigadierCommandEvent.kt
new file mode 100644
index 00000000..1f79d2cd
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/events/RegisterBrigadierCommandEvent.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 Linnea Gräf
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.events
+
+import com.mojang.brigadier.builder.LiteralArgumentBuilder
+import io.github.moulberry.notenoughupdates.util.brigadier.BrigadierRoot
+import io.github.moulberry.notenoughupdates.util.brigadier.NEUBrigadierHook
+import io.github.moulberry.notenoughupdates.util.brigadier.literal
+import net.minecraft.command.ICommandSender
+import java.util.function.Consumer
+
+data class RegisterBrigadierCommandEvent(val brigadierRoot: BrigadierRoot) : NEUEvent() {
+ val dispatcher = brigadierRoot.dispatcher
+ val hooks = mutableListOf<NEUBrigadierHook>()
+ fun command(name: String, block: Consumer<LiteralArgumentBuilder<ICommandSender>>): NEUBrigadierHook {
+ return command(name) {
+ block.accept(this)
+ }
+ }
+
+ fun command(name: String, block: LiteralArgumentBuilder<ICommandSender>.() -> Unit): NEUBrigadierHook {
+ val node = dispatcher.register(literal(name, block))
+ val hook = NEUBrigadierHook(brigadierRoot, node)
+ hooks.add(hook)
+ return hook
+ }
+
+}
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/brigadier/Rome.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/brigadier/BrigadierRoot.kt
index 7f8f3f74..8af23293 100644
--- a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/brigadier/Rome.kt
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/brigadier/BrigadierRoot.kt
@@ -30,6 +30,7 @@ import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe
import io.github.moulberry.notenoughupdates.commands.dev.DevTestCommand.DEV_TESTERS
import io.github.moulberry.notenoughupdates.core.config.GuiPositionEditor
import io.github.moulberry.notenoughupdates.core.util.MiscUtils
+import io.github.moulberry.notenoughupdates.events.RegisterBrigadierCommandEvent
import io.github.moulberry.notenoughupdates.miscfeatures.FishingHelper
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBiomes
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.LocationChangeEvent
@@ -55,11 +56,13 @@ import net.minecraft.util.EnumParticleTypes
import net.minecraftforge.client.ClientCommandHandler
import net.minecraftforge.common.MinecraftForge
import java.util.concurrent.CompletableFuture
+import kotlin.math.floor
@NEUAutoSubscribe
-object Rome {
- val dispatcher = CommandDispatcher<DefaultSource>()
- private val parseText =
+object BrigadierRoot {
+ var dispatcher = CommandDispatcher<DefaultSource>()
+ private set
+ val parseText =
LRUCache.memoize<Pair<ICommandSender, String>, ParseResults<DefaultSource>>({ (sender, text) ->
dispatcher.parse(text, sender)
}, 1)
@@ -162,8 +165,8 @@ object Rome {
}
}
thenLiteralExecute("center") {
- val x = Math.floor(Minecraft.getMinecraft().thePlayer.posX) + 0.5f
- val z = Math.floor(Minecraft.getMinecraft().thePlayer.posZ) + 0.5f
+ val x = floor(Minecraft.getMinecraft().thePlayer.posX) + 0.5f
+ val z = floor(Minecraft.getMinecraft().thePlayer.posZ) + 0.5f
Minecraft.getMinecraft().thePlayer.setPosition(x, Minecraft.getMinecraft().thePlayer.posY, z)
reply("Literal hacks")
}
@@ -186,56 +189,16 @@ object Rome {
fun updateHooks() = registerHooks(ClientCommandHandler.instance)
fun registerHooks(handler: ClientCommandHandler) {
- dispatcher.root.children.forEach { commandNode ->
- if (commandNode.name in handler.commands) return@forEach
- handler.registerCommand(object : CommandBase() {
- override fun getCommandName(): String {
- return commandNode.name
- }
-
- override fun getCommandUsage(sender: ICommandSender): String {
- return dispatcher.getAllUsage(commandNode, sender, true).joinToString("\n")
- }
-
- fun getText(args: Array<out String>) = "${commandNode.name} ${args.joinToString(" ")}"
-
- override fun processCommand(sender: ICommandSender, args: Array<out String>) {
- val results = parseText.apply(sender to getText(args).trim())
- try {
- dispatcher.execute(results)
- } catch (syntax: CommandSyntaxException) {
- sender.addChatMessage(ChatComponentText("${RED}${syntax.message}"))
- }
- }
-
- var lastCompletionText: String? = null
- var lastCompletion: CompletableFuture<Suggestions>? = null
-
- override fun addTabCompletionOptions(
- sender: ICommandSender,
- args: Array<out String>,
- pos: BlockPos
- ): List<String> {
- val originalText = getText(args)
- var lc: CompletableFuture<Suggestions>? = null
- if (lastCompletionText == originalText) {
- lc = lastCompletion
- }
- if (lc == null) {
- lastCompletion?.cancel(true)
- val results = parseText.apply(sender to originalText)
- lc = dispatcher.getCompletionSuggestions(results)
- }
- lastCompletion = lc
- lastCompletionText = originalText
- val suggestions = lastCompletion?.getNow(null) ?: return emptyList()
- return suggestions.list.map { it.text }
- }
-
- override fun canCommandSenderUseCommand(sender: ICommandSender): Boolean {
- return true
- }
- })
+ val iterator = handler.commands.entries.iterator()
+ while (iterator.hasNext()) {
+ if (iterator.next().value is NEUBrigadierHook)
+ iterator.remove()
+ }
+ dispatcher = CommandDispatcher()
+ val event = RegisterBrigadierCommandEvent(this)
+ event.post()
+ event.hooks.forEach {
+ handler.registerCommand(it)
}
}
}
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/brigadier/dsl.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/brigadier/dsl.kt
index b054f6d9..841322b5 100644
--- a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/brigadier/dsl.kt
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/brigadier/dsl.kt
@@ -35,11 +35,7 @@ import java.lang.reflect.TypeVariable
typealias DefaultSource = ICommandSender
-fun literal(
- name: String,
- block: LiteralArgumentBuilder<DefaultSource>.() -> Unit
-): LiteralArgumentBuilder<DefaultSource> =
- LiteralArgumentBuilder.literal<DefaultSource>(name).also(block)
+
private fun normalizeGeneric(argument: Type): Class<*> {
return if (argument is Class<*>) {
@@ -105,6 +101,21 @@ fun <T : ArgumentBuilder<DefaultSource, T>, AT : Any> T.thenArgument(
block: RequiredArgumentBuilder<DefaultSource, AT>.(TypeSafeArg<AT>) -> Unit
): T = then(argument(name, argument, block))
+fun <T : ArgumentBuilder<DefaultSource, T>, AT : Any> T.thenArgumentExecute(
+ name: String,
+ argument: ArgumentType<AT>,
+ block: CommandContext<DefaultSource>.(TypeSafeArg<AT>) -> Unit
+): T = thenArgument(name, argument) {
+ thenExecute {
+ block(it)
+ }
+}
+
+fun literal(
+ name: String,
+ block: LiteralArgumentBuilder<DefaultSource>.() -> Unit
+): LiteralArgumentBuilder<DefaultSource> =
+ LiteralArgumentBuilder.literal<DefaultSource>(name).also(block)
fun <T : ArgumentBuilder<DefaultSource, T>> T.thenLiteral(
name: String,
diff --git a/src/main/resources/mixins.notenoughupdates.json b/src/main/resources/mixins.notenoughupdates.json
index 8877aed8..8a8b10bc 100644
--- a/src/main/resources/mixins.notenoughupdates.json
+++ b/src/main/resources/mixins.notenoughupdates.json
@@ -5,6 +5,7 @@
"plugin": "io.github.moulberry.notenoughupdates.envcheck.NEUMixinConfigPlugin",
"compatibilityLevel": "JAVA_8",
"mixins": [
+ "AccessorCommandHandler",
"AccessorEntityAgeable",
"AccessorEntityArmorStand",
"AccessorGuiPlayerTabOverlay",