Skip to content

Commit

Permalink
DynamicCommands: Allow redirecting to MC CommandNodes
Browse files Browse the repository at this point in the history
  • Loading branch information
mattco98 committed Dec 1, 2023
1 parent 3b7e45d commit f4abb20
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 21 deletions.
1 change: 1 addition & 0 deletions api/ctjs.api
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ public final class com/chattriggers/ctjs/api/commands/DynamicCommands : com/chat
public static final fun player ()Lcom/mojang/brigadier/arguments/ArgumentType;
public static final fun players ()Lcom/mojang/brigadier/arguments/ArgumentType;
public static final fun redirect (Lcom/chattriggers/ctjs/api/commands/RootCommand;)V
public static final fun redirect (Lcom/mojang/brigadier/tree/CommandNode;)V
public static final fun registerCommand (Ljava/lang/String;)Lcom/chattriggers/ctjs/api/commands/RootCommand;
public static final fun registerCommand (Ljava/lang/String;Lorg/mozilla/javascript/Function;)Lcom/chattriggers/ctjs/api/commands/RootCommand;
public static synthetic fun registerCommand$default (Ljava/lang/String;Lorg/mozilla/javascript/Function;ILjava/lang/Object;)Lcom/chattriggers/ctjs/api/commands/RootCommand;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.chattriggers.ctjs.internal.engine.JSLoader
import com.chattriggers.ctjs.internal.mixins.commands.EntitySelectorAccessor
import com.chattriggers.ctjs.MCEntity
import com.chattriggers.ctjs.MCNbtCompound
import com.chattriggers.ctjs.api.client.Client
import com.chattriggers.ctjs.internal.utils.asMixin
import com.mojang.brigadier.CommandDispatcher
import com.mojang.brigadier.ImmutableStringReader
Expand All @@ -32,7 +33,9 @@ import com.mojang.brigadier.context.CommandContext
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType
import com.mojang.brigadier.suggestion.Suggestions
import com.mojang.brigadier.suggestion.SuggestionsBuilder
import com.mojang.brigadier.tree.CommandNode
import net.minecraft.block.pattern.CachedBlockPosition
import net.minecraft.command.CommandSource
import net.minecraft.command.EntitySelector
import net.minecraft.command.argument.*
import net.minecraft.command.argument.AngleArgumentType.Angle
Expand Down Expand Up @@ -206,6 +209,13 @@ object DynamicCommands : CommandCollection() {
currentNode!!.hasRedirect = true
}

@JvmStatic
fun redirect(node: CommandNode<CommandSource>) {
requireNotNull(currentNode) { "Call to Commands.redirect() outside of Commands.buildCommand()" }
require(!currentNode!!.hasRedirect) { "Duplicate call to Commands.redirect()" }
currentNode!!.children.add(DynamicCommand.Node.RedirectToCommandNode(currentNode, node))
}

