From 8fcdec089563455ae5080d17c66223082124b594 Mon Sep 17 00:00:00 2001 From: nea Date: Sun, 22 Jan 2023 06:51:34 +0100 Subject: wip --- .../mixins/AccessorCommandHandler.java | 33 ++++++++ .../util/brigadier/NEUBrigadierHook.kt | 92 ++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorCommandHandler.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/util/brigadier/NEUBrigadierHook.kt (limited to 'src/main/java') 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 . + */ + +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 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 . + */ + +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) : CommandBase() { + /** + * Runs before the command gets executed. Return false to prevent execution. + */ + var beforeCommand: Predicate>? = 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) = "${commandNode.name} ${args.joinToString(" ")}" + + override fun processCommand(sender: ICommandSender, args: Array) { + 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? = null + override fun addTabCompletionOptions( + sender: ICommandSender, + args: Array, + pos: BlockPos + ): List { + val originalText = getText(args) + var lc: CompletableFuture? = 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) + } + +} -- cgit