diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/commands/MsgCommandIT.kt b/src/integration-test/kotlin/de/bixilon/minosoft/commands/MsgCommandIT.kt index 885134772..18a0367c6 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/commands/MsgCommandIT.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/commands/MsgCommandIT.kt @@ -51,7 +51,7 @@ class MsgCommandIT { fun validateStack() { var stack: CommandStack? = null - val node = createNode { stack = it.copy() } + val node = createNode { stack = it.fork() } node.execute("msg Bixilon hi there!") assertEquals(stack!!["msg"], "msg") @@ -70,7 +70,7 @@ class MsgCommandIT { fun redirectStack() { var stack: CommandStack? = null - val node = createNode { stack = it.copy() } + val node = createNode { stack = it.fork() } node.execute("redirect Bixilon hi there!") diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/commands/TPCommandIT.kt b/src/integration-test/kotlin/de/bixilon/minosoft/commands/TPCommandIT.kt index d1d2b0def..ecc21f81c 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/commands/TPCommandIT.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/commands/TPCommandIT.kt @@ -51,7 +51,7 @@ class TPCommandIT { fun relativeStack() { var stack: CommandStack? = null - val node = createNode { stack = it.copy() } + val node = createNode { stack = it.fork() } node.execute("tp @s ~ ~10 ~") diff --git a/src/main/java/de/bixilon/minosoft/commands/nodes/CommandNode.kt b/src/main/java/de/bixilon/minosoft/commands/nodes/CommandNode.kt index 053081cfa..833c1ad22 100644 --- a/src/main/java/de/bixilon/minosoft/commands/nodes/CommandNode.kt +++ b/src/main/java/de/bixilon/minosoft/commands/nodes/CommandNode.kt @@ -41,7 +41,7 @@ abstract class CommandNode( val stackSize = stack.size var childError: Throwable? = null - var errorStack = -1 + var errorStack: CommandStack? = null for (child in (redirect?.children ?: children)) { reader.pointer = pointer @@ -53,12 +53,13 @@ abstract class CommandNode( } return } catch (error: Throwable) { - if (stack.size > errorStack) { - errorStack = stack.size + if (errorStack == null || stack.size > errorStack.size) { + errorStack = stack.fork() childError = error } } } + errorStack?.let { stack.join(it) } throw childError ?: return } @@ -71,7 +72,7 @@ abstract class CommandNode( val stackSize = stack.size var childError: Throwable? = null - var errorStack = -1 + var errorStack: CommandStack? = null var parserSucceeds = 0 for (child in (redirect?.children ?: children)) { @@ -92,8 +93,8 @@ abstract class CommandNode( return childSuggestions } catch (error: Throwable) { - if (stack.size > errorStack) { - errorStack = stack.size + if (errorStack == null || stack.size > errorStack.size) { + errorStack = stack.fork() childError = error } } @@ -103,6 +104,8 @@ abstract class CommandNode( if (!reader.canPeek(pointer) && executable) { return emptyList() } + errorStack?.let { stack.join(it) } + throw childError ?: return emptyList() } diff --git a/src/main/java/de/bixilon/minosoft/commands/stack/CommandStack.kt b/src/main/java/de/bixilon/minosoft/commands/stack/CommandStack.kt index c771fa0d9..e0aa2975c 100644 --- a/src/main/java/de/bixilon/minosoft/commands/stack/CommandStack.kt +++ b/src/main/java/de/bixilon/minosoft/commands/stack/CommandStack.kt @@ -26,11 +26,14 @@ import java.time.Instant class CommandStack( connection: PlayConnection? = null, - val print: PrintTarget = SystemPrintTarget, + print: PrintTarget = SystemPrintTarget, ) { private val stack: MutableList = mutableListOf() val size: Int get() = stack.size + var print = print + private set + var executor: Entity? = null lateinit var connection: PlayConnection @@ -70,7 +73,7 @@ class CommandStack( } - fun copy(): CommandStack { + fun fork(): CommandStack { val stack = CommandStack(null, print) stack.stack += this.stack stack.executor = this.executor @@ -80,4 +83,14 @@ class CommandStack( return stack } + + fun join(stack: CommandStack) { + this.stack.clear() + this.stack += stack.stack + this.print = stack.print + this.executor = stack.executor + if (stack::connection.isInitialized) { + this.connection = stack.connection + } + } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/util/ConnectionUtil.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/util/ConnectionUtil.kt index 902891d85..dcc5e030a 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/util/ConnectionUtil.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/util/ConnectionUtil.kt @@ -34,6 +34,7 @@ import de.bixilon.minosoft.protocol.packets.c2s.play.chat.ChatMessageC2SP import de.bixilon.minosoft.protocol.packets.c2s.play.chat.CommandC2SP import de.bixilon.minosoft.protocol.packets.c2s.play.chat.SignedChatMessageC2SP import de.bixilon.minosoft.util.logging.Log +import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogMessageType import java.security.SecureRandom import java.time.Instant @@ -72,7 +73,11 @@ class ConnectionUtil( val keyManagement = connection.player.keyManagement keyManagement.acquire() try { - val key = keyManagement.key ?: return connection.sendPacket(SignedChatMessageC2SP(message.encodeNetwork(), time = Instant.EPOCH, salt = 0, signature = null, false, Acknowledgement.EMPTY)) + val key = keyManagement.key + if (key == null) { + connection.sendPacket(SignedChatMessageC2SP(message.encodeNetwork(), time = Instant.EPOCH, salt = 0, signature = null, false, Acknowledgement.EMPTY)) + return + } sendSignedMessage(key, trimmed) } finally { keyManagement.release() @@ -104,6 +109,7 @@ class ConnectionUtil( ChatUtil.validateChatMessage(connection, trimmed) if (stack.size == 0) { connection.sendPacket(CommandC2SP(trimmed, Instant.EPOCH, 0L, emptyMap(), false, Acknowledgement.EMPTY)) // TODO: remove + Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Command $trimmed failed to pars!" } throw IllegalArgumentException("Empty command stack! Did the command fail to parse?") } val time = Instant.now()