diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/protocol/packets/s2c/play/CommandsS2CPTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/protocol/packets/s2c/play/CommandsS2CPTest.kt
new file mode 100644
index 000000000..6e581ece6
--- /dev/null
+++ b/src/integration-test/kotlin/de/bixilon/minosoft/protocol/packets/s2c/play/CommandsS2CPTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.protocol.packets.s2c.play
+
+import de.bixilon.kutil.cast.CastUtil.nullCast
+import de.bixilon.kutil.cast.CastUtil.unsafeCast
+import de.bixilon.minosoft.commands.nodes.CommandNode
+import de.bixilon.minosoft.commands.nodes.NamedNode
+import de.bixilon.minosoft.commands.nodes.RootNode
+import org.testng.Assert.assertNotNull
+import org.testng.annotations.Test
+
+@Test(groups = ["packet"])
+class CommandsS2CPTest {
+ private val children = CommandNode::class.java.getDeclaredField("children").apply { isAccessible = true }
+ private val RootNode.children: List get() = this@CommandsS2CPTest.children.get(this).unsafeCast()
+
+ fun vanilla_op_1_19_3() {
+ val packet = PacketReadingTestUtil.read("commands/vanilla_op_1_19_3", "1.19.3", constructor = ::CommandsS2CP)
+ assertNotNull(packet.rootNode)
+ val help = packet.rootNode!!.children.find { it.nullCast()?.name == "help" }
+ assertNotNull(help)
+ }
+
+ fun vanilla_op_1_15_2() {
+ val packet = PacketReadingTestUtil.read("commands/vanilla_op_1_15_2", "1.15.2", constructor = ::CommandsS2CP)
+ assertNotNull(packet.rootNode)
+ val help = packet.rootNode!!.children.find { it.nullCast()?.name == "help" }
+ assertNotNull(help)
+ }
+
+ fun vanilla_op_1_20_1() {
+ val packet = PacketReadingTestUtil.read("commands/vanilla_op_1_20_1", "1.20.1", constructor = ::CommandsS2CP)
+ assertNotNull(packet.rootNode)
+ val help = packet.rootNode!!.children.find { it.nullCast()?.name == "help" }
+ assertNotNull(help)
+ }
+}
+
diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/protocol/packets/s2c/play/PacketReadingTestUtil.kt b/src/integration-test/kotlin/de/bixilon/minosoft/protocol/packets/s2c/play/PacketReadingTestUtil.kt
new file mode 100644
index 000000000..964e0f15f
--- /dev/null
+++ b/src/integration-test/kotlin/de/bixilon/minosoft/protocol/packets/s2c/play/PacketReadingTestUtil.kt
@@ -0,0 +1,30 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.protocol.packets.s2c.play
+
+import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil
+import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
+import de.bixilon.minosoft.protocol.packets.s2c.S2CPacket
+import de.bixilon.minosoft.protocol.protocol.buffers.play.PlayInByteBuffer
+
+object PacketReadingTestUtil {
+
+ fun read(name: String, version: String, connection: PlayConnection = ConnectionTestUtil.createConnection(version = version), constructor: (PlayInByteBuffer) -> T): T {
+ val data = PacketReadingTestUtil::class.java.getResourceAsStream("/packets/$name.bin")!!.readAllBytes()
+
+ val buffer = PlayInByteBuffer(data, connection)
+
+ return constructor.invoke(buffer)
+ }
+}
diff --git a/src/integration-test/resources/packets/commands/vanilla_op_1_15_2.bin b/src/integration-test/resources/packets/commands/vanilla_op_1_15_2.bin
new file mode 100644
index 000000000..b1b135f3e
Binary files /dev/null and b/src/integration-test/resources/packets/commands/vanilla_op_1_15_2.bin differ
diff --git a/src/integration-test/resources/packets/commands/vanilla_op_1_19_3.bin b/src/integration-test/resources/packets/commands/vanilla_op_1_19_3.bin
new file mode 100644
index 000000000..ef8075706
Binary files /dev/null and b/src/integration-test/resources/packets/commands/vanilla_op_1_19_3.bin differ
diff --git a/src/integration-test/resources/packets/commands/vanilla_op_1_20_1.bin b/src/integration-test/resources/packets/commands/vanilla_op_1_20_1.bin
new file mode 100644
index 000000000..611a42716
Binary files /dev/null and b/src/integration-test/resources/packets/commands/vanilla_op_1_20_1.bin differ