@JvmStatic
fun exec(method: Function) {
requireNotNull(currentNode) { "Call to Commands.argument() outside of Commands.buildCommand()" }
Expand Down
14 changes: 11 additions & 3 deletions src/main/kotlin/com/chattriggers/ctjs/internal/commands/Command.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,26 @@ package com.chattriggers.ctjs.internal.commands
import com.chattriggers.ctjs.internal.mixins.commands.CommandNodeAccessor
import com.chattriggers.ctjs.internal.utils.asMixin
import com.mojang.brigadier.CommandDispatcher
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
import com.mojang.brigadier.arguments.ArgumentType
import com.mojang.brigadier.builder.LiteralArgumentBuilder
import com.mojang.brigadier.builder.RequiredArgumentBuilder
import net.minecraft.command.CommandSource

interface Command {
val overrideExisting: Boolean
val name: String

fun registerImpl(dispatcher: CommandDispatcher<FabricClientCommandSource>)
fun registerImpl(dispatcher: CommandDispatcher<CommandSource>)

fun unregisterImpl(dispatcher: CommandDispatcher<FabricClientCommandSource>) {
fun unregisterImpl(dispatcher: CommandDispatcher<CommandSource>) {
dispatcher.root.asMixin<CommandNodeAccessor>().apply {
childNodes.remove(name)
literals.remove(name)
}
}
}

fun literal(name: String) = LiteralArgumentBuilder.literal<CommandSource>(name)

fun <T> argument(name: String, argument: ArgumentType<T>) =
RequiredArgumentBuilder.argument<CommandSource, T>(name, argument)
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,24 @@ import com.mojang.brigadier.CommandDispatcher
import com.mojang.brigadier.builder.ArgumentBuilder
import com.mojang.brigadier.context.CommandContext
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents
import net.minecraft.command.CommandSource

abstract class CommandCollection : Initializer {
private val allCommands = mutableSetOf<Command>()

private var clientDispatcher: CommandDispatcher<FabricClientCommandSource>? = null
private var networkDispatcher: CommandDispatcher<FabricClientCommandSource>? = null
private var clientDispatcher: CommandDispatcher<CommandSource>? = null
private var networkDispatcher: CommandDispatcher<CommandSource>? = null

@Suppress("UNCHECKED_CAST")
override fun init() {
ClientCommandRegistrationCallback.EVENT.register { dispatcher, _ ->
clientDispatcher = dispatcher
clientDispatcher = dispatcher as CommandDispatcher<CommandSource>
allCommands.forEach { it.registerImpl(dispatcher) }
}

CTEvents.NETWORK_COMMAND_DISPATCHER_REGISTER.register { dispatcher ->
networkDispatcher = dispatcher
networkDispatcher = dispatcher as CommandDispatcher<CommandSource>
allCommands.forEach { it.registerImpl(dispatcher) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import com.mojang.brigadier.CommandDispatcher
import com.mojang.brigadier.arguments.ArgumentType
import com.mojang.brigadier.builder.ArgumentBuilder
import com.mojang.brigadier.builder.LiteralArgumentBuilder
import com.mojang.brigadier.tree.CommandNode
import com.mojang.brigadier.tree.LiteralCommandNode
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
import net.minecraft.command.CommandSource
import org.mozilla.javascript.Function
import org.mozilla.javascript.NativeObject
import org.mozilla.javascript.ScriptableObject
Expand All @@ -22,12 +23,12 @@ object DynamicCommand {
var method: Function? = null
var hasRedirect = false
val children = mutableListOf<Node>()
var builder: ArgumentBuilder<FabricClientCommandSource, *>? = null
var builder: ArgumentBuilder<CommandSource, *>? = null

open class Literal(parent: Node?, val name: String) : Node(parent)

class Root(name: String) : Literal(null, name), RootCommand {
var commandNode: LiteralCommandNode<FabricClientCommandSource>? = null
var commandNode: LiteralCommandNode<CommandSource>? = null

override fun register() {
DynamicCommands.register(CommandImpl(this))
Expand All @@ -38,7 +39,9 @@ object DynamicCommand {

class Redirect(parent: Node?, val target: Root) : Node(parent)

fun initialize(dispatcher: CommandDispatcher<FabricClientCommandSource>) {
class RedirectToCommandNode(parent: Node?, val target: CommandNode<CommandSource>) : Node(parent)

fun initialize(dispatcher: CommandDispatcher<CommandSource>) {
if (this is Redirect) {
check(method == null)
check(children.isEmpty())
Expand All @@ -53,9 +56,22 @@ object DynamicCommand {
return
}

if (this is RedirectToCommandNode) {
check(method == null)
check(children.isEmpty())

parent!!.builder!!.redirect(target) {
for ((name, arg) in it.asMixin<CommandContextAccessor>().arguments)
it.source.asMixin<CTClientCommandSource>().setContextValue(name, arg.result)
it.source
}

return
}

builder = when (this) {
is Literal -> ClientCommandManager.literal(name)
is Argument -> ClientCommandManager.argument(name, type)
is Literal -> literal(name)
is Argument -> argument(name, type)
else -> throw IllegalStateException("unreachable")
}

Expand Down Expand Up @@ -88,9 +104,9 @@ object DynamicCommand {
override val overrideExisting = true
override val name = node.name

override fun registerImpl(dispatcher: CommandDispatcher<FabricClientCommandSource>) {
override fun registerImpl(dispatcher: CommandDispatcher<CommandSource>) {
node.initialize(dispatcher)
val builder = node.builder!! as LiteralArgumentBuilder<FabricClientCommandSource>
val builder = node.builder!! as LiteralArgumentBuilder<CommandSource>
node.commandNode = dispatcher.register(builder)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import com.chattriggers.ctjs.internal.mixins.commands.CommandNodeAccessor
import com.chattriggers.ctjs.internal.utils.asMixin
import com.mojang.brigadier.CommandDispatcher
import com.mojang.brigadier.arguments.StringArgumentType
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
import net.minecraft.command.CommandSource

internal class StaticCommand(
val trigger: CommandTrigger,
Expand All @@ -17,7 +15,7 @@ internal class StaticCommand(
private val staticSuggestions: List<String>,
private val dynamicSuggestions: ((List<String>) -> List<String>)?,
) : Command {
override fun registerImpl(dispatcher: CommandDispatcher<FabricClientCommandSource>) {
override fun registerImpl(dispatcher: CommandDispatcher<CommandSource>) {
val builder = literal(name)
.then(argument("args", StringArgumentType.greedyString())
.suggests { ctx, builder ->
Expand Down Expand Up @@ -58,7 +56,7 @@ internal class StaticCommand(
}
}

override fun unregisterImpl(dispatcher: CommandDispatcher<FabricClientCommandSource>) {
override fun unregisterImpl(dispatcher: CommandDispatcher<CommandSource>) {
super.unregisterImpl(dispatcher)
dispatcher.root.asMixin<CommandNodeAccessor>().apply {
for (alias in aliases) {
Expand Down

0 comments on commit f4abb20

Please sign in to comment.