diff --git a/cache/cache-api/src/main/kotlin/net/rsprox/cache/api/rs3/Rs3PacketDefinitions.kt b/cache/cache-api/src/main/kotlin/net/rsprox/cache/api/rs3/Rs3PacketDefinitions.kt index d5a0a7ee..ff811b1c 100644 --- a/cache/cache-api/src/main/kotlin/net/rsprox/cache/api/rs3/Rs3PacketDefinitions.kt +++ b/cache/cache-api/src/main/kotlin/net/rsprox/cache/api/rs3/Rs3PacketDefinitions.kt @@ -8,6 +8,8 @@ public interface Rs3PacketDefinitions : Rs3AppearanceDefinitions { public fun getQuickChatPhrase(id: Int): Rs3QuickChatPhrase + public fun getGameLogEvent(id: Int): Rs3GameLogEventDefinition = error("RS3 game-log definitions are unavailable") + public fun getVariable( domain: Rs3VariableDomain, id: Int, @@ -63,6 +65,10 @@ public data class Rs3QuickChatPhrase( public val commands: List, ) +public data class Rs3GameLogEventDefinition( + public val parameters: List, +) + public data class Rs3QuickChatCommand( public val id: Int, public val transmitBytes: Int, diff --git a/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3Js5Connection.kt b/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3Js5Connection.kt index 19ffb554..05643570 100644 --- a/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3Js5Connection.kt +++ b/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3Js5Connection.kt @@ -123,7 +123,11 @@ internal class Rs3Js5Connection( val batch = ByteBuffer.allocate(MAX_IN_FLIGHT * 10) while (queued.hasNext() && pending.size < MAX_IN_FLIGHT) { val request = queued.next() - batch.put(1).put(request.archive.toByte()).putInt(request.group).putInt(0) + batch + .put(1) + .put(request.archive.toByte()) + .putInt(request.group) + .putInt(0) pending[request] = Response() } if (batch.position() != 0) { diff --git a/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3LiveCacheResolver.kt b/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3LiveCacheResolver.kt index a878e509..c4cfcd2f 100644 --- a/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3LiveCacheResolver.kt +++ b/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3LiveCacheResolver.kt @@ -4,6 +4,7 @@ import com.github.michaelbull.logging.InlineLogger import io.netty.buffer.Unpooled import net.rsprox.cache.CACHES_DIRECTORY import net.rsprox.cache.api.rs3.Rs3AppearanceItem +import net.rsprox.cache.api.rs3.Rs3GameLogEventDefinition import net.rsprox.cache.api.rs3.Rs3NpcDefinition import net.rsprox.cache.api.rs3.Rs3PacketDefinitions import net.rsprox.cache.api.rs3.Rs3QuickChatPhrase @@ -33,9 +34,7 @@ public class Rs3LiveCacheResolver( public var masterIndexSnapshot: ByteArray = ByteArray(0) private set - public fun loadPacketDefinitions( - onProgress: (String, Int, Int) -> Unit = { _, _, _ -> }, - ): Rs3PacketDefinitions { + public fun loadPacketDefinitions(onProgress: (String, Int, Int) -> Unit = { _, _, _ -> }): Rs3PacketDefinitions { require(info.revision == 950) { "RS3 definition decoding is currently verified for revision 950 only" } Rs3Js5Connection(info).use { connection -> onProgress("Loading cache indexes", 0, 0) @@ -43,7 +42,11 @@ public class Rs3LiveCacheResolver( var groups = 0 var downloads = 0 val prefetch: (Int, List) -> Unit = { archive, entries -> - val missing = entries.filter { readCachedGroup(directory, archive, it.id, it.version, it.checksum) == null } + val missing = + entries.filter { + readCachedGroup(directory, archive, it.id, it.version, it.checksum) == + null + } val byId = missing.associateBy { it.id } connection.getAll(missing.map { Rs3Js5Connection.Request(archive, it.id) }) { request, bytes -> val group = byId.getValue(request.group) @@ -211,6 +214,7 @@ public class Rs3LiveCacheResolver( .mapValues { (_, bytes) -> Rs3PacketDefinitionDecoder.phrase(bytes) } onProgress("Loading variable definitions", 0, 0) val configIndex = index(2) + val gameLogEvents = configIndex[70]?.let { files(2, it) }.orEmpty() val varbits = files(2, checkNotNull(configIndex[69]) { "Missing varbit definitions" }) .mapValues { (_, bytes) -> Rs3PacketDefinitionDecoder.varbit(bytes) } @@ -239,7 +243,7 @@ public class Rs3LiveCacheResolver( "${npcs.size} NPCs, ${phrases.size} phrases, " + "${(System.nanoTime() - started) / 1_000_000} ms" } - return Snapshot(slots, items, phrases, variables, npcs, varbits) + return Snapshot(slots, items, phrases, variables, npcs, varbits, gameLogEvents) } private class Snapshot( @@ -249,8 +253,17 @@ public class Rs3LiveCacheResolver( private val variables: Map>, private val npcs: Map, private val varbits: Map, + private val gameLogEvents: Map, ) : Rs3PacketDefinitions { private val decodedNpcs = ConcurrentHashMap() + private val decodedGameLogEvents = ConcurrentHashMap() + + override fun getGameLogEvent(id: Int): Rs3GameLogEventDefinition = + decodedGameLogEvents.computeIfAbsent(id) { + Rs3PacketDefinitionDecoder.gameLogEvent( + checkNotNull(gameLogEvents[id]) { "Missing RS3 game-log event definition $id" }, + ) + } override fun getVarbit(id: Int): Rs3VarbitDefinition = checkNotNull(varbits[id]) { "Missing RS3 varbit definition $id" } diff --git a/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3PacketDefinitionDecoder.kt b/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3PacketDefinitionDecoder.kt index d1b17a31..f0560484 100644 --- a/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3PacketDefinitionDecoder.kt +++ b/cache/src/main/kotlin/net/rsprox/cache/rs3/Rs3PacketDefinitionDecoder.kt @@ -1,6 +1,7 @@ package net.rsprox.cache.rs3 import net.rsprox.cache.api.rs3.Rs3BaseVarType +import net.rsprox.cache.api.rs3.Rs3GameLogEventDefinition import net.rsprox.cache.api.rs3.Rs3QuickChatCommand import net.rsprox.cache.api.rs3.Rs3QuickChatPhrase import net.rsprox.cache.api.rs3.Rs3VarbitDefinition @@ -9,6 +10,27 @@ import java.nio.ByteBuffer /** Revision-950 definition grammars; unsupported opcodes/types fail rather than guess a wire width. */ internal object Rs3PacketDefinitionDecoder { + // Note(revision): 950 beta, config 2:70, native 0x9ddaa0: repeated opcode 103 + gSmart1or2 type ID. + fun gameLogEvent(bytes: ByteArray): Rs3GameLogEventDefinition { + val input = ByteBuffer.wrap(bytes) + val parameters = mutableListOf() + while (true) { + when (val opcode = input.byte()) { + 0 -> { + require(!input.hasRemaining()) { "Trailing game-log definition bytes" } + return Rs3GameLogEventDefinition(parameters) + } + 103 -> { + val id = if (input.get(input.position()) < 0) input.word() - 32768 else input.byte() + val type = baseType(id) + require(type != Rs3BaseVarType.COORDINATE) { "Unsupported game-log parameter type $id" } + parameters += Rs3VariableDefinition(id, type) + } + else -> error("Unsupported game-log definition opcode $opcode") + } + } + } + fun varbit(bytes: ByteArray): Rs3VarbitDefinition { val input = ByteBuffer.wrap(bytes) var domain = -1 @@ -32,6 +54,7 @@ internal object Rs3PacketDefinitionDecoder { end = input.byte() } 16 -> Unit + 17 -> Unit // luaexcluded: no payload or effect on packet decoding. else -> error("Unknown RS3 varbit opcode $opcode") } } @@ -51,6 +74,7 @@ internal object Rs3PacketDefinitionDecoder { 4, 5 -> input.byte() 110 -> input.short 7, 8 -> Unit + 9 -> Unit // luaexcluded: no payload or effect on packet decoding. else -> error("Unsupported variable definition opcode $opcode") } } diff --git a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/components/LaunchBar.kt b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/components/LaunchBar.kt index 1aed93c3..735906fe 100644 --- a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/components/LaunchBar.kt +++ b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/components/LaunchBar.kt @@ -23,6 +23,7 @@ import java.net.URL import javax.swing.BoxLayout import javax.swing.DefaultComboBoxModel import javax.swing.DefaultListCellRenderer +import javax.swing.JCheckBox import javax.swing.JLabel import javax.swing.JList import javax.swing.JMenuItem @@ -63,6 +64,13 @@ public class LaunchBar( private val jagexAuthenticator = JagexAuthenticator() private val sessionTypesModel = DefaultComboBoxModel(sessionTypes) private val charactersModel = DefaultComboBoxModel() + private val rs3BetaToggle = + JCheckBox("Beta").apply { + isOpaque = false + isSelected = App.service.getSelectedRs3Beta() + toolTipText = "Use the RuneScape 3 beta client and servers" + addActionListener { App.service.setSelectedRs3Beta(isSelected) } + } public lateinit var clientTypeDropdown: FlatComboBox private set @@ -165,6 +173,7 @@ public class LaunchBar( fun updateProxyTargetRowState() { val isRs3 = (clientTypeDropdown.selectedItem as? SessionType)?.isRs3 == true + rs3BetaToggle.isVisible = isRs3 val disabledReason = if (isRs3) "Proxy target selection is currently only supported for Old School RuneScape." else null proxyTargetLabel.isEnabled = !isRs3 @@ -174,6 +183,8 @@ public class LaunchBar( proxyTargetLabel.toolTipText = disabledReason proxyTargetDropdown.toolTipText = disabledReason importTargetsButton.toolTipText = disabledReason ?: "Import Proxy Targets" + revalidate() + repaint() } clientTypeDropdown.addActionListener { @@ -192,6 +203,7 @@ public class LaunchBar( add(createFieldLabel("Client Type"), "wrap") add(characterDropdown, "growx, h $CONTROL_HEIGHT!") add(clientTypeDropdown, "growx, h $CONTROL_HEIGHT!, wrap") + add(rs3BetaToggle, "spanx 2, hidemode 3, wrap") add(proxyTargetLabel, "spanx 2, growx, gaptop 4, wrap") add(proxyTargetDropdown, "growx, h $CONTROL_HEIGHT!, spanx 2, split 2") add(importTargetsButton, "w $CONTROL_HEIGHT!, h $CONTROL_HEIGHT!, wrap") @@ -231,7 +243,7 @@ public class LaunchBar( DEFAULT_CHARACTER -> null else -> character as JagexCharacter } - sessionsPanel.createSession(sessionType, character) + sessionsPanel.createSession(sessionType, character, rs3Beta = sessionType.isRs3 && rs3BetaToggle.isSelected) } private fun importProxyTargets() { diff --git a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/Rs3LaunchProgressPanel.kt b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/Rs3LaunchProgressPanel.kt index b666dce5..9a698c2d 100644 --- a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/Rs3LaunchProgressPanel.kt +++ b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/Rs3LaunchProgressPanel.kt @@ -35,7 +35,10 @@ internal class Rs3LaunchProgressPanel : JPanel(BorderLayout(0, 6)) { } } - fun finish(success: Boolean) { + fun finish( + success: Boolean, + failure: String? = null, + ) { SwingUtilities.invokeLater { if (finished) return@invokeLater finished = true @@ -46,6 +49,7 @@ internal class Rs3LaunchProgressPanel : JPanel(BorderLayout(0, 6)) { } else { bar.isVisible = false status.text = "Launch failed during: ${progress.stage}. See the application log for details." + status.toolTipText = failure } revalidate() repaint() diff --git a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionPanel.kt b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionPanel.kt index ae7fbc6b..af5c4edc 100644 --- a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionPanel.kt +++ b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionPanel.kt @@ -45,6 +45,7 @@ public class SessionPanel( public val type: SessionType, private val sessionsPanel: SessionsPanel, character: JagexCharacter?, + private val rs3Beta: Boolean = false, ) : JPanel() { private val treeTable = JXTreeTable() private val tableModel = DefaultTreeTableModel() @@ -278,12 +279,19 @@ public class SessionPanel( rs3SessionMonitor, character, upstreamJavConfigUrl = - if (type == SessionType.RS3_VULKAN) { + if (rs3Beta) { + if (type == SessionType.RS3_VULKAN) { + JagexNativeClientDownloader.BETA_VULKAN_RS3_JAV_CONFIG_URL + } else { + JagexNativeClientDownloader.BETA_RS3_JAV_CONFIG_URL + } + } else if (type == SessionType.RS3_VULKAN) { JagexNativeClientDownloader.VULKAN_RS3_JAV_CONFIG_URL } else { JagexNativeClientDownloader.DEFAULT_RS3_JAV_CONFIG_URL }, onProgress = { launchProgress?.update(it) }, + beta = rs3Beta, ) portNumber = handle.port } @@ -292,7 +300,7 @@ public class SessionPanel( logger.error(e) { "Unable to launch $type client" } - launchProgress?.finish(success = false) + launchProgress?.finish(success = false, failure = e.message) return@submit } } diff --git a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionsPanel.kt b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionsPanel.kt index 51984965..2d9ab1e0 100644 --- a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionsPanel.kt +++ b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionsPanel.kt @@ -79,10 +79,11 @@ public class SessionsPanel( public fun createSession( type: SessionType, character: JagexCharacter?, + rs3Beta: Boolean = false, ) { if (type.isRs3 && !rs3LaunchWarning.confirm(this)) return - val session = SessionPanel(type, this, character) + val session = SessionPanel(type, this, character, rs3Beta = type.isRs3 && rs3Beta) addTab("Session ${++counter}", type.icon, session, "") selectedComponent = session setTabCloseCallback(tabCount - 1) { tabbedPane, tabIndex -> diff --git a/patch/patch-native/src/main/kotlin/net/rsprox/patch/native/NativePatchCriteria.kt b/patch/patch-native/src/main/kotlin/net/rsprox/patch/native/NativePatchCriteria.kt index baa7cb9b..eed0f68a 100644 --- a/patch/patch-native/src/main/kotlin/net/rsprox/patch/native/NativePatchCriteria.kt +++ b/patch/patch-native/src/main/kotlin/net/rsprox/patch/native/NativePatchCriteria.kt @@ -45,27 +45,30 @@ public data class NativePatchCriteria( return this } - /** Revision-950 Windows live lobby/world endpoint construction; never patch arbitrary HTTPS constants. */ + /** Revision-950 Windows lobby/world endpoint construction; never patch arbitrary HTTPS constants. */ public fun rs3LoginPorts( primary: Int, alternate: Int, + beta: Boolean = false, ): Builder { require(type == NativeClientType.RS3_WIN) require(primary in 1024..65535 && alternate in 1024..65535 && primary != alternate) require(primary != DEFAULT_PORT && alternate != DEFAULT_PORT) val first = intToHexStringLE(primary) val second = intToHexStringLE(alternate) - // Note: verified for revision 950 Windows OpenGL (binaryType=2) and Vulkan (binaryType=10). + val modeOffset = if (beta) "909A0100" else "709A0100" + // Note: live 950 OpenGL/Vulkan use 0x19A70; the verified beta-1 builds use 0x19A90. + // Beta callers must identify the supported executable before choosing these instruction windows. // Each guarded instruction window must occur exactly once. Only the two mov immediates change. // Later lobby selection, world selection, and the second world selection entry point respectively. val sites = listOf( - "483986709A0100750E41BE4AAA000041BCBB010000EB1AB8C0630000" to - "483986709A0100750E41BE${first}41BC${second}EB1AB8C0630000", - "493980709A0100750CBF4AAA0000BEBB010000EB18B8C0630000" to - "493980709A0100750CBF${first}BE${second}EB18B8C0630000", - "483982709A0100750E41BE4AAA000041BFBB010000EB1BB8C0630000" to - "483982709A0100750E41BE${first}41BF${second}EB1BB8C0630000", + "483986${modeOffset}750E41BE4AAA000041BCBB010000EB1AB8C0630000" to + "483986${modeOffset}750E41BE${first}41BC${second}EB1AB8C0630000", + "493980${modeOffset}750CBF4AAA0000BEBB010000EB18B8C0630000" to + "493980${modeOffset}750CBF${first}BE${second}EB18B8C0630000", + "483982${modeOffset}750E41BE4AAA000041BFBB010000EB1BB8C0630000" to + "483982${modeOffset}750E41BE${first}41BF${second}EB1BB8C0630000", ) for ((old, new) in sites) { wildcardByteSequence( diff --git a/protocol/rs3-950-beta/build.gradle.kts b/protocol/rs3-950-beta/build.gradle.kts new file mode 100644 index 00000000..f47018b2 --- /dev/null +++ b/protocol/rs3-950-beta/build.gradle.kts @@ -0,0 +1,14 @@ +dependencies { + implementation(platform(rootProject.libs.netty.bom)) + implementation(rootProject.libs.netty.buffer) + implementation(rootProject.libs.netty.transport) + implementation(rootProject.libs.netty.handler) + implementation(rootProject.libs.rsprot.buffer) + implementation(rootProject.libs.rsprot.compression) + implementation(rootProject.libs.rsprot.protocol) + implementation(rootProject.libs.rsprot.crypto) + implementation(platform(rootProject.libs.log4j.bom)) + implementation(rootProject.libs.bundles.log4j) + implementation(projects.protocol) + implementation(projects.cache.cacheApi) +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/ClientPacketDecoderServiceRs3V950Beta.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/ClientPacketDecoderServiceRs3V950Beta.kt new file mode 100644 index 00000000..87abee90 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/ClientPacketDecoderServiceRs3V950Beta.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec +import net.rsprot.protocol.message.IncomingMessage +import net.rsprox.protocol.ClientPacketDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.prot.ClientMessageDecoderRepository +import net.rsprox.protocol.session.Session + +public class ClientPacketDecoderServiceRs3V950Beta( + huffmanCodec: HuffmanCodec, +) : ClientPacketDecoder { + @OptIn(ExperimentalStdlibApi::class) + private val repository = ClientMessageDecoderRepository.build(huffmanCodec) + + override fun decode( + opcode: Int, + payload: JagByteBuf, + session: Session, + ): IncomingMessage { + val decoder = repository.getDecoder(opcode) + val message = decoder.decode(payload, session) + require(payload.readableBytes() == 0) { + "${decoder.prot} (opcode $opcode) left ${payload.readableBytes()} payload bytes unread" + } + return message + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/GameClientProtProviderRs3V950Beta.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/GameClientProtProviderRs3V950Beta.kt new file mode 100644 index 00000000..c9e40fdd --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/GameClientProtProviderRs3V950Beta.kt @@ -0,0 +1,16 @@ +package net.rsprox.protocol.rs3v950beta + +import net.rsprox.protocol.ProtProvider +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.prot.GameClientProt +import kotlin.enums.EnumEntries + +public data object GameClientProtProviderRs3V950Beta : ProtProvider { + override fun get(opcode: Int): GameClientProt { + return GameClientProt.entries.firstOrNull { it.opcode == opcode } + ?: throw IllegalArgumentException("Unknown game client prot: $opcode") + } + + override fun allProts(): EnumEntries { + return GameClientProt.entries + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/GameServerProtProviderRs3V950Beta.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/GameServerProtProviderRs3V950Beta.kt new file mode 100644 index 00000000..a27ea9c4 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/GameServerProtProviderRs3V950Beta.kt @@ -0,0 +1,16 @@ +package net.rsprox.protocol.rs3v950beta + +import net.rsprox.protocol.ProtProvider +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import kotlin.enums.EnumEntries + +public data object GameServerProtProviderRs3V950Beta : ProtProvider { + override fun get(opcode: Int): GameServerProt { + return GameServerProt.entries.firstOrNull { it.opcode == opcode } + ?: throw IllegalArgumentException("Unknown game server prot: $opcode") + } + + override fun allProts(): EnumEntries { + return GameServerProt.entries + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/ServerPacketDecoderServiceRs3V950Beta.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/ServerPacketDecoderServiceRs3V950Beta.kt new file mode 100644 index 00000000..d26be827 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/ServerPacketDecoderServiceRs3V950Beta.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec +import net.rsprot.crypto.cipher.StreamCipher +import net.rsprot.protocol.message.IncomingMessage +import net.rsprox.protocol.ServerPacketDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.ServerMessageDecoderRepository +import net.rsprox.protocol.session.Session + +public class ServerPacketDecoderServiceRs3V950Beta( + huffmanCodec: HuffmanCodec? = null, + cipher: () -> StreamCipher? = { null }, +) : ServerPacketDecoder { + @OptIn(ExperimentalStdlibApi::class) + private val repository = ServerMessageDecoderRepository.build(huffmanCodec, cipher) + + override fun decode( + opcode: Int, + payload: JagByteBuf, + session: Session, + ): IncomingMessage { + val decoder = repository.getDecoder(opcode) + val message = decoder.decode(payload, session) + require(payload.readableBytes() == 0) { + "${decoder.prot} (opcode $opcode) left ${payload.readableBytes()} payload bytes unread" + } + return message + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/buffer/NativeHuffmanReader.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/buffer/NativeHuffmanReader.kt new file mode 100644 index 00000000..f9355be2 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/buffer/NativeHuffmanReader.kt @@ -0,0 +1,13 @@ +package net.rsprox.protocol.rs3v950beta.buffer + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec + +/** Chat bodies finish the frame. A bounded view prevents bit reads into spare buffer capacity. */ +internal fun JagByteBuf.readNativeHuffman(codec: HuffmanCodec?): String { + val input = buffer.slice(buffer.readerIndex(), buffer.readableBytes()) + val result = checkNotNull(codec) { "RS3 Huffman codec is not initialized" }.decode(input) + buffer.readerIndex(buffer.readerIndex() + input.readerIndex()) + // U+FFFD cannot originate in CP1252: the library uses it for undefined bytes/native dropped NULs. + return result.filter { it != '\uFFFD' } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/buffer/NativePayloadReaders.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/buffer/NativePayloadReaders.kt new file mode 100644 index 00000000..c798153f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/buffer/NativePayloadReaders.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.buffer + +import net.rsprot.buffer.JagByteBuf + +/** Native CP1252 conversion drops undefined extension bytes, unlike replacement-character decoders. */ +internal fun JagByteBuf.readNativeString(): String = + buildString { + while (true) { + val byte = g1() + if (byte == 0) break + val character = nativeCharacter(byte) + if (character != '\u0000') append(character) + } + } + +/** A version-zero CP1252 string, not a second length prefix. */ +internal fun JagByteBuf.readNativeString2(): String { + require(g1() == 0) { "Expected a zero native string version marker" } + return readNativeString() +} + +internal fun nativeCharacter(byte: Int): Char = if (byte in 128..159) CP1252_EXTENSION[byte - 128] else byte.toChar() + +private const val CP1252_EXTENSION = + "\u20ac\u0000\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\u0000\u017d\u0000" + + "\u0000\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\u0000\u017e\u0178" diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/cache/CachePayloadReaders.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/cache/CachePayloadReaders.kt new file mode 100644 index 00000000..a7e5ef10 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/cache/CachePayloadReaders.kt @@ -0,0 +1,60 @@ +package net.rsprox.protocol.rs3v950beta.cache + +import net.rsprot.buffer.JagByteBuf +import net.rsprox.cache.api.rs3.Rs3BaseVarType +import net.rsprox.cache.api.rs3.Rs3VariableDomain +import net.rsprox.protocol.rs3.cache.rs3PacketDefinitions +import net.rsprox.protocol.rs3.common.QuickChat +import net.rsprox.protocol.rs3.common.TypedVariable +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString2 +import net.rsprox.protocol.session.Session + +internal fun JagByteBuf.readQuickChat( + session: Session, + phraseId: Int, + fromClient: Boolean = false, +): QuickChat { + val phrase = + checkNotNull(session.rs3PacketDefinitions) { "RS3 packet cache is not initialized" } + .getQuickChatPhrase(phraseId) + return QuickChat( + phrase.template, + phrase.commands.map { command -> + val width = if (fromClient) command.transmitBytes else command.receiveBytes + require(width in 0..8 && width <= readableBytes()) { "Truncated quickchat parameter" } + var value = 0L + repeat(width) { value = (value shl 8) or g1().toLong() } + QuickChat.Parameter(command.id, command.arguments, if (width == 0) null else value) + }, + ) +} + +internal fun JagByteBuf.readTypedVariable( + session: Session, + domain: Rs3VariableDomain, + id: Int = g2(), + fromClient: Boolean = false, +): TypedVariable { + val definition = + checkNotNull(session.rs3PacketDefinitions) { "RS3 packet cache is not initialized" } + .getVariable(domain, id) + val value = + when (definition.baseType) { + Rs3BaseVarType.INT -> TypedVariable.IntValue(g4()) + Rs3BaseVarType.LONG -> TypedVariable.LongValue(g8()) + Rs3BaseVarType.STRING -> + TypedVariable.StringValue( + if (fromClient) readNativeString2() else readNativeString(), + ) + Rs3BaseVarType.COORDINATE -> { + require(!fromClient) { "Coordinate varc uploads are not proven for revision 950 beta" } + val level = g1() + val x = g4() + val y = g4() + val z = g4() + TypedVariable.Coordinate(level, x, y, z) + } + } + return TypedVariable(id, definition.scriptType, value) +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/AddNewEmailAddressDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/AddNewEmailAddressDecoder.kt new file mode 100644 index 00000000..03510559 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/AddNewEmailAddressDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.account.AddNewEmailAddress +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class AddNewEmailAddressDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): AddNewEmailAddress { + val email = buffer.readNativeString() + val flags = buffer.g1() + return AddNewEmailAddress( + email, + flags, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/ChangeEmailAddressDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/ChangeEmailAddressDecoder.kt new file mode 100644 index 00000000..1fd10430 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/ChangeEmailAddressDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.account.ChangeEmailAddress +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class ChangeEmailAddressDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ChangeEmailAddress { + val newEmail = buffer.readNativeString() + val oldEmail = buffer.readNativeString() + return ChangeEmailAddress( + newEmail, + oldEmail, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/CreateLogProgressDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/CreateLogProgressDecoder.kt new file mode 100644 index 00000000..16675feb --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/CreateLogProgressDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.account.CreateLogProgress +import net.rsprox.protocol.session.Session + +internal class CreateLogProgressDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CreateLogProgress { + val progress = buffer.g1() + return CreateLogProgress( + progress, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/CreateSuggestNamesDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/CreateSuggestNamesDecoder.kt new file mode 100644 index 00000000..306ebd8b --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/CreateSuggestNamesDecoder.kt @@ -0,0 +1,18 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.account.CreateSuggestNames +import net.rsprox.protocol.session.Session + +internal class CreateSuggestNamesDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CreateSuggestNames { + return CreateSuggestNames + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/SendEmailValidationCodeDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/SendEmailValidationCodeDecoder.kt new file mode 100644 index 00000000..ad06e994 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/account/SendEmailValidationCodeDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.account.SendEmailValidationCode +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class SendEmailValidationCodeDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SendEmailValidationCode { + val code = buffer.readNativeString() + return SendEmailValidationCode( + code, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/If3ButtonDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/If3ButtonDecoder.kt new file mode 100644 index 00000000..53f8a233 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/If3ButtonDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.util.gCombinedIdAlt3 +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.buttons.If3Button +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.prot.GameClientProt +import net.rsprox.protocol.session.Session + +internal class If3ButtonDecoder( + override val prot: GameClientProt, + private val op: Int, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): If3Button { + val obj = buffer.g3Alt1() + val combinedId = buffer.gCombinedIdAlt3() + val slot = buffer.g2() + return If3Button( + combinedId, + obj, + slot, + op, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfButtonDDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfButtonDDecoder.kt new file mode 100644 index 00000000..0949190d --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfButtonDDecoder.kt @@ -0,0 +1,31 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.buttons.IfButtonD +import net.rsprox.protocol.session.Session + +internal class IfButtonDDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfButtonD { + val sourceObj = buffer.g3() + val targetObj = buffer.g3Alt2() + val targetCombinedId = buffer.g4Alt2() + val sourceCombinedId = buffer.g4() + val targetSub = buffer.g2Alt2() + val sourceSub = buffer.g2Alt3() + return IfButtonD( + sourceSub, + sourceCombinedId, + sourceObj, + targetSub, + targetCombinedId, + targetObj, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfButtonTDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfButtonTDecoder.kt new file mode 100644 index 00000000..7dcdcd8f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfButtonTDecoder.kt @@ -0,0 +1,31 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.buttons.IfButtonT +import net.rsprox.protocol.session.Session + +internal class IfButtonTDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfButtonT { + val selectedCombinedId = buffer.g4Alt2() + val targetCombinedId = buffer.g4() + val targetObj = buffer.g3() + val selectedSub = buffer.g2Alt3() + val selectedObj = buffer.g3Alt3() + val targetSub = buffer.g2Alt3() + return IfButtonT( + selectedSub, + selectedObj, + targetCombinedId, + targetSub, + selectedCombinedId, + targetObj, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfCrmViewOpDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfCrmViewOpDecoder.kt new file mode 100644 index 00000000..c1023226 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfCrmViewOpDecoder.kt @@ -0,0 +1,31 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.buttons.IfCrmViewOp +import net.rsprox.protocol.session.Session + +internal class IfCrmViewOpDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfCrmViewOp { + val selectedCrmEntry = buffer.g4Alt1() + val sub = buffer.g2Alt3() + val crmValue0 = buffer.g4() + val crmValue2 = buffer.g4Alt2() + val combinedId = buffer.g4Alt2() + val crmValue1 = buffer.g4Alt2() + return IfCrmViewOp( + sub, + crmValue0, + crmValue2, + crmValue1, + combinedId, + selectedCrmEntry, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfPlayerDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfPlayerDecoder.kt new file mode 100644 index 00000000..23025e6a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfPlayerDecoder.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.buttons.IfPlayer +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class IfPlayerDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfPlayer { + val crmName = buffer.readNativeString() + val crmType = buffer.g1Alt2() + val operation = buffer.g1Alt2() + val combinedId = buffer.g4Alt2() + val sub = buffer.g2Alt1() + return IfPlayer( + crmName, + combinedId, + operation, + sub, + crmType, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfTextChangeDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfTextChangeDecoder.kt new file mode 100644 index 00000000..6a3d5c20 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfTextChangeDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.buttons.IfTextChange +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class IfTextChangeDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfTextChange { + val combinedId = buffer.g4Alt3() + val text = buffer.readNativeString() + val sub = buffer.g2() + return IfTextChange( + combinedId, + sub, + text, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfValueChange32Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfValueChange32Decoder.kt new file mode 100644 index 00000000..e504d027 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/buttons/IfValueChange32Decoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.buttons.IfValueChange32 +import net.rsprox.protocol.session.Session + +internal class IfValueChange32Decoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfValueChange32 { + val flags = buffer.g1() + val combinedId = buffer.g4Alt3() + val value = buffer.g4Alt2() + val sub = buffer.g2Alt2() + return IfValueChange32( + value, + sub, + combinedId, + flags, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/ChatSetModeDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/ChatSetModeDecoder.kt new file mode 100644 index 00000000..039708d9 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/ChatSetModeDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.chat.ChatSetMode +import net.rsprox.protocol.session.Session + +internal class ChatSetModeDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ChatSetMode { + val channel = buffer.g1() + val mode = buffer.g1() + return ChatSetMode( + channel, + mode, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessagePrivateDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessagePrivateDecoder.kt new file mode 100644 index 00000000..8f9c6aaf --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessagePrivateDecoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.chat.MessagePrivate +import net.rsprox.protocol.rs3v950beta.buffer.readNativeHuffman +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class MessagePrivateDecoder( + override val prot: ClientProt, + private val huffmanCodec: HuffmanCodec, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessagePrivate { + val recipient = buffer.readNativeString() + val message = buffer.readNativeHuffman(huffmanCodec) + return MessagePrivate( + recipient, + message, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessagePublicDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessagePublicDecoder.kt new file mode 100644 index 00000000..81d80af0 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessagePublicDecoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.chat.MessagePublic +import net.rsprox.protocol.rs3v950beta.buffer.readNativeHuffman +import net.rsprox.protocol.session.Session + +internal class MessagePublicDecoder( + override val prot: ClientProt, + private val huffmanCodec: HuffmanCodec, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessagePublic { + // Only the default 0/0 prefix is natively proven; retain both bytes without guessing their roles. + val colourAndEffect = List(2) { buffer.g1() } + val message = buffer.readNativeHuffman(huffmanCodec) + return MessagePublic( + colourAndEffect, + message, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessageQuickchatPrivateDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessageQuickchatPrivateDecoder.kt new file mode 100644 index 00000000..3f95e400 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessageQuickchatPrivateDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.chat.MessageQuickchatPrivate +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.cache.readQuickChat +import net.rsprox.protocol.session.Session + +internal class MessageQuickchatPrivateDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessageQuickchatPrivate { + val recipient = buffer.readNativeString() + val phraseId = buffer.g2() + return MessageQuickchatPrivate(recipient, phraseId, buffer.readQuickChat(session, phraseId, fromClient = true)) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessageQuickchatPublicDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessageQuickchatPublicDecoder.kt new file mode 100644 index 00000000..ffe62e00 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/MessageQuickchatPublicDecoder.kt @@ -0,0 +1,20 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.chat.MessageQuickchatPublic +import net.rsprox.protocol.rs3v950beta.cache.readQuickChat +import net.rsprox.protocol.session.Session + +internal class MessageQuickchatPublicDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessageQuickchatPublic { + val phraseId = buffer.g2() + return MessageQuickchatPublic(phraseId, buffer.readQuickChat(session, phraseId, fromClient = true)) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/SetChatFilterSettingsDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/SetChatFilterSettingsDecoder.kt new file mode 100644 index 00000000..bfd719b8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/chat/SetChatFilterSettingsDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.chat.SetChatFilterSettings +import net.rsprox.protocol.session.Session + +internal class SetChatFilterSettingsDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SetChatFilterSettings { + val publicMode = buffer.g1() + val privateMode = buffer.g1() + val tradeMode = buffer.g1() + return SetChatFilterSettings( + publicMode, + privateMode, + tradeMode, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/AbortPDialogDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/AbortPDialogDecoder.kt new file mode 100644 index 00000000..7f9c6d4a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/AbortPDialogDecoder.kt @@ -0,0 +1,18 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.dialog.AbortPDialog +import net.rsprox.protocol.session.Session + +internal class AbortPDialogDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): AbortPDialog { + return AbortPDialog + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePClanForumQfcDialogDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePClanForumQfcDialogDecoder.kt new file mode 100644 index 00000000..fb85f5f8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePClanForumQfcDialogDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.dialog.ResumePClanForumQfcDialog +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class ResumePClanForumQfcDialogDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ResumePClanForumQfcDialog { + val value = buffer.readNativeString() + return ResumePClanForumQfcDialog( + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePCountDialogDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePCountDialogDecoder.kt new file mode 100644 index 00000000..92b56150 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePCountDialogDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.dialog.ResumePCountDialog +import net.rsprox.protocol.session.Session + +internal class ResumePCountDialogDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ResumePCountDialog { + val value = buffer.g4() + return ResumePCountDialog( + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePHslDialogDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePHslDialogDecoder.kt new file mode 100644 index 00000000..c9542caf --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePHslDialogDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.dialog.ResumePHslDialog +import net.rsprox.protocol.session.Session + +internal class ResumePHslDialogDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ResumePHslDialog { + val hsl = buffer.g2() + return ResumePHslDialog( + hsl, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePLongDialogDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePLongDialogDecoder.kt new file mode 100644 index 00000000..3b975b8d --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePLongDialogDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.dialog.ResumePLongDialog +import net.rsprox.protocol.session.Session + +internal class ResumePLongDialogDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ResumePLongDialog { + val value = buffer.g8() + return ResumePLongDialog( + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePNameDialogDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePNameDialogDecoder.kt new file mode 100644 index 00000000..63190a78 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePNameDialogDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.dialog.ResumePNameDialog +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class ResumePNameDialogDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ResumePNameDialog { + val value = buffer.readNativeString() + return ResumePNameDialog( + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePObjDialogDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePObjDialogDecoder.kt new file mode 100644 index 00000000..2cc341cb --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePObjDialogDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.dialog.ResumePObjDialog +import net.rsprox.protocol.session.Session + +internal class ResumePObjDialogDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ResumePObjDialog { + val obj = buffer.g2() + return ResumePObjDialog( + obj, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePStringDialogDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePStringDialogDecoder.kt new file mode 100644 index 00000000..ca33853a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePStringDialogDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.dialog.ResumePStringDialog +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class ResumePStringDialogDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ResumePStringDialog { + val value = buffer.readNativeString() + return ResumePStringDialog( + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePauseButtonDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePauseButtonDecoder.kt new file mode 100644 index 00000000..d0398c2e --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/dialog/ResumePauseButtonDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.dialog.ResumePauseButton +import net.rsprox.protocol.session.Session + +internal class ResumePauseButtonDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ResumePauseButton { + val combinedId = buffer.g4() + val sub = buffer.g2Alt1() + return ResumePauseButton( + combinedId, + sub, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/ClientDetailOptionsStatusDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/ClientDetailOptionsStatusDecoder.kt new file mode 100644 index 00000000..c786d546 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/ClientDetailOptionsStatusDecoder.kt @@ -0,0 +1,128 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.ClientDetailOptionsStatus +import net.rsprox.protocol.session.Session + +internal class ClientDetailOptionsStatusDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ClientDetailOptionsStatus { + val version = buffer.g1() + require(version == 38) { "Unsupported RS3 preference version $version" } + val compatibility1 = buffer.g1() + val compatibility2 = buffer.g1() + val setting0 = buffer.g1() + val setting1 = buffer.g1() + val setting2 = buffer.g1() + val compatibility6 = buffer.g1() + val setting3 = buffer.g1() + val setting4 = buffer.g1() + val compatibility9 = buffer.g1() + val setting5 = buffer.g1() + val setting6 = buffer.g1() + val compatibility12 = buffer.g1() + val compatibility13 = buffer.g1() + val compatibility14 = buffer.g1() + val setting7 = buffer.g1() + val compatibility16 = buffer.g1() + val compatibility17 = buffer.g1() + val compatibility18 = buffer.g1() + val setting8 = buffer.g1() + val compatibility20 = buffer.g1() + val compatibility21 = buffer.g1() + val compatibility22 = buffer.g1() + val setting9 = buffer.g1() + val compatibility24 = buffer.g1() + val compatibility25 = buffer.g1() + val compatibility26 = buffer.g1() + val setting10 = buffer.g1() + val setting11 = buffer.g1() + val setting12 = buffer.g1() + val setting13 = buffer.g1() + val setting14 = buffer.g1() + val setting15 = buffer.g1() + val setting16 = buffer.g1() + val setting17 = buffer.g1() + val setting18 = buffer.g1() + val setting19 = buffer.g2() + val setting20 = buffer.g2() + val setting21 = buffer.g2() + val setting22 = buffer.g2() + val setting23 = buffer.g1() + val setting24 = buffer.g1() + val compatibility46 = buffer.g1() + val compatibility47 = buffer.g1() + val compatibility48 = buffer.g1() + val compatibility49 = buffer.g1() + val compatibility50 = buffer.g1() + val compatibility51 = buffer.g1() + val setting25 = buffer.g1() + val setting26 = buffer.g1() + val setting27 = buffer.g1() + val setting28 = buffer.g1() + val setting29 = buffer.g1() + val compatibility57 = buffer.g1() + return ClientDetailOptionsStatus( + version, + compatibility1, + compatibility2, + setting0, + setting1, + setting2, + compatibility6, + setting3, + setting4, + compatibility9, + setting5, + setting6, + compatibility12, + compatibility13, + compatibility14, + setting7, + compatibility16, + compatibility17, + compatibility18, + setting8, + compatibility20, + compatibility21, + compatibility22, + setting9, + compatibility24, + compatibility25, + compatibility26, + setting10, + setting11, + setting12, + setting13, + setting14, + setting15, + setting16, + setting17, + setting18, + setting19, + setting20, + setting21, + setting22, + setting23, + setting24, + compatibility46, + compatibility47, + compatibility48, + compatibility49, + compatibility50, + compatibility51, + setting25, + setting26, + setting27, + setting28, + setting29, + compatibility57, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/Cutscene2DFinishedDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/Cutscene2DFinishedDecoder.kt new file mode 100644 index 00000000..7043fdaf --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/Cutscene2DFinishedDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.Cutscene2DFinished +import net.rsprox.protocol.session.Session + +internal class Cutscene2DFinishedDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): Cutscene2DFinished { + val id = buffer.g2Alt3() + val status = buffer.g1Alt1() + return Cutscene2DFinished( + status, + id, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventAppletFocusDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventAppletFocusDecoder.kt new file mode 100644 index 00000000..2964cf92 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventAppletFocusDecoder.kt @@ -0,0 +1,19 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.EventAppletFocus +import net.rsprox.protocol.session.Session + +internal class EventAppletFocusDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): EventAppletFocus { + val inFocus = buffer.g1() != 0 + return EventAppletFocus(inFocus) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventCameraPositionDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventCameraPositionDecoder.kt new file mode 100644 index 00000000..9191f1e1 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventCameraPositionDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.EventCameraPosition +import net.rsprox.protocol.session.Session + +internal class EventCameraPositionDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): EventCameraPosition { + val yaw = buffer.g2Alt3() + val pitch = buffer.g2Alt1() + return EventCameraPosition( + yaw, + pitch, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventKeyboardDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventKeyboardDecoder.kt new file mode 100644 index 00000000..fbf2178a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventKeyboardDecoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.EventKeyboard +import net.rsprox.protocol.session.Session + +internal class EventKeyboardDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): EventKeyboard { + require(buffer.readableBytes() > 0 && buffer.readableBytes() % 4 == 0) { + "Keyboard payload must contain complete four-byte records" + } + val events = + List(buffer.readableBytes() / 4) { + EventKeyboard.Key(buffer.g1(), buffer.g3()) + } + return EventKeyboard( + events, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventMouseClickDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventMouseClickDecoder.kt new file mode 100644 index 00000000..cb82110a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventMouseClickDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.EventMouseClick +import net.rsprox.protocol.session.Session + +internal class EventMouseClickDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): EventMouseClick { + val buttonAndDelta = buffer.g2Alt1() + val packedPosition = buffer.g4() + return EventMouseClick( + packedPosition, + buttonAndDelta, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventMouseMoveDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventMouseMoveDecoder.kt new file mode 100644 index 00000000..2b877be0 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventMouseMoveDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.EventMouseMove +import net.rsprox.protocol.session.Session + +internal class EventMouseMoveDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): EventMouseMove { + val meanRemainder = buffer.g1() + val remainder = buffer.g1() + val movements = buffer.readMouseMovements(nativeMouse = false) + return EventMouseMove( + meanRemainder, + remainder, + movements, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventNativeMouseClickDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventNativeMouseClickDecoder.kt new file mode 100644 index 00000000..ea3ecf82 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventNativeMouseClickDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.EventNativeMouseClick +import net.rsprox.protocol.session.Session + +internal class EventNativeMouseClickDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): EventNativeMouseClick { + val lastTransmittedMouseClick = buffer.g2() + val code = buffer.g1Alt3() + val packedPosition = buffer.g4() + val x = packedPosition and 0xFFFF + val y = packedPosition ushr 16 + return EventNativeMouseClick( + lastTransmittedMouseClick = lastTransmittedMouseClick, + code = code, + x = x, + y = y, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventNativeMouseMoveDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventNativeMouseMoveDecoder.kt new file mode 100644 index 00000000..f4f888a0 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/EventNativeMouseMoveDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.EventNativeMouseMove +import net.rsprox.protocol.session.Session + +internal class EventNativeMouseMoveDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): EventNativeMouseMove { + val meanRemainder = buffer.g1() + val remainder = buffer.g1() + val movements = buffer.readMouseMovements(nativeMouse = true) + return EventNativeMouseMove( + meanRemainder, + remainder, + movements, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/GameLogEventDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/GameLogEventDecoder.kt new file mode 100644 index 00000000..0fae34c5 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/GameLogEventDecoder.kt @@ -0,0 +1,40 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.cache.api.rs3.Rs3BaseVarType +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.cache.rs3PacketDefinitions +import net.rsprox.protocol.rs3.common.TypedVariable +import net.rsprox.protocol.rs3.game.incoming.model.events.GameLogEvent +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class GameLogEventDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): GameLogEvent { + val id = buffer.g2Alt1() + val value16 = buffer.g2() + val script = buffer.g4() + val definition = + checkNotNull(session.rs3PacketDefinitions) { "RS3 packet cache is not initialized" } + .getGameLogEvent(id) + val arguments = + definition.parameters.map { parameter -> + val value = + when (parameter.baseType) { + Rs3BaseVarType.INT -> TypedVariable.IntValue(buffer.g4()) + Rs3BaseVarType.LONG -> TypedVariable.LongValue(buffer.g8()) + Rs3BaseVarType.STRING -> TypedVariable.StringValue(buffer.readNativeString()) + Rs3BaseVarType.COORDINATE -> error("Unsupported game-log coordinate parameter") + } + GameLogEvent.Argument(parameter.scriptType, value) + } + require(buffer.readableBytes() == 0) { "Game-log payload does not match its cache definition" } + return GameLogEvent(id, value16, script, arguments) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/MidiSongStopDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/MidiSongStopDecoder.kt new file mode 100644 index 00000000..248ace13 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/MidiSongStopDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.MidiSongStop +import net.rsprox.protocol.session.Session + +internal class MidiSongStopDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MidiSongStop { + val song = buffer.g4() + return MidiSongStop( + song, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/MouseMovementReader.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/MouseMovementReader.kt new file mode 100644 index 00000000..f263b5f3 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/MouseMovementReader.kt @@ -0,0 +1,48 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprox.protocol.rs3.game.incoming.model.events.MouseMovement + +internal fun JagByteBuf.readMouseMovements(nativeMouse: Boolean): List { + require(isReadable) { "Mouse movement payload has no records" } + return buildList { + while (isReadable) { + val tag = g1() + val elapsedTicks: Int + val x: Int + val y: Int + val absolute: Boolean + when { + tag < 0x80 -> { + val packed = (tag shl 8) or g1() + elapsedTicks = packed ushr 12 + x = ((packed ushr 6) and 63) - 32 + y = (packed and 63) - 32 + absolute = false + } + tag < 0xA0 -> { + elapsedTicks = tag - 0x80 + x = g1() - 128 + y = g1() - 128 + absolute = false + } + tag < 0xC0 -> error("Invalid native mouse movement tag $tag") + else -> { + elapsedTicks = if (tag < 0xE0) tag - 0xC0 else ((tag and 31) shl 8) or g1() + val packed = g4() + x = if (packed == Int.MIN_VALUE) -1 else packed and 0xFFFF + y = if (packed == Int.MIN_VALUE) -1 else packed ushr 16 + absolute = true + } + } + val nativeFlags = if (nativeMouse) g1() else null + add( + if (absolute) { + MouseMovement.Absolute(elapsedTicks, x, y, nativeFlags) + } else { + MouseMovement.Delta(elapsedTicks, x, y, nativeFlags) + }, + ) + } + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/PingStatisticsDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/PingStatisticsDecoder.kt new file mode 100644 index 00000000..8d31cd53 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/PingStatisticsDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.PingStatistics +import net.rsprox.protocol.session.Session + +internal class PingStatisticsDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PingStatistics { + val reserved = buffer.g1() + val latency = buffer.g2Alt1() + val fps = buffer.g1Alt2() + return PingStatistics( + latency, + reserved, + fps, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/SendPingReplyDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/SendPingReplyDecoder.kt new file mode 100644 index 00000000..d7e1a234 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/SendPingReplyDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.SendPingReply +import net.rsprox.protocol.session.Session + +internal class SendPingReplyDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SendPingReply { + val fps = buffer.g1Alt3() + val challengeB = buffer.g4Alt3() + val challengeA = buffer.g4Alt1() + return SendPingReply( + fps, + challengeA, + challengeB, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/TransmitVarVerifyIdDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/TransmitVarVerifyIdDecoder.kt new file mode 100644 index 00000000..fc860084 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/TransmitVarVerifyIdDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.TransmitVarVerifyId +import net.rsprox.protocol.session.Session + +internal class TransmitVarVerifyIdDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TransmitVarVerifyId { + val verifyId = buffer.g4() + return TransmitVarVerifyId( + verifyId, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/UnnamedBatch80Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/UnnamedBatch80Decoder.kt new file mode 100644 index 00000000..a6dad57a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/UnnamedBatch80Decoder.kt @@ -0,0 +1,31 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.UnnamedBatch80 +import net.rsprox.protocol.session.Session + +internal class UnnamedBatch80Decoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UnnamedBatch80 { + val complete = buffer.g1() + val count = buffer.g2() + require(complete in 0..1 && count in 1..38 && buffer.readableBytes() == count * 13) { + "Invalid plugin batch framing" + } + val entries = + List(count) { + val field0 = buffer.g4() + val field1 = buffer.g4() + val field2 = buffer.g4() + val field3 = buffer.g1() + UnnamedBatch80.Entry(field0, field1, field2, field3) + } + return UnnamedBatch80(complete == 1, entries) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/UnnamedEvent92Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/UnnamedEvent92Decoder.kt new file mode 100644 index 00000000..7c295d32 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/UnnamedEvent92Decoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.UnnamedEvent92 +import net.rsprox.protocol.session.Session + +internal class UnnamedEvent92Decoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UnnamedEvent92 { + require(buffer.readableBytes() == 14) { "Invalid plugin event length" } + val field0 = buffer.g1Alt2() + val field4 = buffer.g1Alt3() + val field1 = buffer.g4Alt2() + val field3 = buffer.g4() + val field2 = buffer.g4() + return UnnamedEvent92(field0, field1, field2, field3, field4) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/WindowStatusDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/WindowStatusDecoder.kt new file mode 100644 index 00000000..e4903cde --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/events/WindowStatusDecoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.events.WindowStatus +import net.rsprox.protocol.session.Session + +internal class WindowStatusDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): WindowStatus { + val mode = buffer.g1() + val width = buffer.g2() + val height = buffer.g2() + val antialias = buffer.g1() + return WindowStatus( + mode, + width, + height, + antialias, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/locs/OpLocDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/locs/OpLocDecoder.kt new file mode 100644 index 00000000..9e356f76 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/locs/OpLocDecoder.kt @@ -0,0 +1,36 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.locs + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.locs.OpLoc +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.prot.GameClientProt +import net.rsprox.protocol.session.Session + +internal class OpLocDecoder( + override val prot: ClientProt, + private val op: Int, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): OpLoc { + val run = (buffer.g1Alt3() and 1) != 0 + val locId = buffer.g4Alt2() + val y = buffer.g2Alt3() + val x = buffer.g2Alt2() + return OpLoc(locId, x, y, op, run) + } + + internal companion object { + internal fun all(): List = + listOf( + OpLocDecoder(GameClientProt.OPLOC1, 1), + OpLocDecoder(GameClientProt.OPLOC2, 2), + OpLocDecoder(GameClientProt.OPLOC3, 3), + OpLocDecoder(GameClientProt.OPLOC4, 4), + OpLocDecoder(GameClientProt.OPLOC5, 5), + OpLocDecoder(GameClientProt.OPLOC6, 6), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/locs/OpLocTDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/locs/OpLocTDecoder.kt new file mode 100644 index 00000000..bb2629ae --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/locs/OpLocTDecoder.kt @@ -0,0 +1,33 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.locs + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.locs.OpLocT +import net.rsprox.protocol.session.Session + +internal class OpLocTDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): OpLocT { + val x = buffer.g2Alt3() + val controlKey = buffer.g1Alt1() + val selectedSub = buffer.g2Alt3() + val selectedCombinedId = buffer.g4Alt3() + val z = buffer.g2() + val selectedObj = buffer.g3Alt2() + val id = buffer.g4Alt1() + return OpLocT( + controlKey, + x, + selectedSub, + z, + selectedObj, + id, + selectedCombinedId, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/MapBuildCompleteDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/MapBuildCompleteDecoder.kt new file mode 100644 index 00000000..aa1dbd41 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/MapBuildCompleteDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.client.MapBuildComplete +import net.rsprox.protocol.session.Session + +internal class MapBuildCompleteDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MapBuildComplete { + val buildDurationMillis = buffer.g4() + return MapBuildComplete( + buildDurationMillis, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/NoTimeoutDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/NoTimeoutDecoder.kt new file mode 100644 index 00000000..a370aba7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/NoTimeoutDecoder.kt @@ -0,0 +1,18 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.client.NoTimeout +import net.rsprox.protocol.session.Session + +internal class NoTimeoutDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): NoTimeout { + return NoTimeout + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/StoreServerPermVarcsDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/StoreServerPermVarcsDecoder.kt new file mode 100644 index 00000000..8204a9c8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/StoreServerPermVarcsDecoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.cache.api.rs3.Rs3VariableDomain +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.client.StoreServerPermVarcs +import net.rsprox.protocol.rs3v950beta.cache.readTypedVariable +import net.rsprox.protocol.session.Session + +internal class StoreServerPermVarcsDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): StoreServerPermVarcs { + val complete = buffer.g1() + val variables = + buildList { + while (buffer.isReadable) { + add(buffer.readTypedVariable(session, Rs3VariableDomain.CLIENT, fromClient = true)) + } + } + return StoreServerPermVarcs(complete, variables) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/UidPassportResendRequestDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/UidPassportResendRequestDecoder.kt new file mode 100644 index 00000000..6d9d1386 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/client/UidPassportResendRequestDecoder.kt @@ -0,0 +1,18 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.client.UidPassportResendRequest +import net.rsprox.protocol.session.Session + +internal class UidPassportResendRequestDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UidPassportResendRequest { + return UidPassportResendRequest + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/ApCoordTDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/ApCoordTDecoder.kt new file mode 100644 index 00000000..26f290df --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/ApCoordTDecoder.kt @@ -0,0 +1,29 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.ApCoordT +import net.rsprox.protocol.session.Session + +internal class ApCoordTDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ApCoordT { + val selectedObj = buffer.g3Alt3() + val x = buffer.g2Alt2() + val z = buffer.g2Alt1() + val selectedSub = buffer.g2() + val selectedCombinedId = buffer.g4Alt2() + return ApCoordT( + selectedSub, + selectedObj, + selectedCombinedId, + x, + z, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/BugReportDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/BugReportDecoder.kt new file mode 100644 index 00000000..1c1222c0 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/BugReportDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.BugReport +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString2 +import net.rsprox.protocol.session.Session + +internal class BugReportDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): BugReport { + val summary = buffer.readNativeString2() + val details = buffer.readNativeString2() + val reportCategory = buffer.g1Alt2() + return BugReport( + reportCategory, + details, + summary, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/ClickWorldMapDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/ClickWorldMapDecoder.kt new file mode 100644 index 00000000..19bb5a8f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/ClickWorldMapDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.ClickWorldMap +import net.rsprox.protocol.session.Session + +internal class ClickWorldMapDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ClickWorldMap { + val packedCoordinate = buffer.g4Alt1() + return ClickWorldMap( + packedCoordinate, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/ClientCheatDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/ClientCheatDecoder.kt new file mode 100644 index 00000000..d5c39f5c --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/ClientCheatDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.ClientCheat +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class ClientCheatDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ClientCheat { + val flagA = buffer.g1() + val flagB = buffer.g1() + val command = buffer.readNativeString() + return ClientCheat( + flagA, + flagB, + command, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/CloseModalDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/CloseModalDecoder.kt new file mode 100644 index 00000000..79305768 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/CloseModalDecoder.kt @@ -0,0 +1,18 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.CloseModal +import net.rsprox.protocol.session.Session + +internal class CloseModalDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CloseModal { + return CloseModal + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/FaceSquareDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/FaceSquareDecoder.kt new file mode 100644 index 00000000..fe60d4e3 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/FaceSquareDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.FaceSquare +import net.rsprox.protocol.session.Session + +internal class FaceSquareDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): FaceSquare { + val z = buffer.g2Alt3() + val x = buffer.g2Alt2() + return FaceSquare( + x, + z, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/LocSelectSubmitDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/LocSelectSubmitDecoder.kt new file mode 100644 index 00000000..27daeede --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/LocSelectSubmitDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.LocSelectSubmit +import net.rsprox.protocol.session.Session + +internal class LocSelectSubmitDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LocSelectSubmit { + val packedCoordinate = buffer.g4() + val cursorStyle = buffer.g1Alt1() + return LocSelectSubmit( + cursorStyle, + packedCoordinate, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/MoveGameClickDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/MoveGameClickDecoder.kt new file mode 100644 index 00000000..094a5d04 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/MoveGameClickDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.MoveGameClick +import net.rsprox.protocol.session.Session + +internal class MoveGameClickDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MoveGameClick { + val x = buffer.g2Alt3() + val run = (buffer.g1Alt2() and 1) != 0 + val y = buffer.g2Alt1() + return MoveGameClick(x, y, run) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/MoveMinimapClickDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/MoveMinimapClickDecoder.kt new file mode 100644 index 00000000..12c99ca2 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/MoveMinimapClickDecoder.kt @@ -0,0 +1,34 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.MoveMinimapClick +import net.rsprox.protocol.session.Session + +internal class MoveMinimapClickDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MoveMinimapClick { + val x = buffer.g2Alt3() + val controlKey = buffer.g1Alt2() + val z = buffer.g2Alt1() + // The normal sender emits ff ff 00 00 39 00 00 59. Preserve it instead of discarding it. + val reservedMinimapMetadata = List(8) { buffer.g1() } + val playerX = buffer.g2() + val playerZ = buffer.g2() + val sentinel = buffer.g1() + return MoveMinimapClick( + z, + controlKey, + x, + reservedMinimapMetadata, + playerX, + playerZ, + sentinel, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/MoveScriptedDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/MoveScriptedDecoder.kt new file mode 100644 index 00000000..095e7f3e --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/MoveScriptedDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.MoveScripted +import net.rsprox.protocol.session.Session + +internal class MoveScriptedDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MoveScripted { + val z = buffer.g2Alt2() + val mode = buffer.g1() + val x = buffer.g2Alt1() + return MoveScripted( + z, + x, + mode, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/SendSnapshotDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/SendSnapshotDecoder.kt new file mode 100644 index 00000000..7187eb25 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/SendSnapshotDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.SendSnapshot +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class SendSnapshotDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SendSnapshot { + val name = buffer.readNativeString() + val categoryIndex = buffer.g1() + val includeImage = buffer.g1() + val description = buffer.readNativeString() + return SendSnapshot( + name, + categoryIndex, + includeImage, + description, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/UrlRequestDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/UrlRequestDecoder.kt new file mode 100644 index 00000000..a41649e7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/UrlRequestDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.UrlRequest +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class UrlRequestDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UrlRequest { + val url = buffer.readNativeString() + val textA = buffer.readNativeString() + val textB = buffer.readNativeString() + val flags = buffer.g1() + return UrlRequest( + url, + textA, + textB, + flags, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/WorldListFetchDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/WorldListFetchDecoder.kt new file mode 100644 index 00000000..b5a98c2a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/misc/user/WorldListFetchDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.misc.user.WorldListFetch +import net.rsprox.protocol.session.Session + +internal class WorldListFetchDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): WorldListFetch { + val crc = buffer.g4() + return WorldListFetch( + crc, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/npcs/OpNpcDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/npcs/OpNpcDecoder.kt new file mode 100644 index 00000000..135b3c3c --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/npcs/OpNpcDecoder.kt @@ -0,0 +1,38 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.npcs + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.npcs.OpNpc +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.prot.GameClientProt +import net.rsprox.protocol.session.Session + +internal class OpNpcDecoder( + override val prot: ClientProt, + private val op: Int, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): OpNpc { + val run = (buffer.g1() and 1) != 0 + val index = buffer.g2Alt2() + return OpNpc( + index, + op, + run, + ) + } + + internal companion object { + internal fun all(): List = + listOf( + OpNpcDecoder(GameClientProt.OPNPC1, 1), + OpNpcDecoder(GameClientProt.OPNPC2, 2), + OpNpcDecoder(GameClientProt.OPNPC3, 3), + OpNpcDecoder(GameClientProt.OPNPC4, 4), + OpNpcDecoder(GameClientProt.OPNPC5, 5), + OpNpcDecoder(GameClientProt.OPNPC6, 6), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/npcs/OpNpcTDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/npcs/OpNpcTDecoder.kt new file mode 100644 index 00000000..75b87e82 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/npcs/OpNpcTDecoder.kt @@ -0,0 +1,29 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.npcs + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.npcs.OpNpcT +import net.rsprox.protocol.session.Session + +internal class OpNpcTDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): OpNpcT { + val index = buffer.g2() + val selectedObj = buffer.g3Alt1() + val selectedCombinedId = buffer.g4Alt3() + val controlKey = buffer.g1Alt3() + val selectedSub = buffer.g2Alt2() + return OpNpcT( + index, + selectedObj, + controlKey, + selectedSub, + selectedCombinedId, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/objs/OpObjDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/objs/OpObjDecoder.kt new file mode 100644 index 00000000..e1d09669 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/objs/OpObjDecoder.kt @@ -0,0 +1,37 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.objs + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.objs.OpObj +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.prot.GameClientProt +import net.rsprox.protocol.session.Session + +internal class OpObjDecoder( + override val prot: ClientProt, + private val op: Int, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): OpObj { + val flags = buffer.g1() + val run = (flags and 1) != 0 + val x = buffer.g2Alt2() + val y = buffer.g2Alt2() + val objId = buffer.g3Alt3() + return OpObj(objId, x, y, op, run, flags) + } + + internal companion object { + internal fun all(): List = + listOf( + OpObjDecoder(GameClientProt.OPOBJ1_V2, 1), + OpObjDecoder(GameClientProt.OPOBJ2_V2, 2), + OpObjDecoder(GameClientProt.OPOBJ3_V2, 3), + OpObjDecoder(GameClientProt.OPOBJ4_V2, 4), + OpObjDecoder(GameClientProt.OPOBJ5_V2, 5), + OpObjDecoder(GameClientProt.OPOBJ6_V2, 6), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/objs/OpObjTDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/objs/OpObjTDecoder.kt new file mode 100644 index 00000000..827e9a00 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/objs/OpObjTDecoder.kt @@ -0,0 +1,33 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.objs + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.objs.OpObjT +import net.rsprox.protocol.session.Session + +internal class OpObjTDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): OpObjT { + val flags = buffer.g1() + val selectedSub = buffer.g2() + val id = buffer.g3Alt2() + val x = buffer.g2Alt2() + val selectedObj = buffer.g3() + val selectedCombinedId = buffer.g4Alt3() + val z = buffer.g2Alt1() + return OpObjT( + x, + flags, + selectedSub, + selectedObj, + z, + selectedCombinedId, + id, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/players/OpPlayerDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/players/OpPlayerDecoder.kt new file mode 100644 index 00000000..063cf1db --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/players/OpPlayerDecoder.kt @@ -0,0 +1,42 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.players + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.players.OpPlayer +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.prot.GameClientProt +import net.rsprox.protocol.session.Session + +internal class OpPlayerDecoder( + override val prot: ClientProt, + private val op: Int, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): OpPlayer { + val run = (buffer.g1Alt2() and 1) != 0 + val index = buffer.g2() + return OpPlayer( + index, + op, + run, + ) + } + + internal companion object { + internal fun all(): List = + listOf( + OpPlayerDecoder(GameClientProt.OPPLAYER1, 1), + OpPlayerDecoder(GameClientProt.OPPLAYER2, 2), + OpPlayerDecoder(GameClientProt.OPPLAYER3, 3), + OpPlayerDecoder(GameClientProt.OPPLAYER4, 4), + OpPlayerDecoder(GameClientProt.OPPLAYER5, 5), + OpPlayerDecoder(GameClientProt.OPPLAYER6, 6), + OpPlayerDecoder(GameClientProt.OPPLAYER7, 7), + OpPlayerDecoder(GameClientProt.OPPLAYER8, 8), + OpPlayerDecoder(GameClientProt.OPPLAYER9, 9), + OpPlayerDecoder(GameClientProt.OPPLAYER10, 10), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/players/OpPlayerTDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/players/OpPlayerTDecoder.kt new file mode 100644 index 00000000..40469101 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/players/OpPlayerTDecoder.kt @@ -0,0 +1,29 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.players + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.players.OpPlayerT +import net.rsprox.protocol.session.Session + +internal class OpPlayerTDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): OpPlayerT { + val controlKey = buffer.g1Alt1() + val selectedCombinedId = buffer.g4Alt1() + val index = buffer.g2Alt1() + val selectedObj = buffer.g3Alt1() + val selectedSub = buffer.g2Alt1() + return OpPlayerT( + controlKey, + index, + selectedSub, + selectedObj, + selectedCombinedId, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/AffinedClanSettingsAddBannedFromChannelDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/AffinedClanSettingsAddBannedFromChannelDecoder.kt new file mode 100644 index 00000000..1857ba00 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/AffinedClanSettingsAddBannedFromChannelDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.AffinedClanSettingsAddBannedFromChannel +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class AffinedClanSettingsAddBannedFromChannelDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): AffinedClanSettingsAddBannedFromChannel { + val channel = buffer.g1() + val member = buffer.g2() + val name = buffer.readNativeString() + return AffinedClanSettingsAddBannedFromChannel( + channel, + member, + name, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/AffinedClanSettingsSetMutedFromChannelDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/AffinedClanSettingsSetMutedFromChannelDecoder.kt new file mode 100644 index 00000000..83c72259 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/AffinedClanSettingsSetMutedFromChannelDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.AffinedClanSettingsSetMutedFromChannel +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class AffinedClanSettingsSetMutedFromChannelDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): AffinedClanSettingsSetMutedFromChannel { + val channel = buffer.g1() + val member = buffer.g2() + val muted = buffer.g1() + val name = buffer.readNativeString() + return AffinedClanSettingsSetMutedFromChannel( + channel, + member, + muted, + name, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/ClanChannelKickUserDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/ClanChannelKickUserDecoder.kt new file mode 100644 index 00000000..b343344b --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/ClanChannelKickUserDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.ClanChannelKickUser +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class ClanChannelKickUserDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ClanChannelKickUser { + val channel = buffer.g1() + val member = buffer.g2() + val name = buffer.readNativeString() + return ClanChannelKickUser( + channel, + member, + name, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/ClanJoinChatLeaveChatDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/ClanJoinChatLeaveChatDecoder.kt new file mode 100644 index 00000000..cb86286c --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/ClanJoinChatLeaveChatDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.ClanJoinChatLeaveChat +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class ClanJoinChatLeaveChatDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ClanJoinChatLeaveChat { + // Native CLAN_LEAVECHAT writes only a zero frame length, without a string terminator. + if (!buffer.isReadable) { + return ClanJoinChatLeaveChat(null) + } + val name = buffer.readNativeString() + return ClanJoinChatLeaveChat( + name, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/ClanKickUserDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/ClanKickUserDecoder.kt new file mode 100644 index 00000000..fadbb975 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/ClanKickUserDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.ClanKickUser +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class ClanKickUserDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ClanKickUser { + val name = buffer.readNativeString() + return ClanKickUser( + name, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendListAddDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendListAddDecoder.kt new file mode 100644 index 00000000..a560b810 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendListAddDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.FriendListAdd +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class FriendListAddDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): FriendListAdd { + val name = buffer.readNativeString() + return FriendListAdd( + name, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendListDelDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendListDelDecoder.kt new file mode 100644 index 00000000..958a9055 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendListDelDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.FriendListDel +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class FriendListDelDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): FriendListDel { + val name = buffer.readNativeString() + return FriendListDel( + name, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendSetNotesDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendSetNotesDecoder.kt new file mode 100644 index 00000000..1a88d158 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendSetNotesDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.FriendSetNotes +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class FriendSetNotesDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): FriendSetNotes { + val name = buffer.readNativeString() + val note = buffer.readNativeString() + return FriendSetNotes( + name, + note, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendSetRankDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendSetRankDecoder.kt new file mode 100644 index 00000000..a1692849 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/FriendSetRankDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.FriendSetRank +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class FriendSetRankDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): FriendSetRank { + val rank = buffer.g1Alt3() + val name = buffer.readNativeString() + return FriendSetRank( + name, + rank, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/IgnoreListAddDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/IgnoreListAddDecoder.kt new file mode 100644 index 00000000..b6d271d1 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/IgnoreListAddDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.IgnoreListAdd +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class IgnoreListAddDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IgnoreListAdd { + val name = buffer.readNativeString() + val temporary = buffer.g1() + return IgnoreListAdd( + name, + temporary, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/IgnoreListDelDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/IgnoreListDelDecoder.kt new file mode 100644 index 00000000..0cb06225 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/IgnoreListDelDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.IgnoreListDel +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class IgnoreListDelDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IgnoreListDel { + val name = buffer.readNativeString() + return IgnoreListDel( + name, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/IgnoreSetNotesDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/IgnoreSetNotesDecoder.kt new file mode 100644 index 00000000..01b8aaeb --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/codec/social/IgnoreSetNotesDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.incoming.model.social.IgnoreSetNotes +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.session.Session + +internal class IgnoreSetNotesDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IgnoreSetNotes { + val name = buffer.readNativeString() + val note = buffer.readNativeString() + return IgnoreSetNotes( + note, + name, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/prot/ClientMessageDecoderRepository.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/prot/ClientMessageDecoderRepository.kt new file mode 100644 index 00000000..d2ac4004 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/prot/ClientMessageDecoderRepository.kt @@ -0,0 +1,196 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.prot + +import net.rsprot.compression.HuffmanCodec +import net.rsprot.protocol.ProtRepository +import net.rsprox.protocol.MessageDecoderRepository +import net.rsprox.protocol.MessageDecoderRepositoryBuilder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.account.AddNewEmailAddressDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.account.ChangeEmailAddressDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.account.CreateLogProgressDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.account.CreateSuggestNamesDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.account.SendEmailValidationCodeDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons.If3ButtonDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons.IfButtonDDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons.IfButtonTDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons.IfCrmViewOpDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons.IfPlayerDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons.IfTextChangeDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.buttons.IfValueChange32Decoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat.ChatSetModeDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat.MessagePrivateDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat.MessagePublicDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat.MessageQuickchatPrivateDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat.MessageQuickchatPublicDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.chat.SetChatFilterSettingsDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog.AbortPDialogDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog.ResumePClanForumQfcDialogDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog.ResumePCountDialogDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog.ResumePHslDialogDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog.ResumePLongDialogDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog.ResumePNameDialogDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog.ResumePObjDialogDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog.ResumePStringDialogDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.dialog.ResumePauseButtonDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.ClientDetailOptionsStatusDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.Cutscene2DFinishedDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.EventAppletFocusDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.EventCameraPositionDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.EventKeyboardDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.EventMouseClickDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.EventMouseMoveDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.EventNativeMouseClickDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.EventNativeMouseMoveDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.GameLogEventDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.MidiSongStopDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.PingStatisticsDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.SendPingReplyDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.TransmitVarVerifyIdDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.UnnamedBatch80Decoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.UnnamedEvent92Decoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.events.WindowStatusDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.locs.OpLocDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.locs.OpLocTDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.client.MapBuildCompleteDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.client.NoTimeoutDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.client.StoreServerPermVarcsDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.client.UidPassportResendRequestDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.ApCoordTDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.BugReportDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.ClickWorldMapDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.ClientCheatDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.CloseModalDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.FaceSquareDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.LocSelectSubmitDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.MoveGameClickDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.MoveMinimapClickDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.MoveScriptedDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.SendSnapshotDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.UrlRequestDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.misc.user.WorldListFetchDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.npcs.OpNpcDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.npcs.OpNpcTDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.objs.OpObjDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.objs.OpObjTDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.players.OpPlayerDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.players.OpPlayerTDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.AffinedClanSettingsAddBannedFromChannelDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.AffinedClanSettingsSetMutedFromChannelDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.ClanChannelKickUserDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.ClanJoinChatLeaveChatDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.ClanKickUserDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.FriendListAddDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.FriendListDelDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.FriendSetNotesDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.FriendSetRankDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.IgnoreListAddDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.IgnoreListDelDecoder +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.codec.social.IgnoreSetNotesDecoder + +internal object ClientMessageDecoderRepository { + @ExperimentalStdlibApi + fun build(huffmanCodec: HuffmanCodec): MessageDecoderRepository { + val protRepository = ProtRepository.of() + val builder = + MessageDecoderRepositoryBuilder(protRepository).apply { + bind(If3ButtonDecoder(GameClientProt.IF_BUTTON1_V2, 1)) + bind(If3ButtonDecoder(GameClientProt.IF_BUTTON2_V2, 2)) + bind(If3ButtonDecoder(GameClientProt.IF_BUTTON3_V2, 3)) + bind(If3ButtonDecoder(GameClientProt.IF_BUTTON4_V2, 4)) + bind(If3ButtonDecoder(GameClientProt.IF_BUTTON5_V2, 5)) + bind(If3ButtonDecoder(GameClientProt.IF_BUTTON6_V2, 6)) + bind(If3ButtonDecoder(GameClientProt.IF_BUTTON7_V2, 7)) + bind(If3ButtonDecoder(GameClientProt.IF_BUTTON8_V2, 8)) + bind(If3ButtonDecoder(GameClientProt.IF_BUTTON9_V2, 9)) + bind(If3ButtonDecoder(GameClientProt.IF_BUTTON10_V2, 10)) + for (decoder in OpNpcDecoder.all()) bind(decoder) + for (decoder in OpLocDecoder.all()) bind(decoder) + for (decoder in OpObjDecoder.all()) bind(decoder) + for (decoder in OpPlayerDecoder.all()) bind(decoder) + bind(EventAppletFocusDecoder(GameClientProt.EVENT_APPLET_FOCUS)) + bind(EventNativeMouseClickDecoder(GameClientProt.EVENT_NATIVE_MOUSE_CLICK)) + bind(MoveGameClickDecoder(GameClientProt.MOVE_GAMECLICK)) + bind(MoveMinimapClickDecoder(GameClientProt.MOVE_MINIMAPCLICK)) + bind(MoveScriptedDecoder(GameClientProt.MOVE_SCRIPTED)) + bind(OpNpcTDecoder(GameClientProt.OPNPCT_V2)) + bind(OpPlayerTDecoder(GameClientProt.OPPLAYERT_V2)) + bind(OpLocTDecoder(GameClientProt.OPLOCT_V2)) + bind(OpObjTDecoder(GameClientProt.OPOBJT_V2)) + bind(ApCoordTDecoder(GameClientProt.APCOORDT_V2)) + bind(IfButtonTDecoder(GameClientProt.IF_BUTTONT_V2)) + bind(IfButtonDDecoder(GameClientProt.IF_BUTTOND_V2)) + bind(EventCameraPositionDecoder(GameClientProt.EVENT_CAMERA_POSITION)) + bind(WindowStatusDecoder(GameClientProt.WINDOW_STATUS)) + bind(ResumePauseButtonDecoder(GameClientProt.RESUME_PAUSEBUTTON)) + bind(ResumePCountDialogDecoder(GameClientProt.RESUME_P_COUNTDIALOG)) + bind(ResumePLongDialogDecoder(GameClientProt.RESUME_P_LONGDIALOG)) + bind(ResumePHslDialogDecoder(GameClientProt.RESUME_P_HSLDIALOG)) + bind(ResumePObjDialogDecoder(GameClientProt.RESUME_P_OBJDIALOG)) + bind(ResumePStringDialogDecoder(GameClientProt.RESUME_P_STRINGDIALOG)) + bind(ResumePNameDialogDecoder(GameClientProt.RESUME_P_NAMEDIALOG)) + bind(ResumePClanForumQfcDialogDecoder(GameClientProt.RESUME_P_CLANFORUMQFCDIALOG)) + bind(MessagePublicDecoder(GameClientProt.MESSAGE_PUBLIC, huffmanCodec)) + bind(MessagePrivateDecoder(GameClientProt.MESSAGE_PRIVATE, huffmanCodec)) + bind(ClientCheatDecoder(GameClientProt.CLIENT_CHEAT)) + bind(ChatSetModeDecoder(GameClientProt.CHAT_SETMODE)) + bind(SetChatFilterSettingsDecoder(GameClientProt.SET_CHATFILTERSETTINGS)) + bind(CloseModalDecoder(GameClientProt.CLOSE_MODAL)) + bind(AbortPDialogDecoder(GameClientProt.ABORT_P_DIALOG)) + bind(CreateSuggestNamesDecoder(GameClientProt.CREATE_SUGGEST_NAMES)) + bind(NoTimeoutDecoder(GameClientProt.NO_TIMEOUT)) + bind(MapBuildCompleteDecoder(GameClientProt.MAP_BUILD_COMPLETE)) + bind(IfPlayerDecoder(GameClientProt.IF_PLAYER)) + bind(IgnoreListDelDecoder(GameClientProt.IGNORELIST_DEL)) + bind(FriendListAddDecoder(GameClientProt.FRIENDLIST_ADD)) + bind(ClanChannelKickUserDecoder(GameClientProt.CLANCHANNEL_KICKUSER)) + bind(ClickWorldMapDecoder(GameClientProt.CLICKWORLDMAP)) + bind(BugReportDecoder(GameClientProt.BUG_REPORT)) + bind(IfCrmViewOpDecoder(GameClientProt.IF_CRMVIEW_OP)) + bind(Cutscene2DFinishedDecoder(GameClientProt.CUTSCENE2D_FINISHED)) + bind(TransmitVarVerifyIdDecoder(GameClientProt.TRANSMITVAR_VERIFYID)) + bind(PingStatisticsDecoder(GameClientProt.PING_STATISTICS)) + bind(GameLogEventDecoder(GameClientProt.GAMELOGEVENT)) + bind(UnnamedBatch80Decoder(GameClientProt.UNNAMED_BATCH_80)) + bind(UnnamedEvent92Decoder(GameClientProt.UNNAMED_EVENT_92)) + bind(SendEmailValidationCodeDecoder(GameClientProt.SEND_EMAIL_VALIDATION_CODE)) + bind(FriendListDelDecoder(GameClientProt.FRIENDLIST_DEL)) + bind(ClanKickUserDecoder(GameClientProt.CLAN_KICKUSER)) + bind( + AffinedClanSettingsSetMutedFromChannelDecoder( + GameClientProt.AFFINEDCLANSETTINGS_SETMUTED_FROMCHANNEL, + ), + ) + bind(FaceSquareDecoder(GameClientProt.FACE_SQUARE)) + bind(UrlRequestDecoder(GameClientProt.URL_REQUEST)) + bind(EventMouseClickDecoder(GameClientProt.EVENT_MOUSE_CLICK)) + bind(ClanJoinChatLeaveChatDecoder(GameClientProt.CLAN_JOINCHAT_LEAVECHAT)) + bind(CreateLogProgressDecoder(GameClientProt.CREATE_LOG_PROGRESS)) + bind(IgnoreSetNotesDecoder(GameClientProt.IGNORE_SETNOTES)) + bind( + AffinedClanSettingsAddBannedFromChannelDecoder( + GameClientProt.AFFINEDCLANSETTINGS_ADDBANNED_FROMCHANNEL, + ), + ) + bind(FriendSetNotesDecoder(GameClientProt.FRIEND_SETNOTES)) + bind(SendPingReplyDecoder(GameClientProt.SEND_PING_REPLY)) + bind(FriendSetRankDecoder(GameClientProt.FRIEND_SETRANK)) + bind(WorldListFetchDecoder(GameClientProt.WORLDLIST_FETCH)) + bind(MidiSongStopDecoder(GameClientProt.MIDI_SONG_STOP)) + bind(IgnoreListAddDecoder(GameClientProt.IGNORELIST_ADD)) + bind(IfTextChangeDecoder(GameClientProt.IF_TEXT_CHANGE)) + bind(IfValueChange32Decoder(GameClientProt.IF_VALUE_CHANGE_32)) + bind(LocSelectSubmitDecoder(GameClientProt.LOCSELECT_SUBMIT)) + bind(EventKeyboardDecoder(GameClientProt.EVENT_KEYBOARD)) + bind(EventMouseMoveDecoder(GameClientProt.EVENT_MOUSE_MOVE)) + bind(EventNativeMouseMoveDecoder(GameClientProt.EVENT_NATIVE_MOUSE_MOVE)) + bind(SendSnapshotDecoder(GameClientProt.SEND_SNAPSHOT)) + bind(AddNewEmailAddressDecoder(GameClientProt.ADD_NEW_EMAIL_ADDRESS)) + bind(ChangeEmailAddressDecoder(GameClientProt.CHANGE_EMAIL_ADDRESS)) + bind(UidPassportResendRequestDecoder(GameClientProt.UID_PASSPORT_RESEND_REQUEST)) + bind(MessageQuickchatPublicDecoder(GameClientProt.MESSAGE_QUICKCHAT_PUBLIC)) + bind(MessageQuickchatPrivateDecoder(GameClientProt.MESSAGE_QUICKCHAT_PRIVATE)) + bind(StoreServerPermVarcsDecoder(GameClientProt.STORE_SERVERPERM_VARCS)) + bind(ClientDetailOptionsStatusDecoder(GameClientProt.CLIENT_DETAILOPTIONS_STATUS)) + } + return builder.build() + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/prot/GameClientProt.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/prot/GameClientProt.kt new file mode 100644 index 00000000..c3a4f1d1 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/prot/GameClientProt.kt @@ -0,0 +1,145 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.prot + +import net.rsprot.protocol.ClientProt +import net.rsprot.protocol.Prot + +public enum class GameClientProt( + override val opcode: Int, + override val size: Int, +) : ClientProt { + OPOBJ3_V2(GameClientProtId.OPOBJ3_V2, 8), + MESSAGE_QUICKCHAT_PUBLIC(GameClientProtId.MESSAGE_QUICKCHAT_PUBLIC, Prot.VAR_BYTE), + UNNAMED_OPCODE_2(GameClientProtId.UNNAMED_OPCODE_2, 4), + IGNORE_SETNOTES(GameClientProtId.IGNORE_SETNOTES, Prot.VAR_BYTE), + EVENT_MOUSE_MOVE(GameClientProtId.EVENT_MOUSE_MOVE, Prot.VAR_BYTE), + EVENT_NATIVE_MOUSE_MOVE(GameClientProtId.EVENT_NATIVE_MOUSE_MOVE, Prot.VAR_BYTE), + RESUME_P_OBJDIALOG(GameClientProtId.RESUME_P_OBJDIALOG, 2), + IF_BUTTON10_V2(GameClientProtId.IF_BUTTON10_V2, 9), + RESUME_P_COUNTDIALOG(GameClientProtId.RESUME_P_COUNTDIALOG, 4), + OPPLAYER8(GameClientProtId.OPPLAYER8, 3), + CREATE_CHECK_EMAIL(GameClientProtId.CREATE_CHECK_EMAIL, Prot.VAR_SHORT), + UNNAMED_OPCODE_11(GameClientProtId.UNNAMED_OPCODE_11, Prot.VAR_BYTE), + IF_BUTTON5_V2(GameClientProtId.IF_BUTTON5_V2, 9), + IF_BUTTONT_V2(GameClientProtId.IF_BUTTONT_V2, 18), + UNNAMED_OPCODE_14(GameClientProtId.UNNAMED_OPCODE_14, 15), + IF_BUTTON9_V2(GameClientProtId.IF_BUTTON9_V2, 9), + OPNPC4(GameClientProtId.OPNPC4, 3), + IF_BUTTON3_V2(GameClientProtId.IF_BUTTON3_V2, 9), + SET_CHATFILTERSETTINGS(GameClientProtId.SET_CHATFILTERSETTINGS, 3), + MOVE_MINIMAPCLICK(GameClientProtId.MOVE_MINIMAPCLICK, 18), + UNNAMED_OPCODE_20(GameClientProtId.UNNAMED_OPCODE_20, 1), + OPLOC4(GameClientProtId.OPLOC4, 9), + CLIENT_DETAILOPTIONS_STATUS(GameClientProtId.CLIENT_DETAILOPTIONS_STATUS, Prot.VAR_BYTE), + OPNPC5(GameClientProtId.OPNPC5, 3), + MOVE_SCRIPTED(GameClientProtId.MOVE_SCRIPTED, 5), + SEND_SNAPSHOT(GameClientProtId.SEND_SNAPSHOT, Prot.VAR_BYTE), + OPOBJ1_V2(GameClientProtId.OPOBJ1_V2, 8), + OPPLAYER3(GameClientProtId.OPPLAYER3, 3), + EVENT_NATIVE_MOUSE_CLICK(GameClientProtId.EVENT_NATIVE_MOUSE_CLICK, 7), + OPOBJ6_V2(GameClientProtId.OPOBJ6_V2, 8), + IF_BUTTON4_V2(GameClientProtId.IF_BUTTON4_V2, 9), + UNNAMED_OPCODE_31(GameClientProtId.UNNAMED_OPCODE_31, Prot.VAR_BYTE), + URL_REQUEST(GameClientProtId.URL_REQUEST, Prot.VAR_SHORT), + GAMELOGEVENT(GameClientProtId.GAMELOGEVENT, Prot.VAR_SHORT), + CHANGE_EMAIL_ADDRESS(GameClientProtId.CHANGE_EMAIL_ADDRESS, Prot.VAR_SHORT), + IF_BUTTON6_V2(GameClientProtId.IF_BUTTON6_V2, 9), + IF_BUTTON2_V2(GameClientProtId.IF_BUTTON2_V2, 9), + IF_BUTTON7_V2(GameClientProtId.IF_BUTTON7_V2, 9), + OPPLAYER10(GameClientProtId.OPPLAYER10, 3), + IF_PLAYER(GameClientProtId.IF_PLAYER, Prot.VAR_BYTE), + IF_BUTTOND_V2(GameClientProtId.IF_BUTTOND_V2, 18), + PING_STATISTICS(GameClientProtId.PING_STATISTICS, 4), + CREATE_SUGGEST_NAMES(GameClientProtId.CREATE_SUGGEST_NAMES, 0), + OPLOC6(GameClientProtId.OPLOC6, 9), + OPLOCT_V2(GameClientProtId.OPLOCT_V2, 18), + OPPLAYER1(GameClientProtId.OPPLAYER1, 3), + UNNAMED_OPCODE_46(GameClientProtId.UNNAMED_OPCODE_46, Prot.VAR_SHORT), + OPNPC2(GameClientProtId.OPNPC2, 3), + OPOBJT_V2(GameClientProtId.OPOBJT_V2, 17), + IF_BUTTON8_V2(GameClientProtId.IF_BUTTON8_V2, 9), + OPPLAYER6(GameClientProtId.OPPLAYER6, 3), + FRIEND_SETNOTES(GameClientProtId.FRIEND_SETNOTES, Prot.VAR_BYTE), + OPPLAYER4(GameClientProtId.OPPLAYER4, 3), + CLOSE_MODAL(GameClientProtId.CLOSE_MODAL, 0), + FRIENDLIST_DEL(GameClientProtId.FRIENDLIST_DEL, Prot.VAR_BYTE), + CHAT_SETMODE(GameClientProtId.CHAT_SETMODE, 2), + UNNAMED_OPCODE_56(GameClientProtId.UNNAMED_OPCODE_56, 18), + IF_VALUE_CHANGE_32(GameClientProtId.IF_VALUE_CHANGE_32, 11), + OPLOC2(GameClientProtId.OPLOC2, 9), + MIDI_SONG_STOP(GameClientProtId.MIDI_SONG_STOP, 4), + CREATE_LOG_PROGRESS(GameClientProtId.CREATE_LOG_PROGRESS, 1), + TRANSMITVAR_VERIFYID(GameClientProtId.TRANSMITVAR_VERIFYID, 4), + WORLDLIST_FETCH(GameClientProtId.WORLDLIST_FETCH, 4), + CLAN_JOINCHAT_LEAVECHAT(GameClientProtId.CLAN_JOINCHAT_LEAVECHAT, Prot.VAR_BYTE), + ADD_NEW_EMAIL_ADDRESS(GameClientProtId.ADD_NEW_EMAIL_ADDRESS, Prot.VAR_SHORT), + CLICKWORLDMAP(GameClientProtId.CLICKWORLDMAP, 4), + IF_BUTTON1_V2(GameClientProtId.IF_BUTTON1_V2, 9), + CREATE_CHECK_NAME(GameClientProtId.CREATE_CHECK_NAME, Prot.VAR_BYTE), + EVENT_CAMERA_POSITION(GameClientProtId.EVENT_CAMERA_POSITION, 4), + RESUME_P_HSLDIALOG(GameClientProtId.RESUME_P_HSLDIALOG, 2), + ABORT_P_DIALOG(GameClientProtId.ABORT_P_DIALOG, 0), + IF_CRMVIEW_OP(GameClientProtId.IF_CRMVIEW_OP, 22), + OPNPC3(GameClientProtId.OPNPC3, 3), + NO_TIMEOUT(GameClientProtId.NO_TIMEOUT, 0), + OPLOC3(GameClientProtId.OPLOC3, 9), + EVENT_APPLET_FOCUS(GameClientProtId.EVENT_APPLET_FOCUS, 1), + MAP_BUILD_COMPLETE(GameClientProtId.MAP_BUILD_COMPLETE, 4), + CUTSCENE2D_FINISHED(GameClientProtId.CUTSCENE2D_FINISHED, 3), + MESSAGE_PUBLIC(GameClientProtId.MESSAGE_PUBLIC, Prot.VAR_BYTE), + OPLOC1(GameClientProtId.OPLOC1, 9), + UNNAMED_BATCH_80(GameClientProtId.UNNAMED_BATCH_80, Prot.VAR_SHORT), + OPOBJ5_V2(GameClientProtId.OPOBJ5_V2, 8), + MOVE_GAMECLICK(GameClientProtId.MOVE_GAMECLICK, 5), + UNNAMED_OPCODE_83(GameClientProtId.UNNAMED_OPCODE_83, 1), + OPNPCT_V2(GameClientProtId.OPNPCT_V2, 12), + OPOBJ2_V2(GameClientProtId.OPOBJ2_V2, 8), + OPPLAYER2(GameClientProtId.OPPLAYER2, 3), + SEND_PING_REPLY(GameClientProtId.SEND_PING_REPLY, 9), + CLAN_KICKUSER(GameClientProtId.CLAN_KICKUSER, Prot.VAR_BYTE), + OPPLAYER5(GameClientProtId.OPPLAYER5, 3), + RESUME_P_LONGDIALOG(GameClientProtId.RESUME_P_LONGDIALOG, 8), + OPNPC6(GameClientProtId.OPNPC6, 3), + UNNAMED_EVENT_92(GameClientProtId.UNNAMED_EVENT_92, 14), + OPOBJ4_V2(GameClientProtId.OPOBJ4_V2, 8), + RESUME_P_CLANFORUMQFCDIALOG(GameClientProtId.RESUME_P_CLANFORUMQFCDIALOG, Prot.VAR_BYTE), + UNNAMED_OPCODE_95(GameClientProtId.UNNAMED_OPCODE_95, 1), + AFFINEDCLANSETTINGS_SETMUTED_FROMCHANNEL(GameClientProtId.AFFINEDCLANSETTINGS_SETMUTED_FROMCHANNEL, Prot.VAR_BYTE), + IGNORELIST_ADD(GameClientProtId.IGNORELIST_ADD, Prot.VAR_BYTE), + OPNPC1(GameClientProtId.OPNPC1, 3), + OPPLAYERT_V2(GameClientProtId.OPPLAYERT_V2, 12), + FRIENDLIST_ADD(GameClientProtId.FRIENDLIST_ADD, Prot.VAR_BYTE), + FRIEND_SETRANK(GameClientProtId.FRIEND_SETRANK, Prot.VAR_BYTE), + BUG_REPORT(GameClientProtId.BUG_REPORT, Prot.VAR_SHORT), + CLANCHANNEL_KICKUSER(GameClientProtId.CLANCHANNEL_KICKUSER, Prot.VAR_BYTE), + EVENT_MOUSE_CLICK(GameClientProtId.EVENT_MOUSE_CLICK, 6), + STORE_SERVERPERM_VARCS(GameClientProtId.STORE_SERVERPERM_VARCS, Prot.VAR_SHORT), + AFFINEDCLANSETTINGS_ADDBANNED_FROMCHANNEL( + GameClientProtId.AFFINEDCLANSETTINGS_ADDBANNED_FROMCHANNEL, + Prot.VAR_BYTE, + ), + CLIENT_CHEAT(GameClientProtId.CLIENT_CHEAT, Prot.VAR_BYTE), + RESUME_PAUSEBUTTON(GameClientProtId.RESUME_PAUSEBUTTON, 6), + UNNAMED_OPCODE_109(GameClientProtId.UNNAMED_OPCODE_109, 1), + UNNAMED_OPCODE_110(GameClientProtId.UNNAMED_OPCODE_110, 0), + UNNAMED_OPCODE_111(GameClientProtId.UNNAMED_OPCODE_111, 9), + EVENT_KEYBOARD(GameClientProtId.EVENT_KEYBOARD, Prot.VAR_SHORT), + IF_TEXT_CHANGE(GameClientProtId.IF_TEXT_CHANGE, Prot.VAR_SHORT), + OPPLAYER9(GameClientProtId.OPPLAYER9, 3), + UID_PASSPORT_RESEND_REQUEST(GameClientProtId.UID_PASSPORT_RESEND_REQUEST, 0), + MESSAGE_PRIVATE(GameClientProtId.MESSAGE_PRIVATE, Prot.VAR_SHORT), + RESUME_P_NAMEDIALOG(GameClientProtId.RESUME_P_NAMEDIALOG, Prot.VAR_BYTE), + MESSAGE_QUICKCHAT_PRIVATE(GameClientProtId.MESSAGE_QUICKCHAT_PRIVATE, Prot.VAR_BYTE), + OPPLAYER7(GameClientProtId.OPPLAYER7, 3), + FACE_SQUARE(GameClientProtId.FACE_SQUARE, 4), + CREATE_ACCOUNT(GameClientProtId.CREATE_ACCOUNT, Prot.VAR_SHORT), + SEND_EMAIL_VALIDATION_CODE(GameClientProtId.SEND_EMAIL_VALIDATION_CODE, Prot.VAR_BYTE), + UNNAMED_OPCODE_123(GameClientProtId.UNNAMED_OPCODE_123, 4), + RESUME_P_STRINGDIALOG(GameClientProtId.RESUME_P_STRINGDIALOG, Prot.VAR_BYTE), + IGNORELIST_DEL(GameClientProtId.IGNORELIST_DEL, Prot.VAR_BYTE), + UNNAMED_OPCODE_126(GameClientProtId.UNNAMED_OPCODE_126, 9), + OPLOC5(GameClientProtId.OPLOC5, 9), + LOCSELECT_SUBMIT(GameClientProtId.LOCSELECT_SUBMIT, 5), + UNNAMED_OPCODE_129(GameClientProtId.UNNAMED_OPCODE_129, 2), + WINDOW_STATUS(GameClientProtId.WINDOW_STATUS, 6), + APCOORDT_V2(GameClientProtId.APCOORDT_V2, 13), +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/prot/GameClientProtId.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/prot/GameClientProtId.kt new file mode 100644 index 00000000..3baa8091 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/incoming/decoder/prot/GameClientProtId.kt @@ -0,0 +1,137 @@ +package net.rsprox.protocol.rs3v950beta.game.incoming.decoder.prot + +// Verified beta senders; UNNAMED_OPCODE entries retain descriptor metadata only. +internal object GameClientProtId { + const val OPOBJ3_V2: Int = 0 + const val MESSAGE_QUICKCHAT_PUBLIC: Int = 1 + const val UNNAMED_OPCODE_2: Int = 2 + const val IGNORE_SETNOTES: Int = 3 + const val EVENT_MOUSE_MOVE: Int = 4 + const val EVENT_NATIVE_MOUSE_MOVE: Int = 5 + const val RESUME_P_OBJDIALOG: Int = 6 + const val IF_BUTTON10_V2: Int = 7 + const val RESUME_P_COUNTDIALOG: Int = 8 + const val OPPLAYER8: Int = 9 + const val CREATE_CHECK_EMAIL: Int = 10 + const val UNNAMED_OPCODE_11: Int = 11 + const val IF_BUTTON5_V2: Int = 12 + const val IF_BUTTONT_V2: Int = 13 + const val UNNAMED_OPCODE_14: Int = 14 + const val IF_BUTTON9_V2: Int = 15 + const val OPNPC4: Int = 16 + const val IF_BUTTON3_V2: Int = 17 + const val SET_CHATFILTERSETTINGS: Int = 18 + const val MOVE_MINIMAPCLICK: Int = 19 + const val UNNAMED_OPCODE_20: Int = 20 + const val OPLOC4: Int = 21 + const val CLIENT_DETAILOPTIONS_STATUS: Int = 22 + const val OPNPC5: Int = 23 + const val MOVE_SCRIPTED: Int = 24 + const val SEND_SNAPSHOT: Int = 25 + const val OPOBJ1_V2: Int = 26 + const val OPPLAYER3: Int = 27 + const val EVENT_NATIVE_MOUSE_CLICK: Int = 28 + const val OPOBJ6_V2: Int = 29 + const val IF_BUTTON4_V2: Int = 30 + const val UNNAMED_OPCODE_31: Int = 31 + const val URL_REQUEST: Int = 32 + const val GAMELOGEVENT: Int = 33 + const val CHANGE_EMAIL_ADDRESS: Int = 34 + const val IF_BUTTON6_V2: Int = 35 + const val IF_BUTTON2_V2: Int = 36 + const val IF_BUTTON7_V2: Int = 37 + const val OPPLAYER10: Int = 38 + const val IF_PLAYER: Int = 39 + const val IF_BUTTOND_V2: Int = 40 + const val PING_STATISTICS: Int = 41 + const val CREATE_SUGGEST_NAMES: Int = 42 + const val OPLOC6: Int = 43 + const val OPLOCT_V2: Int = 44 + const val OPPLAYER1: Int = 45 + const val UNNAMED_OPCODE_46: Int = 46 + const val OPNPC2: Int = 47 + const val OPOBJT_V2: Int = 48 + const val IF_BUTTON8_V2: Int = 49 + const val OPPLAYER6: Int = 50 + const val FRIEND_SETNOTES: Int = 51 + const val OPPLAYER4: Int = 52 + const val CLOSE_MODAL: Int = 53 + const val FRIENDLIST_DEL: Int = 54 + const val CHAT_SETMODE: Int = 55 + const val UNNAMED_OPCODE_56: Int = 56 + const val IF_VALUE_CHANGE_32: Int = 57 + const val OPLOC2: Int = 58 + const val MIDI_SONG_STOP: Int = 59 + const val CREATE_LOG_PROGRESS: Int = 60 + const val TRANSMITVAR_VERIFYID: Int = 61 + const val WORLDLIST_FETCH: Int = 62 + const val CLAN_JOINCHAT_LEAVECHAT: Int = 63 + const val ADD_NEW_EMAIL_ADDRESS: Int = 64 + const val CLICKWORLDMAP: Int = 65 + const val IF_BUTTON1_V2: Int = 66 + const val CREATE_CHECK_NAME: Int = 67 + const val EVENT_CAMERA_POSITION: Int = 68 + const val RESUME_P_HSLDIALOG: Int = 69 + const val ABORT_P_DIALOG: Int = 70 + const val IF_CRMVIEW_OP: Int = 71 + const val OPNPC3: Int = 72 + const val NO_TIMEOUT: Int = 73 + const val OPLOC3: Int = 74 + const val EVENT_APPLET_FOCUS: Int = 75 + const val MAP_BUILD_COMPLETE: Int = 76 + const val CUTSCENE2D_FINISHED: Int = 77 + const val MESSAGE_PUBLIC: Int = 78 + const val OPLOC1: Int = 79 + const val UNNAMED_BATCH_80: Int = 80 + const val OPOBJ5_V2: Int = 81 + const val MOVE_GAMECLICK: Int = 82 + const val UNNAMED_OPCODE_83: Int = 83 + const val OPNPCT_V2: Int = 84 + const val OPOBJ2_V2: Int = 85 + const val OPPLAYER2: Int = 86 + const val SEND_PING_REPLY: Int = 87 + const val CLAN_KICKUSER: Int = 88 + const val OPPLAYER5: Int = 89 + const val RESUME_P_LONGDIALOG: Int = 90 + const val OPNPC6: Int = 91 + const val UNNAMED_EVENT_92: Int = 92 + const val OPOBJ4_V2: Int = 93 + const val RESUME_P_CLANFORUMQFCDIALOG: Int = 94 + const val UNNAMED_OPCODE_95: Int = 95 + const val AFFINEDCLANSETTINGS_SETMUTED_FROMCHANNEL: Int = 96 + const val IGNORELIST_ADD: Int = 97 + const val OPNPC1: Int = 98 + const val OPPLAYERT_V2: Int = 99 + const val FRIENDLIST_ADD: Int = 100 + const val FRIEND_SETRANK: Int = 101 + const val BUG_REPORT: Int = 102 + const val CLANCHANNEL_KICKUSER: Int = 103 + const val EVENT_MOUSE_CLICK: Int = 104 + const val STORE_SERVERPERM_VARCS: Int = 105 + const val AFFINEDCLANSETTINGS_ADDBANNED_FROMCHANNEL: Int = 106 + const val CLIENT_CHEAT: Int = 107 + const val RESUME_PAUSEBUTTON: Int = 108 + const val UNNAMED_OPCODE_109: Int = 109 + const val UNNAMED_OPCODE_110: Int = 110 + const val UNNAMED_OPCODE_111: Int = 111 + const val EVENT_KEYBOARD: Int = 112 + const val IF_TEXT_CHANGE: Int = 113 + const val OPPLAYER9: Int = 114 + const val UID_PASSPORT_RESEND_REQUEST: Int = 115 + const val MESSAGE_PRIVATE: Int = 116 + const val RESUME_P_NAMEDIALOG: Int = 117 + const val MESSAGE_QUICKCHAT_PRIVATE: Int = 118 + const val OPPLAYER7: Int = 119 + const val FACE_SQUARE: Int = 120 + const val CREATE_ACCOUNT: Int = 121 + const val SEND_EMAIL_VALIDATION_CODE: Int = 122 + const val UNNAMED_OPCODE_123: Int = 123 + const val RESUME_P_STRINGDIALOG: Int = 124 + const val IGNORELIST_DEL: Int = 125 + const val UNNAMED_OPCODE_126: Int = 126 + const val OPLOC5: Int = 127 + const val LOCSELECT_SUBMIT: Int = 128 + const val UNNAMED_OPCODE_129: Int = 129 + const val WINDOW_STATUS: Int = 130 + const val APCOORDT_V2: Int = 131 +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/NativeIsaacStringReader.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/NativeIsaacStringReader.kt new file mode 100644 index 00000000..bdea36ad --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/NativeIsaacStringReader.kt @@ -0,0 +1,20 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.crypto.cipher.StreamCipher +import net.rsprox.protocol.rs3v950beta.buffer.nativeCharacter + +/** The stream is shared with opcode decoding; each consumed byte (including NUL) draws one key. */ +internal fun JagByteBuf.readNativeIsaacString( + cipher: StreamCipher, + limit: Long, +): String = + buildString { + var count = 0L + while (count++ < limit) { + val byte = (g1() - cipher.nextInt()) and 255 + if (byte == 0) break + val character = nativeCharacter(byte) + if (character != '\u0000') append(character) + } + } diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/VariableInteger.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/VariableInteger.kt new file mode 100644 index 00000000..d8eee15c --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/VariableInteger.kt @@ -0,0 +1,15 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec + +import net.rsprot.buffer.JagByteBuf + +/** Unsigned 32-bit LEB128; deliberately not the big-endian RuneScape varint. */ +internal fun JagByteBuf.gVarIntLE(): Int { + var value = 0 + for (shift in 0..28 step 7) { + val next = g1() + require(shift != 28 || next <= 0x0F) { "Variable integer exceeds 32 bits" } + value = value or ((next and 0x7F) shl shift) + if (next and 0x80 == 0) return value + } + error("Unterminated variable integer") +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateAccountReplyDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateAccountReplyDecoder.kt new file mode 100644 index 00000000..9e14db63 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateAccountReplyDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.account.CreateAccountReply +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class CreateAccountReplyDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CREATE_ACCOUNT_REPLY + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CreateAccountReply { + val response = buffer.g1() + return CreateAccountReply( + response, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateCheckEmailReplyDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateCheckEmailReplyDecoder.kt new file mode 100644 index 00000000..bedb56d7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateCheckEmailReplyDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.account.CreateCheckEmailReply +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class CreateCheckEmailReplyDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CREATE_CHECK_EMAIL_REPLY + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CreateCheckEmailReply { + val response = buffer.g1() + return CreateCheckEmailReply( + response, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateCheckNameReplyDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateCheckNameReplyDecoder.kt new file mode 100644 index 00000000..cac43f49 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateCheckNameReplyDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.account.CreateCheckNameReply +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class CreateCheckNameReplyDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CREATE_CHECK_NAME_REPLY + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CreateCheckNameReply { + val response = buffer.g1() + return CreateCheckNameReply( + response, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateSuggestNameErrorDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateSuggestNameErrorDecoder.kt new file mode 100644 index 00000000..50e77a71 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateSuggestNameErrorDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.account.CreateSuggestNameError +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class CreateSuggestNameErrorDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CREATE_SUGGEST_NAME_ERROR + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CreateSuggestNameError { + val response = buffer.g1() + return CreateSuggestNameError( + response, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateSuggestNameReplyDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateSuggestNameReplyDecoder.kt new file mode 100644 index 00000000..aafd4bd2 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/CreateSuggestNameReplyDecoder.kt @@ -0,0 +1,20 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.account.CreateSuggestNameReply +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class CreateSuggestNameReplyDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CREATE_SUGGEST_NAME_REPLY + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CreateSuggestNameReply { + val name = buffer.gjstr() + return CreateSuggestNameReply(name) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/FriendlistLoadedDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/FriendlistLoadedDecoder.kt new file mode 100644 index 00000000..ae7a3b9b --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/FriendlistLoadedDecoder.kt @@ -0,0 +1,17 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.account.FriendlistLoaded +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class FriendlistLoadedDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.FRIENDLIST_LOADED + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): FriendlistLoaded = FriendlistLoaded +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/UpdateDobDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/UpdateDobDecoder.kt new file mode 100644 index 00000000..39215b6e --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/account/UpdateDobDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.account.UpdateDob +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateDobDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_DOB + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateDob { + val dateOfBirth = buffer.g3() shl 8 shr 8 + val verified = buffer.g1() == 1 + return UpdateDob( + dateOfBirth, + verified, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/appearance/AppearanceBodyDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/appearance/AppearanceBodyDecoder.kt new file mode 100644 index 00000000..ba40f202 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/appearance/AppearanceBodyDecoder.kt @@ -0,0 +1,115 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.appearance + +import net.rsprot.buffer.JagByteBuf +import net.rsprox.cache.api.rs3.Rs3AppearanceDefinitions +import net.rsprox.protocol.rs3.game.outgoing.model.appearance.AppearanceBody +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.extendedinfo.PlayerExtendedInfo +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.extendedinfo.PlayerExtendedInfo.Equipment + +/** Shared player, lobby and snapshot appearance body. */ +internal object AppearanceBodyDecoder { + fun decodeBody( + buffer: JagByteBuf, + definitions: Rs3AppearanceDefinitions, + ): AppearanceBody { + var npc: Int? = null + var npcTeam: Int? = null + val equipment = + buildList { + for ((slot, kind) in definitions.equipmentSlotKinds.withIndex()) { + if (kind == 1) continue + val value = buffer.readVarIntLE() + if (slot == 0 && value == 1) { + npc = buffer.readModel() + npcTeam = buffer.g1() + break + } + add( + when { + value == 0 -> Equipment(slot, Equipment.Kind.EMPTY, -1) + value in 2..2047 -> Equipment(slot, Equipment.Kind.KIT, value - 2) + value >= 2048 -> Equipment(slot, Equipment.Kind.ITEM, value - 2048) + else -> error("Invalid equipment value $value in slot $slot") + }, + ) + } + } + val customisations = + buildList { + if (npc == null || npc == -1) { + val mask = buffer.g2() + var bit = 0 + for ((slot, kind) in definitions.equipmentSlotKinds.withIndex()) { + if (kind != 0) continue + require(bit < 16) { "Too many customisable equipment slots" } + if (mask and (1 shl bit++) == 0) continue + val item = equipment.first { it.slot == slot } + require(item.kind == Equipment.Kind.ITEM) { "Customisation without an item in slot $slot" } + val customFlags = buffer.g1() + val definition = if (customFlags and 3 != 0) definitions.getItem(item.id) else null + + fun models( + male: List, + female: List, + ): List = + buildList { + for (index in male.indices) { + if (index == 0 || male[index] != -1 || female[index] != -1) { + add(PlayerExtendedInfo.ModelPair(index, buffer.readModel(), buffer.readModel())) + } + } + } + val body = + if (customFlags and 1 != 0) { + models(checkNotNull(definition).maleBodyModels, definition.femaleBodyModels) + } else { + emptyList() + } + val head = + if (customFlags and 2 != 0) { + models(checkNotNull(definition).maleHeadModels, definition.femaleHeadModels) + } else { + emptyList() + } + val recolours = if (customFlags and 4 != 0) buffer.palette(buffer.g2(), 4) else emptyList() + val retextures = if (customFlags and 8 != 0) buffer.palette(buffer.g1(), 2) else emptyList() + add(PlayerExtendedInfo.Customisation(slot, customFlags, body, head, recolours, retextures)) + } + require(mask ushr bit == 0) { "Customisation mask exceeds equipment slots" } + } + } + val primary = List(10) { buffer.g1() } + val secondary = List(10) { buffer.g1() } + val renderAnimationSet = buffer.g2().toShort().toInt() + return AppearanceBody(npc, npcTeam, equipment, customisations, primary, secondary, renderAnimationSet) + } + + private fun JagByteBuf.readModel(): Int = + if (buffer.getByte(buffer.readerIndex()) < 0) { + g4() and Int.MAX_VALUE + } else { + g2().let { if (it == 32767) -1 else it } + } + + private fun JagByteBuf.readVarIntLE(): Int { + var value = 0 + for (index in 0..4) { + val next = g1() + require(index != 4 || next <= 15) { "Equipment varint exceeds 32 bits" } + value = value or ((next and 127) shl (index * 7)) + if (next and 128 == 0) return value + } + error("Unterminated equipment varint") + } + + private fun JagByteBuf.palette( + packed: Int, + count: Int, + ): List = + buildList { + repeat(count) { + val index = packed ushr (it * 4) and 15 + if (index != 15) add(PlayerExtendedInfo.PaletteReplacement(index, g2())) + } + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/appearance/LobbyAppearanceDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/appearance/LobbyAppearanceDecoder.kt new file mode 100644 index 00000000..60bff9a6 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/appearance/LobbyAppearanceDecoder.kt @@ -0,0 +1,29 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.appearance + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.appearance.LobbyAppearance +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.rs3AppearanceDefinitions +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LobbyAppearanceDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOBBY_APPEARANCE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LobbyAppearance { + val appearanceFlags = buffer.g1s() + return LobbyAppearance( + appearanceFlags, + AppearanceBodyDecoder.decodeBody( + buffer, + checkNotNull(session.rs3AppearanceDefinitions) { + "RS3 appearance cache is not initialized" + }, + ), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/appearance/PlayerSnapshotDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/appearance/PlayerSnapshotDecoder.kt new file mode 100644 index 00000000..13ac1cc3 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/appearance/PlayerSnapshotDecoder.kt @@ -0,0 +1,31 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.appearance + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.appearance.PlayerSnapshot +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.rs3AppearanceDefinitions +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PlayerSnapshotDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.PLAYER_SNAPSHOT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PlayerSnapshot { + val snapshotIndex = buffer.g1() + val appearanceFlags = buffer.g1s() + return PlayerSnapshot( + snapshotIndex, + appearanceFlags, + AppearanceBodyDecoder.decodeBody( + buffer, + checkNotNull(session.rs3AppearanceDefinitions) { + "RS3 appearance cache is not initialized" + }, + ), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/Cam2EnableDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/Cam2EnableDecoder.kt new file mode 100644 index 00000000..f1f8a270 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/Cam2EnableDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.camera.Cam2Enable +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class Cam2EnableDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CAM2_ENABLE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): Cam2Enable { + val enabled = buffer.g1() == 1 + return Cam2Enable( + enabled, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamForceAngleDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamForceAngleDecoder.kt new file mode 100644 index 00000000..443840fe --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamForceAngleDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.camera.CamForceAngle +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class CamForceAngleDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CAM_FORCEANGLE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CamForceAngle { + val angle0 = buffer.g2Alt1() + val angle1 = buffer.g2Alt3() + return CamForceAngle( + angle0, + angle1, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamLookAtDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamLookAtDecoder.kt new file mode 100644 index 00000000..3eb8ac36 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamLookAtDecoder.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.camera.CamLookAt +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class CamLookAtDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CAM_LOOKAT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CamLookAt { + val height = buffer.g2() + val localZ = buffer.g1Alt3() + val localX = buffer.g1() + val speed = buffer.g1() + val accel = buffer.g1Alt1() + return CamLookAt( + localX, + localZ, + height, + speed, + accel, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamMoveToDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamMoveToDecoder.kt new file mode 100644 index 00000000..00b09e59 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamMoveToDecoder.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.camera.CamMoveTo +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class CamMoveToDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CAM_MOVETO + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CamMoveTo { + val localX = buffer.g1() + val speed = buffer.g1Alt1() + val accel = buffer.g1Alt2() + val localZ = buffer.g1() + val height = buffer.g2Alt3() + return CamMoveTo( + localX, + localZ, + height, + speed, + accel, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamRemoveRoofDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamRemoveRoofDecoder.kt new file mode 100644 index 00000000..5a6608c5 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamRemoveRoofDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.camera.CamRemoveRoof +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class CamRemoveRoofDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CAM_REMOVEROOF + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CamRemoveRoof { + val coordinate = buffer.g4Alt2() + return CamRemoveRoof( + coordinate, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamResetDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamResetDecoder.kt new file mode 100644 index 00000000..8c840a4b --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamResetDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprot.protocol.metadata.Consistent +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.camera.CamReset +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +@Consistent +internal class CamResetDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CAM_RESET + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CamReset { + return CamReset + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamShakeDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamShakeDecoder.kt new file mode 100644 index 00000000..ffdac624 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamShakeDecoder.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.camera.CamShake +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class CamShakeDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CAM_SHAKE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CamShake { + val duration = buffer.g2Alt1() + val axis = buffer.g1Alt3() + val randomAmplitude = buffer.g1() + val sineAmplitude = buffer.g1Alt2() + val frequency = buffer.g1() + return CamShake( + axis, + randomAmplitude, + sineAmplitude, + duration, + frequency, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamSmoothResetDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamSmoothResetDecoder.kt new file mode 100644 index 00000000..84467f82 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CamSmoothResetDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprot.protocol.metadata.Consistent +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.camera.CamSmoothReset +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +@Consistent +internal class CamSmoothResetDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CAM_SMOOTHRESET + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CamSmoothReset { + return CamSmoothReset + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CameraUpdateDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CameraUpdateDecoder.kt new file mode 100644 index 00000000..08d1217d --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/camera/CameraUpdateDecoder.kt @@ -0,0 +1,145 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.camera.CameraUpdate +import net.rsprox.protocol.rs3.game.outgoing.model.camera.CameraUpdate.Controller +import net.rsprox.protocol.rs3.game.outgoing.model.camera.CameraUpdate.EffectPayload +import net.rsprox.protocol.rs3.game.outgoing.model.camera.CameraUpdate.Setting +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session +import net.rsprox.protocol.session.attribute + +internal class CameraUpdateDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CAMERA_UPDATE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): CameraUpdate { + val previous = session.cameraState ?: State() + var lookReader = previous.lookReader + var positionReader = previous.positionReader + val effects = previous.effects.toMutableMap() + val flags = buffer.g1() + val lookMode = if (flags and 8 != 0) buffer.g1() else null + val positionMode = if (flags and 16 != 0) buffer.g1() else null + // Unknown mode IDs retain the previous native reader object. + if (lookMode != null && lookMode in 0..6) lookReader = lookMode + if (positionMode != null && positionMode in 0..4) positionReader = positionMode + val mask = if (flags and 128 != 0) buffer.g2() else null + val settings = + buildList { + if (mask != null) { + for (bit in 0..14) { + if (mask and (1 shl bit) == 0) continue + add(readSetting(buffer, bit, effects)) + } + } + } + val look = if (flags and 32 != 0 && lookReader != null) readController(buffer, lookReader, false) else null + val position = + if (flags and 64 != 0 && positionReader != null) readController(buffer, positionReader, true) else null + require(buffer.readableBytes() == 0) { "CAMERA_UPDATE has ${buffer.readableBytes()} unexpected bytes" } + // Failed/truncated packets must not poison the next packet's state, nor another session. + session.cameraState = State(lookReader, positionReader, effects) + return CameraUpdate(flags, lookMode, positionMode, mask, settings, look, position) + } + + private fun readSetting( + buffer: JagByteBuf, + bit: Int, + effects: MutableMap, + ): Setting = + when (bit) { + in 0..3 -> Setting.Vector(bit, vector(buffer)) + 4, 5 -> Setting.Pair(bit, float(buffer), float(buffer)) + 6, 8, 11 -> Setting.ByteValue(bit, buffer.g1()) + 7 -> Setting.Reserved(buffer.g4()) + 9 -> Setting.Effects(List(buffer.g1()) { readEffect(buffer, effects) }) + 10 -> Setting.ShortFloat(buffer.g2(), float(buffer)) + 12 -> Setting.Motion(vector(buffer), vector(buffer), float(buffer), float(buffer)) + 13, 14 -> Setting.FloatValue(bit, float(buffer)) + else -> error("Unexpected camera setting bit $bit") + } + + private fun readEffect( + buffer: JagByteBuf, + effects: MutableMap, + ): CameraUpdate.EffectUpdate { + val operation = buffer.g1() + val id = buffer.g1() + if (operation == 0) { + effects.remove(id) + return CameraUpdate.EffectUpdate(operation, id, null, null, null) + } + val suppliedSubtype = buffer.g1() + val subtype = effects[id] ?: suppliedSubtype + val payload = + when (subtype) { + 0 -> EffectPayload.Axis(buffer.g1(), float(buffer), float(buffer)) + 1 -> EffectPayload.Scalar(float(buffer)) + else -> null + } + if (payload != null) effects[id] = subtype + return CameraUpdate.EffectUpdate(operation, id, suppliedSubtype, subtype, payload) + } + + private fun readController( + buffer: JagByteBuf, + mode: Int, + position: Boolean, + ): Controller = + when { + mode == 0 -> Controller.Coordinate(vector(buffer)) + mode == 1 && position -> + Controller.ActorPosition( + targetKind = buffer.g1(), + targetIndex = buffer.g2(), + offset = vector(buffer), + rotation = quaternion(buffer), + enabled = buffer.g1() == 1, + parameter = buffer.g2(), + duration = buffer.g2(), + ) + mode == 1 -> Controller.ActorLook(buffer.g1(), buffer.g2(), vector(buffer), buffer.g1() == 1) + !position && mode == 3 -> Controller.Rotation(quaternion(buffer)) + !position && mode == 5 -> Controller.Path(spline(buffer)) + else -> { + val subtype = if (position) mode - 1 else mode / 2 + val entries = List(buffer.g1()) { CameraUpdate.PathEntry(spline(buffer), float(buffer)) } + val parameters = + if (subtype == 1) { + emptyList() + } else { + List(entries.size) { List(if (subtype == 2) 3 else 2) { float(buffer) } } + } + Controller.Paths(subtype, entries, parameters) + } + } + + private fun spline(buffer: JagByteBuf): CameraUpdate.Spline { + val count = buffer.gSmart1or2() + val points = List(maxOf(count, 2)) { CameraUpdate.SplinePoint(vector(buffer), vector(buffer), float(buffer)) } + return CameraUpdate.Spline(count, points) + } + + private fun vector(buffer: JagByteBuf): CameraUpdate.Vector3 = + CameraUpdate.Vector3(float(buffer), float(buffer), float(buffer)) + + private fun quaternion(buffer: JagByteBuf): CameraUpdate.Quaternion = + CameraUpdate.Quaternion(float(buffer), float(buffer), float(buffer), float(buffer)) + + private fun float(buffer: JagByteBuf): Float = Float.fromBits(buffer.g4()) + + private data class State( + val lookReader: Int? = null, + val positionReader: Int? = null, + val effects: Map = emptyMap(), + ) + + private companion object { + var Session.cameraState: State? by attribute() + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanChannelDeltaDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanChannelDeltaDecoder.kt new file mode 100644 index 00000000..31e07a9e --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanChannelDeltaDecoder.kt @@ -0,0 +1,69 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.clan + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.clan.ClanChannelDelta +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ClanChannelDeltaDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLANCHANNEL_DELTA + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ClanChannelDelta { + val channelIndex = buffer.g1s() + val discardedKey = buffer.g8() + val updateNumber = buffer.g8() + val records = mutableListOf() + var terminator: Int + while (true) { + val type = buffer.g1() + terminator = type + val record = + when (type) { + 1 -> { + val sentinel = buffer.g1() + if (sentinel != 255) { + ClanChannelDelta.Rejected(type, sentinel) + } else { + val name = buffer.readNativeString() + val world = buffer.g2() + val rank = buffer.g1s() + val memberIdentity = buffer.g8() + ClanChannelDelta.Add(name, world, rank, memberIdentity) + } + } + 3 -> { + val index = buffer.g2() + val auxiliary = buffer.g1() + val sentinel = buffer.g1() + ClanChannelDelta.Remove(index, auxiliary, sentinel) + } + 4 -> { + val name = buffer.readNativeString() + val headerBoolean = buffer.g1() == 1 + val kickRank = buffer.g1s() + val talkRank = buffer.g1s() + ClanChannelDelta.Header(name, headerBoolean, kickRank, talkRank) + } + 5 -> { + val unused = buffer.g1() + val index = buffer.g2() + val rank = buffer.g1s() + val world = buffer.g2() + val memberIdentity = buffer.g8() + val name = buffer.readNativeString() + val memberBoolean = buffer.g1() == 1 + ClanChannelDelta.Member(unused, index, rank, world, memberIdentity, name, memberBoolean) + } + else -> break + } + records += record + } + return ClanChannelDelta(channelIndex, discardedKey, updateNumber, records, terminator) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanChannelFullDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanChannelFullDecoder.kt new file mode 100644 index 00000000..17ae304c --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanChannelFullDecoder.kt @@ -0,0 +1,55 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.clan + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.clan.ClanChannelFull +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ClanChannelFullDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLANCHANNEL_FULL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ClanChannelFull { + val channelIndex = buffer.g1s() + if (!buffer.isReadable) return ClanChannelFull(channelIndex, null) + val flags = buffer.g1() + val version = if (flags and 4 != 0) buffer.g1() else 2 + val discardedKey = buffer.g8() + val updateNumber = buffer.g8() + val name = buffer.readNativeString() + val headerBoolean = buffer.g1() == 1 + val talkRank = buffer.g1s() + val kickRank = buffer.g1s() + val count = buffer.g2() + val minimumMemberSize = if (version > 2) 5 else 4 + require(count <= buffer.readableBytes() / minimumMemberSize) { "Truncated clan-channel members" } + // Native always transmits names, without the optional hashes used by other clients. + val members = + List(count) { + val memberName = buffer.readNativeString() + val rank = buffer.g1s() + val world = buffer.g2() + val memberBoolean = if (version > 2) buffer.g1() == 1 else null + ClanChannelFull.Member(memberName, rank, world, memberBoolean) + } + return ClanChannelFull( + channelIndex, + ClanChannelFull.Channel( + flags, + version, + discardedKey, + updateNumber, + name, + headerBoolean, + talkRank, + kickRank, + members, + ), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanSettingsDeltaDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanSettingsDeltaDecoder.kt new file mode 100644 index 00000000..d18fc18a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanSettingsDeltaDecoder.kt @@ -0,0 +1,61 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.clan + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.clan.ClanSettingsDelta +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ClanSettingsDeltaDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLANSETTINGS_DELTA + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ClanSettingsDelta { + val channelIndex = buffer.g1s() + val discardedKey = buffer.g8() + val revision = buffer.g4() + val records = mutableListOf() + var terminator: Int + while (true) { + val type = buffer.g1() + terminator = type + val record = + when (type) { + 1, 3, 13 -> { + val sentinel = buffer.g1() + if (sentinel != 255) { + ClanSettingsDelta.Rejected(type, sentinel) + } else { + val name = buffer.readNativeString() + val joinedDay = if (type == 13) buffer.g2() else null + ClanSettingsDelta.AddName(type, name, joinedDay) + } + } + 2 -> ClanSettingsDelta.Rank(buffer.g2(), buffer.g1s()) + 4 -> { + val allowGuests = buffer.g1() == 1 + val rank0 = buffer.g1s() + val rank1 = buffer.g1s() + val rank2 = buffer.g1s() + val headerBoolean = buffer.g1() == 1 + ClanSettingsDelta.Permissions(allowGuests, rank0, rank1, rank2, headerBoolean) + } + 5, 6 -> ClanSettingsDelta.Remove(type, buffer.g2()) + 7 -> ClanSettingsDelta.MemberBits(buffer.g2(), buffer.g4(), buffer.g1(), buffer.g1()) + 8 -> ClanSettingsDelta.IntParameter(buffer.g4(), buffer.g4()) + 9 -> ClanSettingsDelta.LongParameter(buffer.g4(), buffer.g8()) + 10 -> ClanSettingsDelta.StringParameter(buffer.g4(), buffer.readNativeString()) + 11 -> ClanSettingsDelta.IntBits(buffer.g4(), buffer.g4(), buffer.g1(), buffer.g1()) + 12 -> ClanSettingsDelta.Name(buffer.readNativeString(), buffer.g4()) + 14 -> ClanSettingsDelta.Mute(buffer.g2(), buffer.g1() == 1) + else -> break + } + records += record + } + return ClanSettingsDelta(channelIndex, discardedKey, revision, records, terminator) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanSettingsFullDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanSettingsFullDecoder.kt new file mode 100644 index 00000000..2e29f6ea --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/clan/ClanSettingsFullDecoder.kt @@ -0,0 +1,87 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.clan + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.clan.ClanSettingsFull +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ClanSettingsFullDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLANSETTINGS_FULL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ClanSettingsFull { + val channelIndex = buffer.g1s() + if (!buffer.isReadable) return ClanSettingsFull(channelIndex, null) + val version = buffer.g1() + require(version in 1..6) { "Unsupported clan-settings version $version" } + val flags = buffer.g1() + require(flags and 3 == 2) { "Unsupported clan-settings name/hash flags $flags" } + val updateNumber = buffer.g4() + val legacyTimestamp = buffer.g4() + val memberCount = buffer.g2() + val bannedCount = buffer.g1() + val name = buffer.readNativeString() + val extra = if (version >= 4) buffer.g4() else null + val allowGuests = buffer.g1() == 1 + val rank0 = buffer.g1s() + val rank1 = buffer.g1s() + val rank2 = buffer.g1s() + val headerBoolean = buffer.g1() == 1 + val minimumMemberSize = + 2 + (if (version >= 2) 4 else 0) + + (if (version >= 5) 2 else 0) + (if (version >= 6) 1 else 0) + require(memberCount <= buffer.readableBytes() / minimumMemberSize) { "Truncated clan-settings members" } + val members = + List(memberCount) { + val memberName = buffer.readNativeString() + val rank = buffer.g1s() + val bits = if (version >= 2) buffer.g4() else null + val joinedDay = if (version >= 5) buffer.g2() else null + val muted = if (version >= 6) buffer.g1() == 1 else null + ClanSettingsFull.Member(memberName, rank, bits, joinedDay, muted) + } + require(bannedCount <= buffer.readableBytes()) { "Truncated clan-settings banned names" } + val banned = List(bannedCount) { buffer.readNativeString() } + val parameters = + if (version >= 3) { + val count = buffer.g2() + require(count <= buffer.readableBytes() / 4) { "Truncated clan-settings parameters" } + List(count) { + val keyAndType = buffer.g4() + val key = keyAndType and 0x3FFF_FFFF + when (keyAndType ushr 30) { + 0 -> ClanSettingsFull.IntParameter(key, buffer.g4()) + 1 -> ClanSettingsFull.LongParameter(key, buffer.g8()) + 2 -> ClanSettingsFull.StringParameter(key, buffer.readNativeString()) + else -> ClanSettingsFull.NullParameter(key) + } + } + } else { + emptyList() + } + return ClanSettingsFull( + channelIndex, + ClanSettingsFull.Settings( + version, + flags, + updateNumber, + legacyTimestamp, + name, + extra, + allowGuests, + rank0, + rank1, + rank2, + headerBoolean, + members, + banned, + parameters, + ), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/debug/DbFilterDebugDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/debug/DbFilterDebugDecoder.kt new file mode 100644 index 00000000..df17aa1f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/debug/DbFilterDebugDecoder.kt @@ -0,0 +1,114 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.debug + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.debug.DbFilterDebug +import net.rsprox.protocol.rs3.game.outgoing.model.debug.DbFilterDebug.Filter +import net.rsprox.protocol.rs3.game.outgoing.model.debug.DbFilterDebug.RowSet +import net.rsprox.protocol.rs3.game.outgoing.model.debug.DbFilterDebug.Value +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class DbFilterDebugDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.DBFILTER_DEBUG + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): DbFilterDebug { + val version = buffer.g1() + val titleMarker = buffer.g1() + val title = if (titleMarker == 0) buffer.readNativeString() else null + return DbFilterDebug(version, titleMarker, title, readFilter(buffer, 0)) + } + + private fun readFilter( + buffer: JagByteBuf, + depth: Int, + ): Filter { + require(depth < 128) { "DB filter nesting exceeds the proxy safety limit (128)" } + return when (val type = buffer.gSmart1or2()) { + 1 -> { + val rows = readRows(buffer) + val version = buffer.g1() + val valueType = buffer.gSmart1or2() + val value = readValue(buffer, valueType) + Filter.CompareRows(rows, version, valueType, value, buffer.gSmart1or2()) + } + 2 -> Filter.Unary(buffer.g1(), readFilter(buffer, depth + 1)) + 3, 4 -> { + val version = buffer.g1() + val first = readChildren(buffer, depth) + val second = readChildren(buffer, depth) + Filter.Compound(type, version, first, second) + } + 5, 6 -> { + val version = buffer.g1() + val valueType = buffer.gSmart1or2() + val fieldId = buffer.g4() + val operator = buffer.gSmart1or2() + val operandVersion = buffer.g1() + if (type == 5) { + Filter.CompareField( + version, + valueType, + fieldId, + operator, + operandVersion, + readValue(buffer, valueType), + ) + } else { + Filter.CompareFieldInteger(version, valueType, fieldId, operator, operandVersion, buffer.g4()) + } + } + 7 -> { + val rows = readRows(buffer) + val version = buffer.g1() + val valueType = buffer.gSmart1or2() + val count = buffer.gSmart1or2() + require(count <= buffer.readableBytes()) { "Truncated DB value set" } + Filter.ValueSet(rows, version, valueType, List(count) { readValue(buffer, valueType) }) + } + 8 -> { + val version = buffer.g1() + val flags = buffer.g1() + val value = buffer.g4() + val marker = buffer.g1() + Filter.Text(version, flags, value, marker, if (marker == 0) buffer.readNativeString() else null) + } + else -> error("Unsupported DB filter wire type $type") + } + } + + private fun readChildren( + buffer: JagByteBuf, + depth: Int, + ): List { + val count = buffer.gSmart1or2() + require(count <= buffer.readableBytes() / 2) { "Truncated DB child list" } + return List(count) { readFilter(buffer, depth + 1) } + } + + private fun readRows(buffer: JagByteBuf): RowSet { + val version = buffer.g1() + val tableId = buffer.g4() + val count = buffer.g4() + require(count == -1 || count in 0..buffer.readableBytes() / 4) { "Invalid DB row count $count" } + // Preserve transmitted duplicates; native set insertion is a consumer effect, not a wire transformation. + return RowSet(version, tableId, if (count == -1) null else List(count) { buffer.g4() }) + } + + private fun readValue( + buffer: JagByteBuf, + type: Int, + ): Value = + when (type) { + 0 -> Value.IntegerValue(buffer.g4()) + 1 -> Value.LongValue(buffer.g8()) + 2 -> Value.StringValue(buffer.readNativeString()) + 3 -> Value.Coordinate(buffer.g1(), buffer.g4(), buffer.g4(), buffer.g4()) + else -> error("Unsupported DB value type $type") + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupDeltaDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupDeltaDecoder.kt new file mode 100644 index 00000000..16558f52 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupDeltaDecoder.kt @@ -0,0 +1,82 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.group + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.cache.api.rs3.Rs3VariableDomain +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.group.PlayerGroupDelta +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.cache.readTypedVariable +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PlayerGroupDeltaDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.PLAYER_GROUP_DELTA + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PlayerGroupDelta { + val discardedKey = buffer.g8() + val revision = buffer.g4() + val records = mutableListOf() + var terminator: Int + while (true) { + val type = buffer.g1() + terminator = type + val record = + when (type) { + 1 -> { + val sentinel = buffer.g1() + if (sentinel == 255) { + PlayerGroupDelta.AddMember(buffer.readPlayerGroupMember(true, session)) + } else { + PlayerGroupDelta.Rejected(type, sentinel) + } + } + 2 -> PlayerGroupDelta.RemoveMember(buffer.g2()) + 3 -> { + val sentinel = buffer.g1() + if (sentinel == 255) { + PlayerGroupDelta.AddBanned(buffer.readNativeString()) + } else { + PlayerGroupDelta.Rejected(type, sentinel) + } + } + 4 -> PlayerGroupDelta.RemoveBanned(buffer.g2()) + 5 -> PlayerGroupDelta.MemberByte35(buffer.g2(), buffer.g1()) + 6 -> PlayerGroupDelta.MemberWorld(buffer.g2(), buffer.g2()) + 7 -> PlayerGroupDelta.MemberOffline(buffer.g2()) + 8 -> PlayerGroupDelta.MemberState(buffer.g2(), buffer.g1()) + 9 -> PlayerGroupDelta.AllMembersState2 + 10 -> PlayerGroupDelta.AllMembersState3 + 11 -> { + val memberIndex = buffer.g2() + PlayerGroupDelta.UpdateMember( + memberIndex, + buffer.readPlayerGroupMember(false, session), + ) + } + 12 -> { + val id = buffer.g2() + if (id == 65535) { + PlayerGroupDelta.NoVariable + } else { + PlayerGroupDelta.Variable( + buffer.readTypedVariable(session, Rs3VariableDomain.PLAYER_GROUP, id), + ) + } + } + 13 -> { + // Revision 950 has a three-byte varbit ID, not the older two-byte encoding. + val id = buffer.g3() + PlayerGroupDelta.Varbit(id, if (id == 16777215) null else buffer.g4()) + } + 14 -> PlayerGroupDelta.MemberByte3c(buffer.g2(), buffer.g1()) + else -> break + } + records += record + } + return PlayerGroupDelta(discardedKey, revision, records, terminator) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupFullDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupFullDecoder.kt new file mode 100644 index 00000000..f063932d --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupFullDecoder.kt @@ -0,0 +1,58 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.group + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.cache.api.rs3.Rs3VariableDomain +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.group.PlayerGroupFull +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.cache.readTypedVariable +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PlayerGroupFullDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.PLAYER_GROUP_FULL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PlayerGroupFull { + if (buffer.readableBytes() == 0) return PlayerGroupFull(null, null) + val version = buffer.g1() + if (version > 1) return PlayerGroupFull(version, null) + val flags = buffer.g1() + val revision = buffer.g4() + val groupKey = buffer.g8() + val groupName = buffer.readNativeString() + val groupWord22 = buffer.g2() + val groupInt98 = buffer.g4() + val groupLongA0 = buffer.g8() + val memberCount = buffer.g2() + require(memberCount <= buffer.readableBytes() / 9) { "Truncated player-group members" } + val members = + List(memberCount) { + buffer.readPlayerGroupMember(flags and 4 != 0, session) + } + val bannedCount = buffer.g2() + require(bannedCount <= buffer.readableBytes()) { "Truncated player-group banned names" } + val bannedNames = List(bannedCount) { buffer.readNativeString() } + val variableCount = buffer.g2() + require(variableCount <= buffer.readableBytes() / 3) { "Truncated group variables" } + val variables = List(variableCount) { buffer.readTypedVariable(session, Rs3VariableDomain.PLAYER_GROUP) } + return PlayerGroupFull( + version, + PlayerGroupFull.Group( + flags, + revision, + groupKey, + groupName, + groupWord22, + groupInt98, + groupLongA0, + members, + bannedNames, + variables, + ), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupMemberReader.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupMemberReader.kt new file mode 100644 index 00000000..7257b92d --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupMemberReader.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.group + +import net.rsprot.buffer.JagByteBuf +import net.rsprox.cache.api.rs3.Rs3VariableDomain +import net.rsprox.protocol.rs3.game.outgoing.model.group.PlayerGroupMember +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.cache.readTypedVariable +import net.rsprox.protocol.session.Session + +internal fun JagByteBuf.readPlayerGroupMember( + named: Boolean, + session: Session, +): PlayerGroupMember { + val name = if (named) readNativeString() else null + val flags = g1() + val skillCount = g1() + require(skillCount <= readableBytes() / 4) { "Truncated player-group skills" } + // TODO Cache skill definitions gate native acceptance; retain all transmitted XP without guessing a maximum. + val experience = List(skillCount) { g4() } + val variableCount = g2() + require(variableCount <= readableBytes() / 3) { "Truncated member variables" } + val variables = List(variableCount) { readTypedVariable(session, Rs3VariableDomain.PLAYER) } + return PlayerGroupMember(name, flags, experience, variables, g2(), g1(), g1(), g1()) +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupVarpsDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupVarpsDecoder.kt new file mode 100644 index 00000000..ee00cad7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/group/PlayerGroupVarpsDecoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.group + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.cache.api.rs3.Rs3VariableDomain +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.group.PlayerGroupVarps +import net.rsprox.protocol.rs3v950beta.cache.readTypedVariable +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PlayerGroupVarpsDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.PLAYER_GROUP_VARPS + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PlayerGroupVarps { + val member = buffer.g2() + val clear = buffer.g1() + val variables = + buildList { + while (buffer.isReadable) add(buffer.readTypedVariable(session, Rs3VariableDomain.PLAYER)) + } + return PlayerGroupVarps(member, clear, variables) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/SpotanimRemovals.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/SpotanimRemovals.kt new file mode 100644 index 00000000..d95373f5 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/SpotanimRemovals.kt @@ -0,0 +1,15 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info + +import net.rsprot.buffer.JagByteBuf + +internal fun JagByteBuf.readSpotanimRemovals(): List = + buildList { + val count = g1() + for (index in 0 until count) { + val id = g2().toShort().toInt() + add(id) + // Note: native 950 player/NPC masks end the removal list at -1, even before count. + // The next byte is the addition count; do not consume the remaining advertised entries. + if (id == -1) break + } + } diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/npcinfo/NpcExtendedInfoDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/npcinfo/NpcExtendedInfoDecoder.kt new file mode 100644 index 00000000..5483e409 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/npcinfo/NpcExtendedInfoDecoder.kt @@ -0,0 +1,408 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo + +import net.rsprot.buffer.JagByteBuf +import net.rsprox.cache.api.rs3.Rs3PacketDefinitions +import net.rsprox.protocol.rs3.common.TypedVariable +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.extendedinfo.NpcExtendedInfo +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.extendedinfo.NpcMask +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.extendedinfo.UnusedExtendedInfo +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.ATTACHMENTS +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.BAS_OVERRIDE +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.BODY_CUSTOMISATION +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.COMBAT_LEVEL_CHANGE +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.DISABLED_OPS +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.EXACT_MOVE +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.FACE_ENTITY +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.FACE_TILE +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.HEADICON_CUSTOMISATION +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.HEAD_CUSTOMISATION +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.HITMARKS_AND_HEADBARS_V1 +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.HITMARKS_AND_HEADBARS_V2 +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.NAME_CHANGE +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.NPC_STATS +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.OVERLAP_CULLING +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.PRIORITY_OFFSET +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.SAY +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.SEQUENCE +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.SPOTANIM +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.TINTING +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.TRANSFORMATION +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.VARNPC_DELTA +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey.VARNPC_FULL +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.readSpotanimRemovals + +/** Revision-950 beta wire bits/order, mapped to revision-independent semantic keys. */ +internal object NpcExtendedInfoDecoder { + private val routes = + listOf( + 0 to FACE_ENTITY, + 7 to VARNPC_FULL, + 30 to ATTACHMENTS, + 4 to null, + 1 to SAY, + 25 to null, + 6 to DISABLED_OPS, + 16 to null, + 13 to null, + 33 to HITMARKS_AND_HEADBARS_V2, + 3 to FACE_TILE, + 15 to HEADICON_CUSTOMISATION, + 28 to NPC_STATS, + 2 to TINTING, + 8 to COMBAT_LEVEL_CHANGE, + 12 to null, + 27 to SEQUENCE, + 22 to null, + 21 to BODY_CUSTOMISATION, + 23 to SPOTANIM, + 9 to null, + 29 to EXACT_MOVE, + 34 to BAS_OVERRIDE, + 17 to HEAD_CUSTOMISATION, + 19 to HITMARKS_AND_HEADBARS_V1, + 14 to NAME_CHANGE, + 24 to PRIORITY_OFFSET, + 10 to VARNPC_DELTA, + 32 to TRANSFORMATION, + 18 to OVERLAP_CULLING, + ) + private val continuations = intArrayOf(5, 11, 20, 31) + private val known = + (routes.map { it.first } + continuations.toList()).fold(0L) { value, bit -> + value or + (1L shl bit) + } + + fun decode( + buffer: JagByteBuf, + initialType: Int, + definitions: Rs3PacketDefinitions?, + morphVariables: NpcMorphVariables = NpcMorphVariables(), + ): List { + var mask = buffer.g1().toLong() + for ((index, bit) in continuations.withIndex()) { + if (mask and (1L shl bit) == 0L) break + mask = mask or (buffer.g1().toLong() shl ((index + 1) * 8)) + } + require(mask and known.inv() == 0L) { "Unknown NPC mask bits: ${mask.toString(16)}" } + var type = initialType + return buildList { + for ((bit, key) in routes) { + if (mask and (1L shl bit) == 0L) continue + if (key == null) { + // Note(revision): these beta blocks have no established live-950 identity. + val fields = + when (bit) { + 4 -> listOf(buffer.g2Alt1(), buffer.g4(), buffer.g1()) + 25 -> listOf(buffer.g2Alt2(), buffer.g4(), buffer.g1Alt3()) + 16 -> listOf(buffer.g1Alt2(), buffer.g2(), buffer.g2(), buffer.g2Alt2()) + 13 -> listOf(buffer.g2Alt1(), buffer.g4Alt1(), buffer.g1Alt2()) + 12 -> listOf(buffer.g1(), buffer.g1Alt3(), buffer.g2()) + 22 -> listOf(buffer.g2Alt2(), buffer.g4Alt2(), buffer.g1Alt1()) + 9 -> listOf(buffer.g2Alt1(), buffer.g4Alt3(), buffer.g1()) + else -> error("Unregistered discarded NPC mask $bit") + } + add(UnusedExtendedInfo(bit, fields)) + continue + } + + fun scalars(vararg values: Int) = NpcMask.Scalars(key, values.toList()) + val value = + when (key) { + SAY, NAME_CHANGE -> NpcMask.Text(key, buffer.readNativeString()) + PRIORITY_OFFSET -> { + // Native -128 clears the override; zero is an explicit priority offset. + val offset = buffer.g1Alt1().toByte().toInt() + NpcMask.PriorityOffset(offset.takeUnless { it == -128 }) + } + BAS_OVERRIDE -> NpcMask.BasOverride(buffer.g2Alt1().takeUnless { it == 65535 }) + HEAD_CUSTOMISATION -> customisation(buffer, key, type, definitions, morphVariables, false) + OVERLAP_CULLING -> NpcMask.OverlapCulling(buffer.g1Alt3() == 1) + TINTING -> + scalars( + buffer.g1(), + buffer.g1Alt1(), + buffer.g1(), + buffer.g1Alt2(), + buffer.g2(), + buffer.g2Alt1(), + ) + TRANSFORMATION -> { + type = buffer.model() + NpcMask.Transformation(type) + } + EXACT_MOVE -> + NpcMask.ExactMove( + deltaX1 = buffer.g1Alt3().toByte().toInt(), + deltaZ1 = buffer.g1Alt2().toByte().toInt(), + deltaX2 = buffer.g1Alt3().toByte().toInt(), + deltaZ2 = buffer.g1().toByte().toInt(), + deltaLevel1 = buffer.g1().toByte().toInt(), + deltaLevel2 = buffer.g1Alt1().toByte().toInt(), + delay1 = buffer.g2Alt3(), + delay2 = buffer.g2Alt3(), + angle = buffer.g2Alt2(), + ) + VARNPC_FULL, VARNPC_DELTA -> variables(buffer, key) + NPC_STATS -> + NpcMask.Stats( + List(buffer.g1()) { + NpcMask.Stat(buffer.g1Alt1(), buffer.g4(), buffer.g3Alt1()) + }, + ) + FACE_ENTITY -> NpcMask.FaceEntity(buffer.g3Alt1()) + FACE_TILE -> scalars(buffer.g2Alt1(), buffer.g2Alt3()) + ATTACHMENTS -> attachments(buffer) + BODY_CUSTOMISATION -> customisation(buffer, key, type, definitions, morphVariables, true) + SPOTANIM -> { + val removals = buffer.readSpotanimRemovals() + val additions = + List(buffer.g1()) { + NpcMask.Spotanim( + buffer.g1Alt2(), + buffer.g2Alt2(), + buffer.g4(), + buffer.g1Alt3(), + buffer.g3(), + ) + } + NpcMask.Spotanims(removals, additions) + } + HITMARKS_AND_HEADBARS_V2, HITMARKS_AND_HEADBARS_V1 -> + hits( + buffer, + key == HITMARKS_AND_HEADBARS_V2, + ) + COMBAT_LEVEL_CHANGE -> scalars(buffer.g2Alt1()) + SEQUENCE -> NpcMask.Sequence(List(4) { buffer.model() }, buffer.g1Alt3()) + HEADICON_CUSTOMISATION -> { + val presence = buffer.g1Alt1() + // Native expands omitted head-icon slots to -1/-1, not an unchanged-slot delta. + NpcMask.HeadIconCustomisation( + List(8) { slot -> + if (presence and (1 shl slot) != 0) { + NpcMask.HeadIcon(slot, buffer.gSmart2or4null(), buffer.gSmart1or2() - 1) + } else { + NpcMask.HeadIcon(slot, -1, -1) + } + }, + ) + } + // One replacement bitmask: set bits suppress NPC interaction options. + DISABLED_OPS -> scalars(buffer.g1Alt1()) + else -> error("Unimplemented NPC mask $key") + } + add(value) + } + } + } + + private fun variables( + buffer: JagByteBuf, + key: Rs3NpcUpdateMaskKey, + ): NpcMask.Variables { + val prefix = buffer.g2() + val variables = + List(buffer.g1()) { + val tag = buffer.g1Alt3() + val id = buffer.g2() + val value = + when (tag) { + 0 -> TypedVariable.IntValue(buffer.g4()) + 1 -> TypedVariable.LongValue(buffer.g8()) + 2 -> TypedVariable.StringValue(buffer.readNativeString()) + 3 -> TypedVariable.Coordinate(buffer.g1(), buffer.g4(), buffer.g4(), buffer.g4()) + else -> error("Unknown NPC variable tag $tag") + } + TypedVariable(id, listOf(0, 110, 36, 50)[tag], value) + } + return NpcMask.Variables(key, prefix, variables) + } + + private fun customisation( + buffer: JagByteBuf, + key: Rs3NpcUpdateMaskKey, + type: Int, + definitions: Rs3PacketDefinitions?, + morphVariables: NpcMorphVariables, + body: Boolean, + ): NpcMask.Customisation { + val flags = if (body) buffer.g1Alt3() else buffer.g1Alt2() + if (flags and 1 != 0) { + return NpcMask.Customisation(key, flags, emptyList(), emptyList(), emptyList(), emptyList()) + } + val models = + if (flags and 2 == 0) { + emptyList() + } else { + List(if (body) buffer.g1Alt2() else buffer.g1()) { + val id = buffer.model() + val transformed = body && id != -1 && flags and 16 != 0 + val scale = if (transformed) Float.fromBits(buffer.g4()) else null + val translation = if (transformed) List(3) { buffer.g2Alt3().toShort().toInt() } else emptyList() + val rotation = if (transformed) List(3) { buffer.g2Alt2().toShort().toInt() } else emptyList() + val recolours = + if (body && id != -1 && flags and 32 != 0) { + List(buffer.g1()) { buffer.g2().toShort().toInt() } + } else { + emptyList() + } + val retextures = + if (body && id != -1 && flags and 64 != 0) { + List(buffer.g1Alt1()) { buffer.g2Alt1().toShort().toInt() } + } else { + emptyList() + } + NpcMask.Model(id, scale, rotation, translation, recolours, retextures) + } + } + val definition = + if (flags and 12 != 0) { + morphVariables.resolve( + type, + checkNotNull(definitions) { "NPC palette customisation requires the live cache" }, + ) + } else { + null + } + val recolours = + if (flags and 4 == 0) { + emptyList() + } else { + List(checkNotNull(definition).recolourCount) { + if (body) buffer.g2Alt1() else buffer.g2Alt2() + } + } + val retextures = + if (flags and 8 == 0) { + emptyList() + } else { + List(checkNotNull(definition).retextureCount) { if (body) buffer.g2() else buffer.g2Alt2() } + } + val paletteIndices = if (body && flags and 128 != 0) List(10) { buffer.g1Alt3() } else emptyList() + return NpcMask.Customisation( + key, + flags, + models, + recolours, + retextures, + paletteIndices, + if (flags and 4 != 0) checkNotNull(definition).recolourSlots else emptyList(), + if (flags and 8 != 0) checkNotNull(definition).retextureSlots else emptyList(), + ) + } + + private fun hits( + buffer: JagByteBuf, + wide: Boolean, + ): NpcMask.Hits { + val hits = + List(if (wide) buffer.g1Alt3() else buffer.g1Alt1()) { + var id = buffer.gSmart1or2() + var secondary = -1 + var secondaryValue = -1 + val value = + when (id) { + 32767 -> { + id = buffer.gSmart1or2() + val first = if (wide) buffer.g4Alt2() else buffer.gSmart1or2() + secondary = buffer.gSmart1or2() + secondaryValue = if (wide) buffer.g4() else buffer.gSmart1or2() + first + } + 32766 -> { + id = -1 + if (wide) buffer.g1Alt2() else buffer.g1Alt1() + } + else -> if (wide) buffer.g4Alt2() else buffer.gSmart1or2() + } + NpcMask.Hit(id, value, secondary, secondaryValue, buffer.gSmart1or2()) + } + val bars = + List(if (wide) buffer.g1() else buffer.g1Alt1()) { + val id = buffer.gSmart1or2() + val duration = buffer.gSmart1or2() + if (duration == 32767) { + NpcMask.Headbar(id, duration, null, null, null, null, null, null) + } else { + val delay = buffer.gSmart1or2() + val startFill = if (wide) buffer.g1Alt2() else buffer.g1() + val endFill = + if (duration == 0) { + startFill + } else if (wide) { + buffer.g1Alt1() + } else { + buffer.g1Alt2() + } + val secondaryId = buffer.gSmart1or2() - 1 + val secondaryStartFill = + if (secondaryId == -1) { + null + } else if (wide) { + buffer.g1() + } else { + buffer.g1Alt1() + } + val secondaryEndFill = + if (secondaryId == -1) { + null + } else if (duration == 0) { + secondaryStartFill + } else { + if (wide) buffer.g1Alt3() else buffer.g1Alt2() + } + NpcMask.Headbar( + id, + duration, + delay, + startFill, + endFill, + secondaryId.takeIf { it != -1 }, + secondaryStartFill, + secondaryEndFill, + ) + } + } + return NpcMask.Hits(wide, hits, bars) + } + + private fun attachments(buffer: JagByteBuf): NpcMask.Attachments { + val count = buffer.g1Alt3().toByte().toInt() + val attachments = + List(count.coerceAtLeast(0)) { + val flags = buffer.g2Alt3().toShort().toInt() + val slot = buffer.g2Alt3().toShort().toInt() + val id = if (flags and 0xc00 != 0) buffer.g4() else null + val translation = + listOf( + if (flags and 1 != 0) buffer.g4Alt3() else null, + if (flags and 2 != 0) buffer.g4Alt2() else null, + if (flags and 4 != 0) buffer.g4Alt3() else null, + ) + val rotation = + listOf( + if (flags and 8 != 0) buffer.g4() else null, + if (flags and 16 != 0) buffer.g4Alt3() else null, + if (flags and 32 != 0) buffer.g4Alt3() else null, + ) + val scale = + listOf( + if (flags and 128 != 0) buffer.g4Alt2() else null, + if (flags and 256 != 0) buffer.g4Alt1() else null, + if (flags and 512 != 0) buffer.g4Alt1() else null, + ) + NpcMask.Attachment(flags, slot, id, translation, rotation, scale) + } + return NpcMask.Attachments(count, attachments) + } + + private fun JagByteBuf.model(): Int = + if (buffer.getByte(buffer.readerIndex()) < 0) { + g4() and Int.MAX_VALUE + } else { + g2().let { if (it == 32767) -1 else it } + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/npcinfo/NpcInfoClient.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/npcinfo/NpcInfoClient.kt new file mode 100644 index 00000000..248f674b --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/npcinfo/NpcInfoClient.kt @@ -0,0 +1,187 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.buffer.bitbuffer.BitBuf +import net.rsprot.buffer.bitbuffer.toBitBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.cache.api.rs3.Rs3PacketDefinitions +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.common.CoordGrid +import net.rsprox.protocol.rs3.cache.rs3PacketDefinitions +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.NpcInfo +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.NpcUpdateType +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.extendedinfo.NpcMask +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo.localPlayerCoordinate +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session +import net.rsprox.protocol.session.attribute + +private var Session.npcInfo: NpcInfoState? by attribute() +private var Session.npcCoordinateBits: Int? by attribute() + +internal fun Session.initializeNpcInfo( + coordinateBits: Int, + initial: Boolean, +) { + require(coordinateBits in 1..31) { "Unsupported NPC coordinate width $coordinateBits" } + npcCoordinateBits = coordinateBits + if (initial) npcInfo = NpcInfoState() +} + +/** The repository holds this stateless adapter; actor history belongs to the connection. */ +public class NpcInfoClient : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.NPC_INFO_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): NpcInfo = + checkNotNull(session.npcInfo) { "NPC_INFO_V2 requires the initial rebuild" }.decode( + buffer, + session.localPlayerCoordinate(), + checkNotNull(session.npcCoordinateBits), + session.rs3PacketDefinitions, + session.npcMorphVariables(), + ) +} + +/** Decode transactionally; a rejected relative frame requires a fresh initial rebuild. */ +internal class NpcInfoState { + private data class Npc( + val id: Int, + val coord: CoordGrid, + ) + + private var synchronized = true + private var active = linkedMapOf() + + fun decode( + buffer: JagByteBuf, + base: CoordGrid, + coordinateBits: Int, + definitions: Rs3PacketDefinitions?, + variables: NpcMorphVariables = NpcMorphVariables(), + ): NpcInfo { + check(synchronized) { "NPC_INFO_V2 state lost after a failed frame; a fresh login/rebuild is required" } + try { + val next = linkedMapOf() + val updates = linkedMapOf() + val masks = mutableListOf() + val previous = active.entries.toList() + buffer.buffer.toBitBuf().use { bits -> + val count = bits.read(8) + require(count <= previous.size) { "NPC count $count exceeds previous count ${previous.size}" } + for (position in count until previous.size) updates[previous[position].key] = NpcUpdateType.Remove + for (position in 0 until count) { + val (index, npc) = previous[position] + if (bits.read(1) == 0) { + next[index] = npc + updates[index] = NpcUpdateType.Idle + continue + } + val kind = bits.read(2) + if (kind == 3) { + updates[index] = NpcUpdateType.Remove + continue + } + var first: Int? = null + var second: Int? = null + val movement = + when (kind) { + 0 -> NpcUpdateType.MovementType.EXT_ONLY + 1 -> { + first = bits.read(3) + NpcUpdateType.MovementType.WALK + } + else -> { + val run = bits.read(1) != 0 + first = bits.read(3) + if (run) second = bits.read(3) + if (run) NpcUpdateType.MovementType.RUN else NpcUpdateType.MovementType.CRAWL + } + } + if (kind == 0 || bits.read(1) != 0) masks += index + var coord = npc.coord + first?.let { coord = step(coord, it) } + second?.let { coord = step(coord, it) } + next[index] = npc.copy(coord = coord) + updates[index] = + NpcUpdateType.Active( + movement, + first, + second, + coord.level, + coord.x, + coord.z, + emptyList(), + ) + } + while (bits.readableBits() >= 16) { + val index = bits.read(16) + if (index == 65535) break + require(index !in next) { "Duplicate NPC index $index" } + val direction = bits.read(3) + val x = bits.signed(coordinateBits) + val hasMask = bits.read(1) != 0 + val level = bits.read(2) + val teleport = bits.read(1) != 0 + val z = bits.signed(coordinateBits) + val id = bits.read(16) + val coord = CoordGrid(level, base.x + x, base.z + z) + next[index] = Npc(id, coord) + updates[index] = + NpcUpdateType.Add( + id, + x, + z, + level, + coord.x, + coord.z, + direction, + emptyList(), + teleport, + ) + if (hasMask) masks += index + } + } + for (index in masks) { + // Native advances by two bytes; this is NOT a payload-length field. + buffer.g2() + val npc = next.getValue(index) + val extendedInfo = NpcExtendedInfoDecoder.decode(buffer, npc.id, definitions, variables) + val morph = extendedInfo.filterIsInstance().lastOrNull() + if (morph != null) next[index] = npc.copy(id = morph.id) + updates[index] = + when (val update = updates.getValue(index)) { + is NpcUpdateType.Active -> update.copy(extendedInfo = extendedInfo) + is NpcUpdateType.Add -> update.copy(extendedInfo = extendedInfo) + else -> error("NPC mask without an update for $index") + } + } + require(buffer.readableBytes() == 0) { "NPC_INFO_V2 has ${buffer.readableBytes()} trailing bytes" } + active = next + return NpcInfo(updates) + } catch (exception: Exception) { + synchronized = false + throw exception + } + } + + private fun step( + coord: CoordGrid, + direction: Int, + ): CoordGrid = CoordGrid(coord.level, coord.x + DX[direction], coord.z + DZ[direction]) + + private fun BitBuf.read(count: Int): Int { + require(isReadable(count)) { "Truncated NPC bit block" } + return gBits(count) + } + + private fun BitBuf.signed(count: Int): Int = read(count) shl (32 - count) shr (32 - count) + + private companion object { + // Native 0x24a300: N, NE, E, SE, S, SW, W, NW (not the OSRS table). + val DX = intArrayOf(0, 1, 1, 1, 0, -1, -1, -1) + val DZ = intArrayOf(1, 1, 0, -1, -1, -1, 0, 1) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/npcinfo/NpcMorphVariables.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/npcinfo/NpcMorphVariables.kt new file mode 100644 index 00000000..8a788611 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/npcinfo/NpcMorphVariables.kt @@ -0,0 +1,92 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo + +import net.rsprox.cache.api.rs3.Rs3NpcDefinition +import net.rsprox.cache.api.rs3.Rs3PacketDefinitions +import net.rsprox.cache.api.rs3.Rs3VariableDomain +import net.rsprox.protocol.rs3.cache.rs3PacketDefinitions +import net.rsprox.protocol.session.Session +import net.rsprox.protocol.session.attribute + +private var Session.npcMorphVariables: NpcMorphVariables? by attribute() + +internal fun Session.npcMorphVariables(): NpcMorphVariables = + npcMorphVariables ?: NpcMorphVariables().also { npcMorphVariables = it } + +/** + * Server-visible player variables, not NPC-local config parameters. + * Beta variable handlers update client+0x19b80. Client-script overrides/timed + * synchronization are not observable from packets and are not simulated here. + */ +internal class NpcMorphVariables { + private val values = mutableMapOf() + + fun clear() { + values.clear() + } + + fun set( + id: Int, + value: Int, + ) { + values[id] = value + } + + fun setBit( + id: Int, + value: Int, + definitions: Rs3PacketDefinitions, + ) { + val bit = definitions.getVarbit(id) + if (bit.domain != 0) return + // All revision-950 NPC selectors are integer (script type 0). Other domains/types + // still decode normally; they are not inputs to this NPC-specific state. + if (definitions.getVariable(Rs3VariableDomain.PLAYER, bit.base).scriptType != 0) return + require(bit.endBit < 32) { "NPC morph variable requires an integer player varbit: $id" } + val mask = (1 shl (bit.endBit - bit.startBit + 1)) - 1 + // Native 0xa52d10 leaves the old value unchanged for an out-of-range update. + if (value < 0 || value.toLong() > (mask.toLong() and 0xffffffffL)) return + val old = get(bit.base, definitions) + values[bit.base] = (old and (mask shl bit.startBit).inv()) or (value shl bit.startBit) + } + + private fun get( + id: Int, + definitions: Rs3PacketDefinitions, + ): Int { + values[id]?.let { return it } + val definition = definitions.getVariable(Rs3VariableDomain.PLAYER, id) + check( + definition.scriptType == 0, + ) { "Uninitialized NPC morph selector $id has script type ${definition.scriptType}" } + return 0 + } + + fun resolve( + type: Int, + definitions: Rs3PacketDefinitions, + ): Rs3NpcDefinition { + val base = definitions.getNpc(type) + val morph = base.morph ?: return base + val selector = + when { + morph.varbit != -1 -> { + val bit = definitions.getVarbit(morph.varbit) + require(bit.domain == 0 && bit.endBit < 32) { "NPC morph uses non-player varbit ${morph.varbit}" } + (get(bit.base, definitions) ushr bit.startBit) and ((1 shl (bit.endBit - bit.startBit + 1)) - 1) + } + morph.varp != -1 -> get(morph.varp, definitions) + else -> -1 + } + val selected = if (selector in 0 until morph.types.lastIndex) morph.types[selector] else morph.types.last() + // One lookup, not recursive morph resolution. Beta NPC-info integration is pending. + return if (selected == -1) Rs3NpcDefinition(0, 0) else definitions.getNpc(selected) + } +} + +internal fun Session.updateNpcMorphVarbit( + id: Int, + value: Int, +) { + val definitions = rs3PacketDefinitions ?: return + npcMorphVariables().setBit(id, value, definitions) +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerAppearanceDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerAppearanceDecoder.kt new file mode 100644 index 00000000..b6a3ba94 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerAppearanceDecoder.kt @@ -0,0 +1,81 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo + +import io.netty.buffer.Unpooled +import net.rsprot.buffer.JagByteBuf +import net.rsprot.buffer.extensions.toJagByteBuf +import net.rsprox.cache.api.rs3.Rs3AppearanceDefinitions +import net.rsprox.protocol.rs3.game.outgoing.model.appearance.AppearanceBody +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.extendedinfo.PlayerExtendedInfo +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.appearance.AppearanceBodyDecoder + +/** Native shared appearance grammar plus the player-profile prefix/footer. */ +internal object PlayerAppearanceDecoder { + fun decode( + bytes: ByteArray, + definitions: Rs3AppearanceDefinitions, + ): PlayerExtendedInfo.Appearance { + val storage = Unpooled.wrappedBuffer(bytes) + try { + val buffer = storage.toJagByteBuf() + val flags = buffer.g1() + val title = if (flags and 0x40 != 0) buffer.gSmart1or2() else null + val icons = + if (flags and 2 != 0) { + List(buffer.g1()) { PlayerExtendedInfo.NameIcon(buffer.g2(), buffer.g1()) } + } else { + emptyList() + } + val visibility = buffer.g1().toByte().toInt() + val appearance = decodeBody(buffer, definitions) + val name = buffer.readNativeString() + val combat = buffer.g1() + val skillLevel = if (flags and 4 != 0) buffer.g2().let { if (it == 65535) -1 else it } else null + val effectiveCombat = if (flags and 4 == 0) buffer.g1() else null + val colourParameter = if (flags and 4 == 0) buffer.g1().let { if (it == 255) -1 else it } else null + val soundRange = buffer.g1().toByte().toInt() + val backgroundSound = + if (soundRange != 0) { + // Native applies these four IDs as signed shorts; 65535 is the absent sound -1. + PlayerExtendedInfo.BackgroundSound( + range = soundRange, + stationary = buffer.g2().toShort().toInt(), + crawl = buffer.g2().toShort().toInt(), + walk = buffer.g2().toShort().toInt(), + run = buffer.g2().toShort().toInt(), + volume = buffer.g1(), + ) + } else { + null + } + require(!storage.isReadable) { "Player appearance has ${storage.readableBytes()} trailing bytes" } + return PlayerExtendedInfo.Appearance( + flags = flags, + size = (flags ushr 3 and 7) + 1, + title = title, + icons = icons, + visibility = visibility, + npc = appearance.npc, + npcTeam = appearance.npcTeam, + equipment = appearance.equipment, + customisations = appearance.customisations, + primaryColours = appearance.primaryColours, + secondaryColours = appearance.secondaryColours, + renderAnimationSet = appearance.renderAnimationSet, + name = name, + combatLevel = combat, + skillLevel = skillLevel, + effectiveCombatLevel = effectiveCombat, + combatColourParameter = colourParameter, + backgroundSound = backgroundSound, + ) + } finally { + storage.release() + } + } + + fun decodeBody( + buffer: JagByteBuf, + definitions: Rs3AppearanceDefinitions, + ): AppearanceBody = AppearanceBodyDecoder.decodeBody(buffer, definitions) +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerAttachmentMaskDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerAttachmentMaskDecoder.kt new file mode 100644 index 00000000..df750311 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerAttachmentMaskDecoder.kt @@ -0,0 +1,38 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo + +import net.rsprot.buffer.JagByteBuf +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.extendedinfo.PlayerExtendedInfo +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.extendedinfo.PlayerExtendedInfo.TransformAxes + +internal object PlayerAttachmentMaskDecoder { + fun decode(buffer: JagByteBuf): PlayerExtendedInfo.Attachments { + val count = buffer.g1Alt3().toByte().toInt() + val attachments = + List(count.coerceAtLeast(0)) { + val flags = buffer.g2().toShort().toInt() + val slot = buffer.g2Alt2().toShort().toInt() + val id = if (flags and 0xc00 != 0) buffer.g4Alt1() else null + val translation = + TransformAxes( + if (flags and 0x1 != 0) buffer.g4Alt2() else null, + if (flags and 0x2 != 0) buffer.g4Alt2() else null, + if (flags and 0x4 != 0) buffer.g4Alt1() else null, + ) + val rotation = + TransformAxes( + if (flags and 0x8 != 0) buffer.g4Alt3() else null, + if (flags and 0x10 != 0) buffer.g4Alt3() else null, + if (flags and 0x20 != 0) buffer.g4Alt3() else null, + ) + // Bit 6 rotates the translation by the supplied rotation. Scale starts at bit 7. + val scale = + TransformAxes( + if (flags and 0x80 != 0) buffer.g4Alt2() else null, + if (flags and 0x100 != 0) buffer.g4Alt2() else null, + if (flags and 0x200 != 0) buffer.g4Alt1() else null, + ) + PlayerExtendedInfo.Attachment(flags, slot, id, translation, rotation, scale) + } + return PlayerExtendedInfo.Attachments(count, attachments) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerExtendedInfoDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerExtendedInfoDecoder.kt new file mode 100644 index 00000000..7ac9057f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerExtendedInfoDecoder.kt @@ -0,0 +1,196 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo + +import io.netty.buffer.Unpooled +import net.rsprot.buffer.JagByteBuf +import net.rsprot.buffer.extensions.toJagByteBuf +import net.rsprox.cache.api.rs3.Rs3AppearanceDefinitions +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.extendedinfo.PlayerExtendedInfo +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.readSpotanimRemovals + +/** Revision-950 beta native mask order and getter selectors. */ +internal object PlayerExtendedInfoDecoder { + private val order = + intArrayOf( + 18, + 13, + 25, + 27, + 14, + 21, + 19, + 7, + 5, + 1, + 2, + 24, + 23, + 12, + 15, + 26, + 17, + 16, + 10, + 9, + 3, + 0, + 6, + 22, + ) + private val continuationBits = intArrayOf(4, 8, 20) + private val knownBits = (order.toList() + continuationBits.toList()).fold(0) { mask, bit -> mask or (1 shl bit) } + + fun decode( + buffer: JagByteBuf, + definitions: Rs3AppearanceDefinitions? = null, + ): List { + var mask = buffer.g1() + for ((byte, bit) in continuationBits.withIndex()) { + if (mask and (1 shl bit) == 0) break + mask = mask or (buffer.g1() shl ((byte + 1) * 8)) + } + require(mask and knownBits.inv() == 0) { "Unknown player mask bits: 0x${mask.toUInt().toString(16)}" } + return buildList { + for (bit in order) { + if (mask and (1 shl bit) == 0) continue + add(decodeMask(buffer, bit, definitions)) + } + } + } + + private fun decodeMask( + buffer: JagByteBuf, + bit: Int, + definitions: Rs3AppearanceDefinitions?, + ): PlayerExtendedInfo = + when (bit) { + 26 -> { + val removals = buffer.readSpotanimRemovals() + val additions = + List(buffer.g1()) { + PlayerExtendedInfo.Spotanim( + buffer.g1Alt3(), + buffer.g2Alt3(), + buffer.g4(), + buffer.g1Alt2(), + buffer.g3Alt3(), + ) + } + PlayerExtendedInfo.Spotanims(removals, additions) + } + // Note(revision): beta reads/discards these fields. Their bit numbers are not live-950 identities. + 9 -> PlayerExtendedInfo.UnusedFields(bit, listOf(buffer.g1Alt2(), buffer.g1Alt2(), buffer.g2())) + 10 -> PlayerExtendedInfo.UnusedFields(bit, listOf(buffer.g2(), buffer.g4Alt3(), buffer.g1())) + 12 -> PlayerExtendedInfo.UnusedFields(bit, listOf(buffer.g2Alt2(), buffer.g4Alt3(), buffer.g1Alt1())) + 13 -> PlayerExtendedInfo.UnusedFields(bit, listOf(buffer.g2(), buffer.g4(), buffer.g1())) + 15 -> PlayerExtendedInfo.UnusedFields(bit, listOf(buffer.g2Alt3(), buffer.g4(), buffer.g1())) + 16 -> PlayerExtendedInfo.UnusedFields(bit, listOf(buffer.g2(), buffer.g4Alt2(), buffer.g1Alt1())) + 2 -> + PlayerExtendedInfo.UnusedFields( + bit, + listOf(buffer.g1(), buffer.g2(), buffer.g2Alt3(), buffer.g2Alt1()), + ) + 18 -> PlayerExtendedInfo.Sequence(List(4) { buffer.readNullableSmart() }, buffer.g1Alt1()) + 6 -> PlayerExtendedInfo.ClanMember(buffer.g1Alt2() == 1) + 3 -> PlayerExtendedInfo.FaceEntity(buffer.g3Alt1()) + 25 -> PlayerVariableMaskDecoder.decode(buffer, full = false) + 5 -> PlayerHitMaskDecoder.decode(buffer, wide = false) + 1 -> decodeHeadIcons(buffer) + 19 -> PlayerExtendedInfo.SayV2(buffer.readNativeString(), buffer.g1() and 1 != 0) + 14 -> + PlayerExtendedInfo.ExactMove( + deltaX1 = buffer.g1().toByte().toInt(), + deltaZ1 = buffer.g1Alt3().toByte().toInt(), + deltaX2 = buffer.g1Alt2().toByte().toInt(), + deltaZ2 = buffer.g1Alt3().toByte().toInt(), + deltaLevel1 = buffer.g1().toByte().toInt(), + deltaLevel2 = buffer.g1Alt2().toByte().toInt(), + delay1 = buffer.g2Alt1(), + delay2 = buffer.g2Alt1(), + angle = buffer.g2Alt2(), + ) + 22 -> + PlayerExtendedInfo.Tinting( + hue = buffer.g1Alt3(), + saturation = buffer.g1Alt1(), + lightness = buffer.g1Alt1(), + weight = buffer.g1Alt3(), + start = buffer.g2Alt1(), + end = buffer.g2Alt3(), + ) + 21 -> PlayerVariableMaskDecoder.decode(buffer, full = true) + 24 -> PlayerHitMaskDecoder.decode(buffer, wide = true) + 23 -> PlayerAttachmentMaskDecoder.decode(buffer) + 7 -> PlayerExtendedInfo.PlayerStatus(buffer.g1Alt2()) + 27 -> PlayerExtendedInfo.SayV1(buffer.readNativeString()) + 0 -> PlayerExtendedInfo.FaceAngle(buffer.g2Alt2()) + 17 -> { + val length = buffer.g1Alt3() + require(length <= buffer.readableBytes()) { "Truncated player appearance: $length bytes required" } + val payload = ByteArray(length) + for (index in payload.indices.reversed()) payload[index] = buffer.g1().toByte() + if (definitions == null) { + PlayerExtendedInfo.UndecodedAppearance(payload) + } else { + try { + PlayerAppearanceDecoder.decode(payload, definitions) + } catch (failure: Exception) { + // The independent, length-bounded envelope is consumed exactly. A profile failure + // must be visible, but does not invalidate subsequent movement/mask framing. + PlayerExtendedInfo.UndecodedAppearance( + payload, + "${failure.javaClass.simpleName}: ${failure.message}", + ) + } + } + } + else -> error("Unregistered player mask $bit") + } + + private fun decodeHeadIcons(buffer: JagByteBuf): PlayerExtendedInfo.HeadIcons { + val length = buffer.g1Alt1() + require(length <= buffer.readableBytes()) { "Truncated player head-icon envelope" } + // The native mask skips the embedded decoder entirely for a zero-length envelope. + if (length == 0) return PlayerExtendedInfo.HeadIcons(update = false, slots = emptyList()) + val bytes = ByteArray(length) + for (index in bytes.indices) bytes[index] = buffer.g1Alt1().toByte() + val storage = Unpooled.wrappedBuffer(bytes) + try { + val inner = storage.toJagByteBuf() + val presence = inner.g1() + val slots = + buildList { + for (slot in 0..7) { + if (presence and (1 shl slot) == 0) continue + add( + PlayerExtendedInfo.HeadIcon( + slot, + inner.g1(), + inner.g2().let { if (it == 65535) -1 else it }, + inner.readSmart(), + inner.readSmart(), + inner.readSmart(), + inner.readSmart(), + ), + ) + } + } + // The native motion reader reads only the presence-selected records, not the entire blob. + // Unused tail bytes are legal inside this already-consumed, length-bounded envelope. + // Keep slot-read bounds and the enclosing PLAYER_INFO consumption check strict. + return PlayerExtendedInfo.HeadIcons(update = true, slots = slots) + } finally { + storage.release() + } + } + + private fun JagByteBuf.readSmart(): Int = + if (buffer.getByte(buffer.readerIndex()).toInt() < 0) g4() and Int.MAX_VALUE else g2() + + private fun JagByteBuf.readNullableSmart(): Int = + if (buffer.getByte(buffer.readerIndex()).toInt() < 0) { + g4() and Int.MAX_VALUE + } else { + g2().let { if (it == 32767) -1 else it } + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerHitMaskDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerHitMaskDecoder.kt new file mode 100644 index 00000000..6dbe9d76 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerHitMaskDecoder.kt @@ -0,0 +1,72 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo + +import net.rsprot.buffer.JagByteBuf +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.extendedinfo.PlayerExtendedInfo +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.extendedinfo.PlayerExtendedInfo.Headbar + +internal object PlayerHitMaskDecoder { + fun decode( + buffer: JagByteBuf, + wide: Boolean, + ): PlayerExtendedInfo.Hits { + val hitCount = buffer.g1Alt3() + val hits = + List(hitCount) { + var type = buffer.gSmart1or2() + val value: Int + var secondaryType = -1 + var secondaryValue = -1 + when (type) { + 32767 -> { + type = buffer.gSmart1or2() + value = if (wide) buffer.g4Alt3() else buffer.gSmart1or2() + secondaryType = buffer.gSmart1or2() + secondaryValue = if (wide) buffer.g4Alt3() else buffer.gSmart1or2() + } + 32766 -> { + type = -1 + value = buffer.g1Alt3() + } + else -> value = if (wide) buffer.g4Alt3() else buffer.gSmart1or2() + } + PlayerExtendedInfo.Hit(type, value, secondaryType, secondaryValue, buffer.gSmart1or2()) + } + val headbarCount = if (wide) buffer.g1Alt3() else buffer.g1Alt2() + val headbars = List(headbarCount) { readHeadbar(buffer, wide) } + return PlayerExtendedInfo.Hits(wide, hits, headbars) + } + + private fun readHeadbar( + buffer: JagByteBuf, + wide: Boolean, + ): Headbar { + val type = buffer.gSmart1or2() + val duration = buffer.gSmart1or2() + if (duration == 32767) return Headbar.Remove(type) + val delay = buffer.gSmart1or2() + val startFill = if (wide) buffer.g1Alt2() else buffer.g1() + val endFill = + if (duration == 0) { + startFill + } else { + buffer.g1Alt1() + } + val secondaryId = buffer.gSmart1or2() - 1 + val secondary = + if (secondaryId == -1) { + null + } else { + val secondaryStartFill = if (wide) buffer.g1Alt2() else buffer.g1Alt1() + val secondaryEndFill = + if (duration == 0) { + secondaryStartFill + } else if (wide) { + buffer.g1Alt1() + } else { + buffer.g1() + } + PlayerExtendedInfo.SecondaryHeadbar(secondaryId, secondaryStartFill, secondaryEndFill) + } + return Headbar.Update(type, duration, delay, startFill, endFill, secondary) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerInfoClient.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerInfoClient.kt new file mode 100644 index 00000000..8e19208b --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerInfoClient.kt @@ -0,0 +1,274 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.buffer.bitbuffer.BitBuf +import net.rsprot.buffer.bitbuffer.toBitBuf +import net.rsprox.cache.api.rs3.Rs3AppearanceDefinitions +import net.rsprox.protocol.common.CoordGrid +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.PlayerInfo +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.PlayerUpdateType +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.util.PlayerInfoInitBlock + +/** Per-connection state. Never shared by a decoder repository or committed from a failed frame. */ +internal class PlayerInfoClient( + init: PlayerInfoInitBlock, + private val appearanceDefinitions: Rs3AppearanceDefinitions? = null, +) { + private data class Player( + var highResolution: Boolean = false, + var oldSkip: Boolean = false, + var level: Int = 0, + var x: Int = 0, + var z: Int = 0, + var movementMode: Int = 0, + ) + + private val localIndex = init.localPlayerIndex + private var synchronized = true + private var players = + Array(2048) { index -> + if (index == localIndex) { + Player(true, false, init.localPlayerLevel, init.localPlayerX, init.localPlayerZ) + } else { + val packed = init.getLowResolutionPosition(index) + val mode = packed ushr 18 and 3 + Player(false, mode == 0, packed ushr 16 and 3, packed ushr 8 and 255, packed and 255, mode) + } + } + + fun localCoordinate(): CoordGrid { + check(synchronized) { "Local player position is unavailable after a failed PLAYER_INFO frame" } + val player = players[localIndex] + return CoordGrid(player.level, player.x, player.z) + } + + fun decode(buffer: JagByteBuf): PlayerInfo { + check(synchronized) { "PLAYER_INFO state lost after a failed frame; a fresh login/rebuild is required" } + val working = Array(players.size) { players[it].copy() } + try { + val frame = Frame(working) + val result = frame.decode(buffer) + players = working + return result + } catch (exception: Exception) { + // The next frame is relative to the client's NEW state, not our last successful one. + synchronized = false + throw exception + } + } + + private inner class Frame( + private val state: Array, + ) { + private val updates = linkedMapOf() + private val masks = mutableListOf() + private val nextSkip = BooleanArray(2048) + + fun decode(buffer: JagByteBuf): PlayerInfo { + // Snapshot all four cohorts before additions/removals change resolution. + val phases = listOf(true to false, true to true, false to true, false to false) + val cohorts = + phases.map { (high, skip) -> + (1..2047).filter { state[it].highResolution == high && state[it].oldSkip == skip } + } + buffer.buffer.toBitBuf().use { bits -> + for ((phase, indices) in cohorts.withIndex()) { + var cursor = 0 + while (cursor < indices.size) { + val index = indices[cursor] + if (bits.read(1) == 0) { + val width = intArrayOf(0, 5, 8, 11)[bits.read(2)] + val count = if (width == 0) 0 else bits.read(width) + require(count < indices.size - cursor) { "Player skip exceeds phase $phase" } + repeat(count + 1) { nextSkip[indices[cursor++]] = true } + } else { + if (phase < 2) existing(bits, index) else nextSkip[index] = external(bits, index) + cursor++ + } + } + bits.readerIndex((bits.readerIndex() + 7) and -8) + } + } + for (index in masks) { + // Native outer handler skips these bytes; it never treats them as a block length. + buffer.g2() + val extendedInfo = PlayerExtendedInfoDecoder.decode(buffer, appearanceDefinitions) + updates[index] = + when (val update = updates[index]) { + is PlayerUpdateType.HighResolutionIdle -> update.copy(extendedInfo = extendedInfo) + is PlayerUpdateType.LowResolutionToHighResolution -> update.copy(extendedInfo = extendedInfo) + is PlayerUpdateType.HighResolutionMovement -> update.copy(extendedInfo = extendedInfo) + else -> error("Mask without an active player update: $index") + } + } + require(buffer.readableBytes() == 0) { "PLAYER_INFO has ${buffer.readableBytes()} trailing bytes" } + for (index in 1..2047) state[index].oldSkip = nextSkip[index] + return PlayerInfo(updates) + } + + private fun existing( + bits: BitBuf, + index: Int, + ) { + val player = state[index] + val hasMasks = bits.read(1) != 0 + if (hasMasks) masks += index + when (bits.read(2)) { + 0 -> { + if (hasMasks || index == localIndex) { + updates[index] = PlayerUpdateType.HighResolutionIdle(emptyList()) + return + } + player.highResolution = false + player.x = player.x shr 6 + player.z = player.z shr 6 + updates[index] = PlayerUpdateType.HighResolutionToLowResolution(player.level, player.x, player.z) + if (bits.read(1) != 0) { + external(bits, index) + // Region-only follow-ups must not hide the removal in the transcript. + if (!player.highResolution) { + updates[index] = + PlayerUpdateType.HighResolutionToLowResolution( + player.level, + player.x, + player.z, + ) + } + } + } + 1 -> { + val direction = bits.read(3) + val extra = bits.read(1) != 0 + val steps = mutableListOf() + if (extra) { + val cardinal = bits.read(2) + steps += PlayerUpdateType.Step(player.x + CARDINAL_X[cardinal], player.z + CARDINAL_Z[cardinal]) + } + // Both native waypoints are relative to the original position, not to each other. + steps += PlayerUpdateType.Step(player.x + WALK_X[direction], player.z + WALK_Z[direction]) + move(index, false, player.level, steps, if (extra) 3 else player.movementMode) + } + 2 -> { + val direction = bits.read(4) + val step = PlayerUpdateType.Step(player.x + RUN_X[direction], player.z + RUN_Z[direction]) + move(index, false, player.level, listOf(step), player.movementMode) + } + 3 -> { + val large = bits.read(1) != 0 + val mode: Int + val level: Int + val x: Int + val z: Int + if (large) { + mode = bits.read(3) + val packed = bits.read(30) + level = (player.level + (packed ushr 28)) and 3 + x = (player.x + (packed ushr 14 and 0x3fff)) and 0x3fff + z = (player.z + (packed and 0x3fff)) and 0x3fff + } else { + val packed = bits.read(15) + mode = packed ushr 12 + level = (player.level + (packed ushr 10 and 3)) and 3 + x = player.x + ((packed ushr 5 and 31) shl 27 shr 27) + z = player.z + ((packed and 31) shl 27 shr 27) + } + val previousMode = player.movementMode + move(index, mode == 4, level, listOf(PlayerUpdateType.Step(x, z)), mode) + // Large instant teleports retain the cached mode; small ones reset it. + if (mode == 4) player.movementMode = if (large) previousMode else 0 + } + } + } + + private fun move( + index: Int, + teleport: Boolean, + level: Int, + steps: List, + mode: Int, + ) { + val player = state[index] + player.level = level + player.x = steps.last().x + player.z = steps.last().z + player.movementMode = mode + updates[index] = + PlayerUpdateType.HighResolutionMovement( + teleport, + level, + player.x, + player.z, + mode, + steps, + emptyList(), + ) + } + + private fun external( + bits: BitBuf, + index: Int, + depth: Int = 0, + ): Boolean { + require(depth < 32) { "Excessive recursive external-player updates" } + val player = state[index] + when (bits.read(2)) { + 0 -> { + if (bits.read(1) != 0) external(bits, index, depth + 1) + require(!player.highResolution) { "Duplicate player add: $index" } + val x = bits.read(6) + val z = bits.read(6) + if (bits.read(1) != 0) masks += index + player.highResolution = true + player.x = (player.x shl 6) + x + player.z = (player.z shl 6) + z + updates[index] = + PlayerUpdateType.LowResolutionToHighResolution( + player.level, + player.x, + player.z, + player.movementMode, + emptyList(), + ) + return true + } + 1 -> player.level = (player.level + bits.read(2)) and 3 + 2 -> { + val packed = bits.read(5) + player.level = (player.level + (packed ushr 3)) and 3 + // Native reads the previous regions as unsigned bytes, then stores full integer deltas. + player.x = (player.x and 255) + WALK_X[packed and 7] + player.z = (player.z and 255) + WALK_Z[packed and 7] + } + 3 -> { + val packed = bits.read(20) + player.movementMode = packed ushr 18 + player.level = (player.level + (packed ushr 16 and 3)) and 3 + player.x = (player.x + (packed ushr 8 and 255)) and 255 + player.z = (player.z + (packed and 255)) and 255 + } + } + updates[index] = + PlayerUpdateType.LowResolutionMovement( + player.level, + player.x, + player.z, + player.movementMode, + ) + return false + } + } + + private companion object { + val WALK_X = intArrayOf(-1, 0, 1, -1, 1, -1, 0, 1) + val WALK_Z = intArrayOf(-1, -1, -1, 0, 0, 1, 1, 1) + val RUN_X = intArrayOf(-2, -1, 0, 1, 2, -2, 2, -2, 2, -2, 2, -2, -1, 0, 1, 2) + val RUN_Z = intArrayOf(-2, -2, -2, -2, -2, -1, -1, 0, 0, 1, 1, 2, 2, 2, 2, 2) + val CARDINAL_X = intArrayOf(0, -1, 1, 0) + val CARDINAL_Z = intArrayOf(1, 0, 0, -1) + } +} + +private fun BitBuf.read(count: Int): Int { + require(isReadable(count)) { "Truncated player movement ($count bits required)" } + return gBits(count) +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerInfoDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerInfoDecoder.kt new file mode 100644 index 00000000..74a5f7f1 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerInfoDecoder.kt @@ -0,0 +1,58 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.buffer.bitbuffer.toBitBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.common.CoordGrid +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.PlayerInfo +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.rs3AppearanceDefinitions +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.rs3PlayerInfoInitPending +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.util.PlayerInfoInitBlock +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session +import net.rsprox.protocol.session.attribute + +private var Session.playerInfo: PlayerInfoClient? by attribute() + +internal class PlayerInfoDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.PLAYER_INFO + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PlayerInfo = + checkNotNull(session.playerInfo) { + "PLAYER_INFO requires the initial rebuild's player table" + }.decode(buffer) +} + +/** Native 0x00cd1a00, called before either initial rebuild body. Not a packet-size heuristic. */ +internal fun Session.readPlayerInfoInit( + buffer: JagByteBuf, + reconnect: Boolean = false, +): PlayerInfoInitBlock? { + if (!reconnect && rs3PlayerInfoInitPending != true) return null + require(localPlayerIndex in 1..2047) { "Invalid login player index $localPlayerIndex" } + val positions = IntArray(2048) + val local = + buffer.buffer.toBitBuf().use { bits -> + require(bits.isReadable(30 + 2046 * 20)) { "Truncated initial player table" } + val position = bits.gBits(30) + for (index in 1..2047) { + if (index != localPlayerIndex) positions[index] = bits.gBits(20) + } + position + } + return PlayerInfoInitBlock(localPlayerIndex, local ushr 28, local ushr 14 and 0x3fff, local and 0x3fff, positions) +} + +/** Commit only after the entire rebuild has decoded successfully. */ +internal fun Session.initializePlayerInfo(init: PlayerInfoInitBlock?) { + if (init == null) return + playerInfo = PlayerInfoClient(init, rs3AppearanceDefinitions) + rs3PlayerInfoInitPending = false +} + +internal fun Session.localPlayerCoordinate(): CoordGrid = + checkNotNull(playerInfo) { "Local player position requires the initial rebuild" }.localCoordinate() diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerVariableMaskDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerVariableMaskDecoder.kt new file mode 100644 index 00000000..725ae73a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/info/playerinfo/PlayerVariableMaskDecoder.kt @@ -0,0 +1,32 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo + +import net.rsprot.buffer.JagByteBuf +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.extendedinfo.PlayerExtendedInfo +import net.rsprox.protocol.rs3.game.outgoing.model.info.playerinfo.extendedinfo.PlayerExtendedInfo.VariableValue +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString + +internal object PlayerVariableMaskDecoder { + fun decode( + buffer: JagByteBuf, + full: Boolean, + ): PlayerExtendedInfo.Variables { + buffer.g2() // Native discarded prefix, not a trusted length. + val entries = + List(buffer.g1()) { + val tag = if (full) buffer.g1() else buffer.g1Alt3() + val id = buffer.g2() + // Unlike VARCLAN, these masks send their strategy tag on the wire. + // Rs3InfoVariableProof.Registry checks the client's four real vtable bindings. + val value = + when (tag) { + 0 -> VariableValue.IntegerValue(buffer.g4()) + 1 -> VariableValue.LongValue(buffer.g8()) + 2 -> VariableValue.StringValue(buffer.readNativeString()) + 3 -> VariableValue.Coordinate(buffer.g1(), buffer.g4(), buffer.g4(), buffer.g4()) + else -> error("Unsupported player variable tag $tag for id $id") + } + PlayerExtendedInfo.Variable(id, value) + } + return PlayerExtendedInfo.Variables(full, entries) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfCloseSubDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfCloseSubDecoder.kt new file mode 100644 index 00000000..ebed5123 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfCloseSubDecoder.kt @@ -0,0 +1,20 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfCloseSub +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfCloseSubDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_CLOSESUB + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfCloseSub { + val parentComponentHash = buffer.g4Alt3().toLong() and 0xFFFFFFFFL + return IfCloseSub(parentComponentHash) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfMoveSubDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfMoveSubDecoder.kt new file mode 100644 index 00000000..9c109b34 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfMoveSubDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfMoveSub +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfMoveSubDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_MOVESUB + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfMoveSub { + val source = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + val destination = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + return IfMoveSub( + destination, + source, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActiveLocDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActiveLocDecoder.kt new file mode 100644 index 00000000..4ded2b6d --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActiveLocDecoder.kt @@ -0,0 +1,44 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfOpenSubActiveLoc +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfOpenSubActiveLocDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_OPENSUB_ACTIVE_LOC + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfOpenSubActiveLoc { + val reserved0 = List(4) { buffer.g1() } + val coord = buffer.g4Alt1() + val reserved1 = List(8) { buffer.g1() } + val layer = buffer.g1Alt2() + val locId = buffer.g4Alt1() + val componentHash = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + val rawShapeRot = buffer.g1Alt3() + require(rawShapeRot and 0x80 == 0) { "Extended location transforms do not fit the fixed beta packet" } + val shape = (rawShapeRot ushr 2) and 0x1F + val rotation = rawShapeRot and 0x3 + val reserved2 = List(4) { buffer.g1() } + val childId = buffer.g2() + return IfOpenSubActiveLoc( + componentHash = componentHash, + locId = locId, + childId = childId, + layer = layer, + shape = shape, + rotation = rotation, + coord = coord, + extra1 = null, + extra2 = null, + extra3 = null, + extra4 = null, + reserved = reserved0 + reserved1 + reserved2, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActiveNpcDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActiveNpcDecoder.kt new file mode 100644 index 00000000..a579ade7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActiveNpcDecoder.kt @@ -0,0 +1,36 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfOpenSubActiveNpc +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfOpenSubActiveNpcDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_OPENSUB_ACTIVE_NPC + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfOpenSubActiveNpc { + // The native handler skips these fixed spans; preserve bytes without inventing XTEA transforms. + val layer = buffer.g1Alt3() + val reserved0 = List(12) { buffer.g1() } + val npcIndex = buffer.g2Alt1() + val componentHash = buffer.g4Alt2().toLong() and 0xFFFF_FFFFL + val reserved1 = List(4) { buffer.g1() } + val childId = buffer.g2Alt3() + return IfOpenSubActiveNpc( + legacyWord0 = null, + npcIndex = npcIndex, + childId = childId, + legacyWord1 = null, + componentHash = componentHash, + legacyWord2 = null, + legacyWord3 = null, + layer = layer, + reserved = reserved0 + reserved1, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActiveObjDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActiveObjDecoder.kt new file mode 100644 index 00000000..cbe9116b --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActiveObjDecoder.kt @@ -0,0 +1,38 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfOpenSubActiveObj +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfOpenSubActiveObjDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_OPENSUB_ACTIVE_OBJ_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfOpenSubActiveObj { + // The native handler skips these fixed spans; preserve bytes without inventing XTEA transforms. + val objId = buffer.g3Alt1() + val layer = buffer.g1Alt3() + val componentHash = buffer.g4Alt3().toLong() and 0xFFFF_FFFFL + val reserved0 = List(12) { buffer.g1() } + val coord = buffer.g4Alt2() + val reserved1 = List(4) { buffer.g1() } + val childId = buffer.g2Alt3() + return IfOpenSubActiveObj( + componentHash = componentHash, + childId = childId, + objId = objId, + layer = layer, + coord = coord, + extra1 = null, + extra2 = null, + extra3 = null, + extra4 = null, + reserved = reserved0 + reserved1, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActivePlayerDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActivePlayerDecoder.kt new file mode 100644 index 00000000..7b9a51fb --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubActivePlayerDecoder.kt @@ -0,0 +1,36 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfOpenSubActivePlayer +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfOpenSubActivePlayerDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_OPENSUB_ACTIVE_PLAYER + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfOpenSubActivePlayer { + // The native handler skips these fixed spans; preserve bytes without inventing XTEA transforms. + val reserved0 = List(8) { buffer.g1() } + val layer = buffer.g1Alt1() + val playerIndex = buffer.g2Alt3() + val componentHash = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + val reserved1 = List(8) { buffer.g1() } + val childId = buffer.g2Alt2() + return IfOpenSubActivePlayer( + legacyWord0 = null, + legacyWord1 = null, + playerIndex = playerIndex, + componentHash = componentHash, + legacyWord2 = null, + legacyWord3 = null, + childId = childId, + layer = layer, + reserved = reserved0 + reserved1, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubDecoder.kt new file mode 100644 index 00000000..88aef9c1 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenSubDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfOpenSub +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfOpenSubDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_OPENSUB + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfOpenSub { + // The native handler skips these fixed spans; preserve bytes without inventing XTEA transforms. + val reserved0 = List(4) { buffer.g1() } + val layer = buffer.g1Alt1() + val childId = buffer.g2() + val reserved1 = List(8) { buffer.g1() } + val componentHash = buffer.g4Alt2().toLong() and 0xFFFF_FFFFL + val reserved2 = List(4) { buffer.g1() } + return IfOpenSub(componentHash, childId, layer, reserved = reserved0 + reserved1 + reserved2) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenTopDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenTopDecoder.kt new file mode 100644 index 00000000..5319d5cb --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfOpenTopDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfOpenTop +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfOpenTopDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_OPENTOP + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfOpenTop { + // The native handler skips these fixed spans; preserve bytes without inventing XTEA transforms. + val interfaceId = buffer.g2Alt3() + val reserved = List(17) { buffer.g1() } + return IfOpenTop(interfaceId = interfaceId, reserved = reserved) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetAngleDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetAngleDecoder.kt new file mode 100644 index 00000000..af424817 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetAngleDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetAngle +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetAngleDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETANGLE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetAngle { + val angle1 = buffer.g2() + val angle0 = buffer.g2Alt1() + val zoom = buffer.g2Alt3() + val componentHash = buffer.g4Alt3().toLong() and 0xFFFF_FFFFL + return IfSetAngle( + zoom, + angle1, + angle0, + componentHash, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetAnimDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetAnimDecoder.kt new file mode 100644 index 00000000..9c18c744 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetAnimDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetAnim +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetAnimDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETANIM + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetAnim { + val componentHash = buffer.g4Alt2().toLong() and 0xFFFF_FFFFL + val animId = buffer.g4Alt3() + return IfSetAnim( + componentHash, + animId, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetClickMaskDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetClickMaskDecoder.kt new file mode 100644 index 00000000..16de358a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetClickMaskDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetClickMask +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetClickMaskDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETCLICKMASK + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetClickMask { + val enabled = buffer.g1Alt3() == 1 + val componentHash = buffer.g4().toLong() and 0xFFFF_FFFFL + return IfSetClickMask( + enabled, + componentHash, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetColourDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetColourDecoder.kt new file mode 100644 index 00000000..568f7885 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetColourDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetColour +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetColourDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETCOLOUR + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetColour { + val packedColor = buffer.g2Alt1() + val componentHash = buffer.g4Alt3().toLong() and 0xFFFF_FFFFL + return IfSetColour( + componentHash, + packedColor, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetEventsDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetEventsDecoder.kt new file mode 100644 index 00000000..7d7dd4e5 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetEventsDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetEvents +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetEventsDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETEVENTS + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetEvents { + val componentHash = buffer.g4Alt3().toLong() and 0xFFFF_FFFFL + val settings = buffer.g4() + val toSlot = buffer.g2Alt2().let { if (it == 65535) -1 else it } + val fromSlot = buffer.g2Alt2().let { if (it == 65535) -1 else it } + return IfSetEvents( + componentHash, + fromSlot, + toSlot, + settings, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetGraphicDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetGraphicDecoder.kt new file mode 100644 index 00000000..a61f6ed6 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetGraphicDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetGraphic +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetGraphicDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETGRAPHIC + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetGraphic { + val graphicId = buffer.g4() + val componentHash = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + return IfSetGraphic( + componentHash, + graphicId, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetHideDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetHideDecoder.kt new file mode 100644 index 00000000..2686ced6 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetHideDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetHide +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetHideDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETHIDE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetHide { + val componentHash = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + val hidden = buffer.g1Alt2() == 1 + return IfSetHide( + componentHash, + hidden, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetHttpImageDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetHttpImageDecoder.kt new file mode 100644 index 00000000..34eb4cc4 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetHttpImageDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetHttpImage +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetHttpImageDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SET_HTTP_IMAGE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetHttpImage { + val imageId = buffer.g4Alt1() + val componentHash = buffer.g4Alt2().toLong() and 0xFFFF_FFFFL + return IfSetHttpImage( + componentHash, + imageId, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetModelDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetModelDecoder.kt new file mode 100644 index 00000000..7a737069 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetModelDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetModel +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetModelDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETMODEL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetModel { + val modelId = buffer.g4Alt1() + val componentHash = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + return IfSetModel( + componentHash, + modelId, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetNpcHeadDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetNpcHeadDecoder.kt new file mode 100644 index 00000000..85d90882 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetNpcHeadDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetNpcHead +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetNpcHeadDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETNPCHEAD + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetNpcHead { + val npcId = buffer.g4Alt1() + val componentHash = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + return IfSetNpcHead( + componentHash, + npcId, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetObjectDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetObjectDecoder.kt new file mode 100644 index 00000000..8431e89e --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetObjectDecoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetObject +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetObjectDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETOBJECT_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetObject { + val componentHash = buffer.g4Alt1().toLong() and 0xFFFFFFFFL + val rawObjId = buffer.g3Alt3() + val count = buffer.g4Alt3() + val objId = if (rawObjId == 0xFFFFFF) -1 else rawObjId + return IfSetObject( + componentHash, + objId, + count, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetObjectLongV2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetObjectLongV2Decoder.kt new file mode 100644 index 00000000..66ee4510 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetObjectLongV2Decoder.kt @@ -0,0 +1,29 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetObjectLongV2 +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetObjectLongV2Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETOBJECT_LONG_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetObjectLongV2 { + val rawObjId = buffer.g3Alt1() + val objId = if (rawObjId == 0xFFFFFF) -1 else rawObjId + val quantityHigh = buffer.g4Alt2().toLong() + val quantityLow = buffer.g4Alt2().toLong() and 0xFFFF_FFFFL + val quantity = (quantityHigh shl 32) or quantityLow + val componentHash = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + return IfSetObjectLongV2( + quantity, + componentHash, + objId, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadDecoder.kt new file mode 100644 index 00000000..00a4bea8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetPlayerHead +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetPlayerHeadDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETPLAYERHEAD + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetPlayerHead { + val componentHash = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + return IfSetPlayerHead( + componentHash, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadIgnoreWornDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadIgnoreWornDecoder.kt new file mode 100644 index 00000000..343c9043 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadIgnoreWornDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetPlayerHeadIgnoreWorn +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetPlayerHeadIgnoreWornDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETPLAYERHEAD_IGNOREWORN + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetPlayerHeadIgnoreWorn { + val kitExtra = buffer.g2Alt2() + val kitHigh = buffer.g2Alt1() + val kitLow = buffer.g2Alt2() + val componentHash = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + return IfSetPlayerHeadIgnoreWorn( + kitLow, + kitExtra, + kitHigh, + componentHash, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadOtherDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadOtherDecoder.kt new file mode 100644 index 00000000..2a319233 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadOtherDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetPlayerHeadOther +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetPlayerHeadOtherDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETPLAYERHEAD_OTHER + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetPlayerHeadOther { + val componentHash = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + val playerIndex = buffer.g2Alt2() + val appearanceHash = buffer.g4() + return IfSetPlayerHeadOther( + appearanceHash, + componentHash, + playerIndex, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadSnapshotDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadSnapshotDecoder.kt new file mode 100644 index 00000000..222ef7ae --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerHeadSnapshotDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetPlayerHeadSnapshot +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetPlayerHeadSnapshotDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETPLAYERHEAD_SNAPSHOT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetPlayerHeadSnapshot { + val componentHash = buffer.g4().toLong() and 0xFFFF_FFFFL + val snapshotSlot = buffer.g1Alt1() + return IfSetPlayerHeadSnapshot( + componentHash, + snapshotSlot, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerModelOtherDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerModelOtherDecoder.kt new file mode 100644 index 00000000..951b60e8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerModelOtherDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetPlayerModelOther +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetPlayerModelOtherDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETPLAYERMODEL_OTHER + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetPlayerModelOther { + val appearanceHash = buffer.g4Alt2() + val playerIndex = buffer.g2Alt2() + val componentHash = buffer.g4Alt3().toLong() and 0xFFFF_FFFFL + return IfSetPlayerModelOther( + appearanceHash, + playerIndex, + componentHash, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerModelSelfDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerModelSelfDecoder.kt new file mode 100644 index 00000000..281bead3 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerModelSelfDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetPlayerModelSelf +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetPlayerModelSelfDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETPLAYERMODEL_SELF + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetPlayerModelSelf { + val componentHash = buffer.g4Alt1().toLong() and 0xFFFF_FFFFL + return IfSetPlayerModelSelf( + componentHash, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerModelSnapshotDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerModelSnapshotDecoder.kt new file mode 100644 index 00000000..8feae067 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPlayerModelSnapshotDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetPlayerModelSnapshot +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetPlayerModelSnapshotDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETPLAYERMODEL_SNAPSHOT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetPlayerModelSnapshot { + val snapshotSlot = buffer.g1() + val componentHash = buffer.g4().toLong() and 0xFFFF_FFFFL + return IfSetPlayerModelSnapshot( + componentHash, + snapshotSlot, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPositionDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPositionDecoder.kt new file mode 100644 index 00000000..fcd5b78f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetPositionDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetPosition +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetPositionDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETPOSITION + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetPosition { + val x = buffer.g2s() + val componentHash = buffer.g4Alt3().toLong() and 0xFFFF_FFFFL + val y = buffer.g2sAlt3() + return IfSetPosition( + componentHash, + x, + y, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetRecolDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetRecolDecoder.kt new file mode 100644 index 00000000..43e621de --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetRecolDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetRecol +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetRecolDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETRECOL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetRecol { + val source = buffer.g2Alt2() + val componentHash = buffer.g4Alt2().toLong() and 0xFFFF_FFFFL + val index = buffer.g1Alt3() + val destination = buffer.g2Alt1() + return IfSetRecol(index, componentHash, destination, source) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetRetexDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetRetexDecoder.kt new file mode 100644 index 00000000..166623ce --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetRetexDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetRetex +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetRetexDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETRETEX + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetRetex { + val componentHash = buffer.g4Alt2().toLong() and 0xFFFF_FFFFL + val destination = buffer.g2() + val index = buffer.g1Alt3() + val source = buffer.g2Alt3() + return IfSetRetex(destination, index, source, componentHash) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetScrollPosDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetScrollPosDecoder.kt new file mode 100644 index 00000000..dacf274e --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetScrollPosDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetScrollPos +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetScrollPosDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETSCROLLPOS + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetScrollPos { + val scrollPos = buffer.g2Alt1() + val componentHash = buffer.g4Alt3().toLong() and 0xFFFF_FFFFL + return IfSetScrollPos( + componentHash, + scrollPos, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTargetParamDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTargetParamDecoder.kt new file mode 100644 index 00000000..54ef4bb1 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTargetParamDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetTargetParam +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetTargetParamDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETTARGETPARAM + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetTargetParam { + val fromSlot = buffer.g2Alt3().let { if (it == 65535) -1 else it } + val toSlot = buffer.g2Alt3().let { if (it == 65535) -1 else it } + val componentHash = buffer.g4Alt3().toLong() and 0xFFFF_FFFFL + val targetParam = buffer.g2Alt3() + return IfSetTargetParam( + componentHash, + targetParam, + fromSlot, + toSlot, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTextAntiMacroDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTextAntiMacroDecoder.kt new file mode 100644 index 00000000..c614cdb5 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTextAntiMacroDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetTextAntiMacro +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetTextAntiMacroDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETTEXTANTIMACRO + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetTextAntiMacro { + val enabled = buffer.g1Alt2() == 1 + val componentHash = buffer.g4Alt3().toLong() and 0xFFFF_FFFFL + return IfSetTextAntiMacro( + componentHash, + enabled, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTextDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTextDecoder.kt new file mode 100644 index 00000000..bf3bbd69 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTextDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetText +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetTextDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETTEXT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetText { + val text = buffer.gjstr() + val componentHash = buffer.g4Alt3().toLong() and 0xFFFFFFFFL + return IfSetText( + componentHash, + text, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTextFontDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTextFontDecoder.kt new file mode 100644 index 00000000..273eea6b --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/interfaces/IfSetTextFontDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.interfaces.IfSetTextFont +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class IfSetTextFontDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.IF_SETTEXTFONT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): IfSetTextFont { + val componentHash = buffer.g4().toLong() and 0xFFFF_FFFFL + val fontId = buffer.g4Alt2() + return IfSetTextFont( + componentHash, + fontId, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/inv/UpdateInvFullDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/inv/UpdateInvFullDecoder.kt new file mode 100644 index 00000000..df63c0f5 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/inv/UpdateInvFullDecoder.kt @@ -0,0 +1,52 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.inv + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.inv.UpdateInvFull +import net.rsprox.protocol.rs3.game.outgoing.model.inv.util.InvVar +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateInvFullDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_INV_FULL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateInvFull { + val inventoryId = buffer.g2() + val flags = buffer.g1() + val hasVars = (flags and 0x2) != 0 + val slotCount = buffer.g2() + val objs = + buildList { + for (slot in 0 until slotCount) { + val rawObjId = buffer.g3() + var amount = buffer.g1() + if (amount == 0xFF) { + amount = buffer.g4() + } + val vars = + if (hasVars) { + val varCount = buffer.g1() + buildList { + for (v in 0 until varCount) { + val varId = buffer.g2() + val varVal = buffer.g4() + add(InvVar(varId, varVal)) + } + } + } else { + emptyList() + } + add(UpdateInvFull.Obj(rawObjId - 1, amount, vars)) + } + } + return UpdateInvFull( + inventoryId, + flags, + objs, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/inv/UpdateInvPartialDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/inv/UpdateInvPartialDecoder.kt new file mode 100644 index 00000000..0bda9ec8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/inv/UpdateInvPartialDecoder.kt @@ -0,0 +1,56 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.inv + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.inv.UpdateInvPartial +import net.rsprox.protocol.rs3.game.outgoing.model.inv.util.InvVar +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateInvPartialDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_INV_PARTIAL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateInvPartial { + val inventoryId = buffer.g2() + val flags = buffer.g1() + val hasVars = (flags and 0x2) != 0 + val objs = + buildList { + while (buffer.isReadable) { + val slot = buffer.gSmart1or2() + val rawObjId = buffer.g3() + if (rawObjId == 0) { + add(UpdateInvPartial.IndexedObj(slot, -1, 0, emptyList())) + continue + } + var amount = buffer.g1() + if (amount == 0xFF) { + amount = buffer.g4() + } + val vars = + if (hasVars) { + val varCount = buffer.g1() + buildList { + for (v in 0 until varCount) { + val varId = buffer.g2() + val varVal = buffer.g4() + add(InvVar(varId, varVal)) + } + } + } else { + emptyList() + } + add(UpdateInvPartial.IndexedObj(slot, rawObjId - 1, amount, vars)) + } + } + return UpdateInvPartial( + inventoryId, + flags, + objs, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/inv/UpdateInvStopTransmitDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/inv/UpdateInvStopTransmitDecoder.kt new file mode 100644 index 00000000..28342ed3 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/inv/UpdateInvStopTransmitDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.inv + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.inv.UpdateInvStopTransmit +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateInvStopTransmitDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_INV_STOP_TRANSMIT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateInvStopTransmit { + // Only bit zero is consumed natively; all byte variants agree on that bit. + val flags = buffer.g1() + val inventoryId = buffer.g2Alt2() + return UpdateInvStopTransmit( + inventoryId, + flags, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/EnvironmentOverrideDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/EnvironmentOverrideDecoder.kt new file mode 100644 index 00000000..e73682e3 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/EnvironmentOverrideDecoder.kt @@ -0,0 +1,42 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.map.EnvironmentOverride +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class EnvironmentOverrideDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.ENVIRONMENT_OVERRIDE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): EnvironmentOverride { + val flags = buffer.g8() + val fields = mutableListOf() + // Native wire order differs from numeric flag order at bits 45 and 46. + val order = (0..5) + listOf(45, 46) + (6..44) + 47 + for (bit in order) { + if (flags and (1L shl bit) == 0L) continue + fields += + when (bit) { + 0, 6, 20, 21, 27, 43, 44 -> EnvironmentOverride.IntegerValue(bit, buffer.g4()) + 7, 15 -> EnvironmentOverride.WordValue(bit, buffer.g2()) + 16 -> EnvironmentOverride.WordReserved(bit, buffer.g2(), List(8) { buffer.g1() }) + 17, 18, 19 -> EnvironmentOverride.WordScalar(bit, buffer.g2(), Float.fromBits(buffer.g4())) + 4, 32, 33, 34 -> + EnvironmentOverride.VectorValue( + bit, + Float.fromBits(buffer.g4()), + Float.fromBits(buffer.g4()), + Float.fromBits(buffer.g4()), + ) + else -> EnvironmentOverride.ScalarValue(bit, Float.fromBits(buffer.g4())) + } + } + val duration = buffer.g2() + return EnvironmentOverride(flags, fields, duration) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/RebuildNormalDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/RebuildNormalDecoder.kt new file mode 100644 index 00000000..bb219cca --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/RebuildNormalDecoder.kt @@ -0,0 +1,47 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.map.RebuildNormal +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo.initializeNpcInfo +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo.initializePlayerInfo +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo.readPlayerInfoInit +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class RebuildNormalDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.REBUILD_NORMAL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): RebuildNormal { + val init = session.readPlayerInfoInit(buffer) + val npcCoordinateBits = buffer.g1() + val unused0 = buffer.g1() + val baseChunkZ = buffer.g2Alt2() + val unused1 = buffer.g1() + val baseChunkX = buffer.g2Alt2() + val format = buffer.g1() + val message = + RebuildNormal( + baseChunkZ = baseChunkZ, + format = format, + npcCoordinateBits = npcCoordinateBits, + // The two skipped bytes are separated by baseChunkZ in beta. + unused = (unused0 shl 8) or unused1, + baseChunkX = baseChunkX, + worldAreaId = buffer.g2(), + minimumCoordinate = buffer.g4(), + maximumCoordinate = buffer.g4(), + sceneSize = SCENE_SIZE, + playerInfoInit = init, + ) + require(message.format == 5) { "Unsupported REBUILD_NORMAL format ${message.format}" } + require(buffer.readableBytes() == 0) { "Trailing REBUILD_NORMAL bytes" } + session.initializeNpcInfo(message.npcCoordinateBits, init != null) + session.initializePlayerInfo(init) + return message + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/RebuildRegionDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/RebuildRegionDecoder.kt new file mode 100644 index 00000000..eaf6912e --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/RebuildRegionDecoder.kt @@ -0,0 +1,69 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.buffer.bitbuffer.toBitBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.map.RebuildRegion +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo.initializeNpcInfo +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo.initializePlayerInfo +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo.readPlayerInfoInit +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class RebuildRegionDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.REBUILD_REGION + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): RebuildRegion { + val init = session.readPlayerInfoInit(buffer) + val unused = buffer.g1() + val npcCoordinateBits = buffer.g1Alt3() + val mode = buffer.g1Alt2() + val baseChunkX = buffer.g2Alt3() + val baseChunkZ = buffer.g2Alt2() + val format = buffer.g1Alt3() + require(format == 5 && mode in 1..4) { "Unsupported region format/mode $format/$mode" } + val regionOriginX = buffer.g2() + val regionOriginZ = buffer.g2() + val rows = buffer.g1() + val columns = buffer.g1() + require(4 * rows * columns <= buffer.readableBytes() * 8) { "Truncated region presence bits" } + val templates = + buffer.buffer.toBitBuf().use { bits -> + List(4) { + List(rows) { + List(columns) { + require(bits.isReadable(1)) { "Missing region presence bit" } + if (bits.gBits(1) == 0) { + -1 + } else { + require(bits.isReadable(26)) { "Truncated region template" } + bits.gBits(26) + } + } + } + } + } + require(buffer.readableBytes() == 0) { "Trailing REBUILD_REGION bytes" } + session.initializeNpcInfo(npcCoordinateBits, init != null) + session.initializePlayerInfo(init) + return RebuildRegion( + baseChunkZ, + unused, + npcCoordinateBits, + format, + mode, + baseChunkX, + regionOriginX, + regionOriginZ, + rows, + columns, + templates, + SCENE_SIZE, + init, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/ReconnectDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/ReconnectDecoder.kt new file mode 100644 index 00000000..a8e8e33c --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/ReconnectDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map + +import net.rsprot.buffer.JagByteBuf +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.map.Reconnect +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo.initializePlayerInfo +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo.readPlayerInfoInit +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +/** Recording-only response-15 payload. Native 950 uses the rebuild player initializer. */ +internal class ReconnectDecoder : ProxyMessageDecoder { + override val prot = GameServerProt.RECONNECT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): Reconnect { + val init = checkNotNull(session.readPlayerInfoInit(buffer, reconnect = true)) + require(buffer.readableBytes() == 0) { "Unconsumed reconnect initialization" } + session.initializePlayerInfo(init) + return Reconnect(init) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/SceneConstants.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/SceneConstants.kt new file mode 100644 index 00000000..6316789a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/SceneConstants.kt @@ -0,0 +1,7 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map + +// Native 950 constructor: Ghidra 0x182d76 initializes Client+0x19440's +// scene window size (+0x610) to 256. Both rebuild handlers use size >> 4 +// to convert their centre chunks to the scene's south-west tile origin. +// This is the scene window size, not the variable instance-template grid size. +internal const val SCENE_SIZE: Int = 256 diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightAttenuationFalloffDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightAttenuationFalloffDecoder.kt new file mode 100644 index 00000000..3264f22a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightAttenuationFalloffDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.map.lighting.PointLightAttenuationFalloff +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PointLightAttenuationFalloffDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.POINTLIGHT_ATTENUATION_FALLOFF + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PointLightAttenuationFalloff { + val falloff = buffer.g2() + val id = buffer.g2Alt2().toShort().toInt() + return PointLightAttenuationFalloff(falloff, id) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightColourDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightColourDecoder.kt new file mode 100644 index 00000000..aa40f789 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightColourDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.map.lighting.PointLightColour +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PointLightColourDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.POINTLIGHT_COLOUR + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PointLightColour { + val id = buffer.g2().toShort().toInt() + val duration = buffer.g2Alt1() + val colour = buffer.g4Alt2() + return PointLightColour(colour, duration, id) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightEnabledDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightEnabledDecoder.kt new file mode 100644 index 00000000..c2ebad09 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightEnabledDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.map.lighting.PointLightEnabled +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PointLightEnabledDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.POINTLIGHT_ENABLED + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PointLightEnabled { + val encodedControl = buffer.g1() + val id = buffer.g2Alt2().toShort().toInt() + return PointLightEnabled(encodedControl, id, encodedControl and 0xF, encodedControl and 0x10 != 0) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightExtendAboveDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightExtendAboveDecoder.kt new file mode 100644 index 00000000..3ac68776 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightExtendAboveDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.map.lighting.PointLightExtendAbove +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PointLightExtendAboveDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.POINTLIGHT_EXTEND_ABOVE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PointLightExtendAbove { + val mode = buffer.g1() + val id = buffer.g2Alt3().toShort().toInt() + return PointLightExtendAbove(id, mode) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightExtendBelowDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightExtendBelowDecoder.kt new file mode 100644 index 00000000..610369b7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightExtendBelowDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.map.lighting.PointLightExtendBelow +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PointLightExtendBelowDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.POINTLIGHT_EXTEND_BELOW + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PointLightExtendBelow { + val mode = buffer.g1Alt1() + val id = buffer.g2().toShort().toInt() + return PointLightExtendBelow(id, mode) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightIntensityScaleDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightIntensityScaleDecoder.kt new file mode 100644 index 00000000..5c3ec037 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightIntensityScaleDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.map.lighting.PointLightIntensityScale +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PointLightIntensityScaleDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.POINTLIGHT_INTENSITYSCALE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PointLightIntensityScale { + val intensity = buffer.g1Alt3() + val duration = buffer.g2() + val id = buffer.g2Alt3().toShort().toInt() + return PointLightIntensityScale(intensity, duration, id) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightShadowDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightShadowDecoder.kt new file mode 100644 index 00000000..b784d14a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/map/lighting/PointLightShadowDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.map.lighting.PointLightShadow +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PointLightShadowDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.POINTLIGHT_SHADOW + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PointLightShadow { + val encodedControl = buffer.g1() + val id = buffer.g2().toShort().toInt() + return PointLightShadow(id, encodedControl, encodedControl and 0xF) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ChangeLobbyDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ChangeLobbyDecoder.kt new file mode 100644 index 00000000..fe330702 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ChangeLobbyDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.ChangeLobby +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ChangeLobbyDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CHANGE_LOBBY + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ChangeLobby { + val host = buffer.gjstr() + val world = buffer.g2() + val port = buffer.g2() + val alternatePort = buffer.g2() + return ChangeLobby(host, world, port, alternatePort) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ConsoleFeedbackDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ConsoleFeedbackDecoder.kt new file mode 100644 index 00000000..303b919b --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ConsoleFeedbackDecoder.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.ConsoleFeedback +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ConsoleFeedbackDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CONSOLE_FEEDBACK + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ConsoleFeedback { + val unusedText = buffer.readNativeString() + val prefix = buffer.readNativeString() + val totalMatches = buffer.g4() + val resultCount = buffer.g2() + val results = mutableListOf() + for (index in 0 until resultCount) { + val result = buffer.readNativeString() + results += result // Retain the transmitted terminator as well as nonempty results. + if (result.isEmpty()) break + } + return ConsoleFeedback(unusedText, prefix, totalMatches, resultCount, results) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Cutscene2dPlayDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Cutscene2dPlayDecoder.kt new file mode 100644 index 00000000..b12a0b2a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Cutscene2dPlayDecoder.kt @@ -0,0 +1,20 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.Cutscene2dPlay +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class Cutscene2dPlayDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CUTSCENE2D_PLAY + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): Cutscene2dPlay { + val id = buffer.g2() + return Cutscene2dPlay(id) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/DebugServerTriggersDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/DebugServerTriggersDecoder.kt new file mode 100644 index 00000000..e6c2d161 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/DebugServerTriggersDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.DebugServerTriggers +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class DebugServerTriggersDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.DEBUG_SERVER_TRIGGERS + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): DebugServerTriggers { + val interfaceId = buffer.g2() + val start = buffer.g2() + val endExclusive = buffer.g2() + val count = (endExclusive - start).coerceAtLeast(0) + require(count <= buffer.readableBytes() / 3) { "Truncated debug trigger records" } + // Native skips exactly three bytes per record; do not invent trigger IDs or parameters. + val records = List(count) { DebugServerTriggers.Record(buffer.g1(), buffer.g1(), buffer.g1()) } + return DebugServerTriggers(interfaceId, start, endExclusive, records) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/DoCheatDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/DoCheatDecoder.kt new file mode 100644 index 00000000..7246a3e3 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/DoCheatDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.DoCheat +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class DoCheatDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.DO_CHEAT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): DoCheat { + val command = buffer.readNativeString() + return DoCheat(command) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ExecuteClientCheatDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ExecuteClientCheatDecoder.kt new file mode 100644 index 00000000..f748a0ca --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ExecuteClientCheatDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.ExecuteClientCheat +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ExecuteClientCheatDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.EXECUTE_CLIENT_CHEAT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ExecuteClientCheat { + val command = buffer.g2() + return ExecuteClientCheat( + command, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/HintArrowDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/HintArrowDecoder.kt new file mode 100644 index 00000000..3a9a12f7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/HintArrowDecoder.kt @@ -0,0 +1,44 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.HintArrow +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class HintArrowDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.HINT_ARROW + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): HintArrow { + val header = buffer.g1() + val kind = header and 31 + val payload = + when (kind) { + 0 -> HintArrow.Clear(List(13) { buffer.g1() }) + 1, 10 -> + HintArrow.Actor( + buffer.g1(), + buffer.g2(), + buffer.g2(), + List(4) { buffer.g1() }, + buffer.g4(), + ) + in 2..7 -> + HintArrow.Location( + buffer.g1(), + buffer.g1(), + buffer.g2(), + buffer.g2(), + buffer.g1(), + buffer.g2(), + buffer.g4(), + ) + else -> HintArrow.Other(buffer.g1(), buffer.g4(), List(8) { buffer.g1() }) + } + return HintArrow(header ushr 5, kind, payload) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/HintTrailDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/HintTrailDecoder.kt new file mode 100644 index 00000000..a826d6da --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/HintTrailDecoder.kt @@ -0,0 +1,31 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.HintTrail +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class HintTrailDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.HINT_TRAIL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): HintTrail { + val slot = buffer.g1() + val modelId = buffer.gSmart2or4null() + if (modelId == -1) return HintTrail(slot, modelId, null) + val count = buffer.gSmart1or2s() + val baseX = buffer.g2() + val baseZ = buffer.g2() + val points = + List(count.coerceAtLeast(0)) { + val deltaX = buffer.g1s() + val deltaZ = buffer.g1s() + HintTrail.Point(deltaX, deltaZ) + } + return HintTrail(slot, modelId, HintTrail.Trail(count, baseX, baseZ, points)) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Js5ReloadDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Js5ReloadDecoder.kt new file mode 100644 index 00000000..24ff12ff --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Js5ReloadDecoder.kt @@ -0,0 +1,17 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.Js5Reload +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class Js5ReloadDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.JS5_RELOAD + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): Js5Reload = Js5Reload +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/LogoutDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/LogoutDecoder.kt new file mode 100644 index 00000000..60813b61 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/LogoutDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.Logout +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LogoutDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOGOUT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): Logout { + val reason = buffer.g1() + return Logout( + reason, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/LogoutFullDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/LogoutFullDecoder.kt new file mode 100644 index 00000000..b75b3509 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/LogoutFullDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.LogoutFull +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LogoutFullDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOGOUT_FULL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LogoutFull { + val reason = buffer.g1() + return LogoutFull( + reason, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/LogoutTransferDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/LogoutTransferDecoder.kt new file mode 100644 index 00000000..2bbd13be --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/LogoutTransferDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.LogoutTransfer +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LogoutTransferDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOGOUT_TRANSFER + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LogoutTransfer { + val world = buffer.g2() + val host = buffer.gjstr() + val port = buffer.g2() + val alternatePort = buffer.g2() + val transferFlag = buffer.g1() + return LogoutTransfer(world, host, port, alternatePort, transferFlag) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/MinimapToggleDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/MinimapToggleDecoder.kt new file mode 100644 index 00000000..b35fdc55 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/MinimapToggleDecoder.kt @@ -0,0 +1,20 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.game.outgoing.model.misc.client.MinimapToggle +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MinimapToggleDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MINIMAP_TOGGLE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MinimapToggle { + val state = buffer.g1() + return MinimapToggle(state) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/NoTimeoutDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/NoTimeoutDecoder.kt new file mode 100644 index 00000000..6a0efe0a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/NoTimeoutDecoder.kt @@ -0,0 +1,19 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprot.protocol.metadata.Consistent +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.NoTimeout +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +@Consistent +internal class NoTimeoutDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.NO_TIMEOUT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): NoTimeout = NoTimeout +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ResetAnimsDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ResetAnimsDecoder.kt new file mode 100644 index 00000000..0f673668 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ResetAnimsDecoder.kt @@ -0,0 +1,17 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.ResetAnims +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ResetAnimsDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.RESET_ANIMS + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ResetAnims = ResetAnims +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SendPingDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SendPingDecoder.kt new file mode 100644 index 00000000..74fac7b9 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SendPingDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprot.protocol.metadata.Consistent +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.SendPing +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +@Consistent +internal class SendPingDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SEND_PING + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SendPing { + val echo0 = buffer.g4() + val echo1 = buffer.g4() + return SendPing( + echo0, + echo1, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SetDrawOrderDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SetDrawOrderDecoder.kt new file mode 100644 index 00000000..32bc6a79 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SetDrawOrderDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.SetDrawOrder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SetDrawOrderDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SETDRAWORDER + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SetDrawOrder { + val order = buffer.g1Alt1() + return SetDrawOrder( + order, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ShowFaceHereDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ShowFaceHereDecoder.kt new file mode 100644 index 00000000..f33de4ed --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/ShowFaceHereDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.ShowFaceHere +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ShowFaceHereDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SHOW_FACE_HERE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ShowFaceHere { + val enabled = buffer.g1Alt3() == 1 + return ShowFaceHere( + enabled, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SiteSettingsDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SiteSettingsDecoder.kt new file mode 100644 index 00000000..7c2b19ae --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SiteSettingsDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.game.outgoing.model.misc.client.SiteSettings +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +// OSRS's consistent string layout, also observed in live RS3 950 traffic. +// The native 950 handler ignores it; this is not a native-reader proof. +internal class SiteSettingsDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_SITESETTINGS + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SiteSettings { + return SiteSettings(buffer.gjstr()) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/StoreResetDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/StoreResetDecoder.kt new file mode 100644 index 00000000..4318a207 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/StoreResetDecoder.kt @@ -0,0 +1,17 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.StoreReset +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class StoreResetDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.STORE_RESET + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): StoreReset = StoreReset +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/StoreServerpermVarcsAckDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/StoreServerpermVarcsAckDecoder.kt new file mode 100644 index 00000000..03b1ac5d --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/StoreServerpermVarcsAckDecoder.kt @@ -0,0 +1,17 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.StoreServerpermVarcsAck +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class StoreServerpermVarcsAckDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.STORE_SERVERPERM_VARCS_ACK + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): StoreServerpermVarcsAck = StoreServerpermVarcsAck +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SyncClockDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SyncClockDecoder.kt new file mode 100644 index 00000000..30e46042 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/SyncClockDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.SyncClock +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SyncClockDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SYNC_CLOCK + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SyncClock { + val serverTime = buffer.g8() + return SyncClock( + serverTime, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/TickEndDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/TickEndDecoder.kt new file mode 100644 index 00000000..4e85a6e9 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/TickEndDecoder.kt @@ -0,0 +1,16 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.TickEnd +import net.rsprox.protocol.session.Session + +internal class TickEndDecoder( + override val prot: ClientProt, +) : ProxyMessageDecoder { + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TickEnd = TickEnd() +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/TriggerOnDialogAbortDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/TriggerOnDialogAbortDecoder.kt new file mode 100644 index 00000000..0c3b29ea --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/TriggerOnDialogAbortDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprot.protocol.metadata.Consistent +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.TriggerOnDialogAbort +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +@Consistent +internal class TriggerOnDialogAbortDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TRIGGER_ONDIALOGABORT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TriggerOnDialogAbort { + return TriggerOnDialogAbort + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Unnamed1Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Unnamed1Decoder.kt new file mode 100644 index 00000000..7510e9b0 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Unnamed1Decoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.Unnamed1 +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class Unnamed1Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UNNAMED_1 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): Unnamed1 { + val mode = buffer.g1() + val modeWord = if (mode == 1) buffer.g2() else null + val modeBytes = if (mode == 2) Unnamed1.ModeBytes(buffer.g1(), buffer.g1(), buffer.g1()) else null + val textFlag = buffer.g1() + val discardedText = if (textFlag == 0) buffer.readNativeString() else null + return Unnamed1(mode, modeWord, modeBytes, textFlag, discardedText) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Unnamed2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Unnamed2Decoder.kt new file mode 100644 index 00000000..c172385f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/Unnamed2Decoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.Unnamed2 +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class Unnamed2Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UNNAMED_2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): Unnamed2 { + val count = buffer.g4() + val recordCount = count.coerceAtLeast(0) + require(buffer.readableBytes() >= 4 && recordCount <= (buffer.readableBytes() - 4) / 4) { + "Truncated counted ignored-word block" + } + // Beta skips both the records and footer; retain their bytes without assigning an integer encoding. + val records = List(recordCount) { Unnamed2.Record(buffer.g1(), buffer.g1(), buffer.g1(), buffer.g1()) } + val reservedFooter = List(4) { buffer.g1() } + return Unnamed2(count, records, null, reservedFooter) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/UpdateRebootTimerDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/UpdateRebootTimerDecoder.kt new file mode 100644 index 00000000..29c1839d --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/UpdateRebootTimerDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.UpdateRebootTimer +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateRebootTimerDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_REBOOT_TIMER + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateRebootTimer { + val duration = buffer.g2() + return UpdateRebootTimer( + duration, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/UpdateUid192Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/UpdateUid192Decoder.kt new file mode 100644 index 00000000..8771d02c --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/client/UpdateUid192Decoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.client.UpdateUid192 +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session +import java.util.zip.CRC32 + +internal class UpdateUid192Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_UID192 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateUid192 { + val uid = List(24) { buffer.g1() } + val crc = buffer.g4() + val valid = CRC32().apply { uid.forEach { update(it) } }.value.toInt() == crc + return UpdateUid192( + uid, + crc, + valid, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/ChatFilterSettingsDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/ChatFilterSettingsDecoder.kt new file mode 100644 index 00000000..eb8c0df9 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/ChatFilterSettingsDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.ChatFilterSettings +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ChatFilterSettingsDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CHAT_FILTER_SETTINGS + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ChatFilterSettings { + val filterSlot0 = buffer.g1Alt2() + val filterSlot1 = buffer.g1() + return ChatFilterSettings( + filterSlot1, + filterSlot0, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/ChatFilterSettingsPrivateChatDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/ChatFilterSettingsPrivateChatDecoder.kt new file mode 100644 index 00000000..0929d54c --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/ChatFilterSettingsPrivateChatDecoder.kt @@ -0,0 +1,20 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.game.outgoing.model.misc.player.ChatFilterSettingsPrivateChat +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ChatFilterSettingsPrivateChatDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CHAT_FILTER_SETTINGS_PRIVATECHAT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ChatFilterSettingsPrivateChat { + val privateChatFilter = buffer.g1() + return ChatFilterSettingsPrivateChat(privateChatFilter) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/ClearPlayerSnapshotDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/ClearPlayerSnapshotDecoder.kt new file mode 100644 index 00000000..b6577978 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/ClearPlayerSnapshotDecoder.kt @@ -0,0 +1,20 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.ClearPlayerSnapshot +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ClearPlayerSnapshotDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLEAR_PLAYER_SNAPSHOT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ClearPlayerSnapshot { + val index = buffer.g1() + return ClearPlayerSnapshot(index) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/JcoinsUpdateDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/JcoinsUpdateDecoder.kt new file mode 100644 index 00000000..b32af866 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/JcoinsUpdateDecoder.kt @@ -0,0 +1,20 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.JcoinsUpdate +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class JcoinsUpdateDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.JCOINS_UPDATE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): JcoinsUpdate { + val jcoins = buffer.g4() + return JcoinsUpdate(jcoins) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/LastLoginInfoDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/LastLoginInfoDecoder.kt new file mode 100644 index 00000000..cae4c84c --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/LastLoginInfoDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.LastLoginInfo +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LastLoginInfoDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LAST_LOGIN_INFO + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LastLoginInfo { + val lastLogin = buffer.g4() + return LastLoginInfo( + lastLogin, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/LoyaltyUpdateDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/LoyaltyUpdateDecoder.kt new file mode 100644 index 00000000..4a2703e8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/LoyaltyUpdateDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.LoyaltyUpdate +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LoyaltyUpdateDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOYALTY_UPDATE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LoyaltyUpdate { + val loyaltyPoints = buffer.g4Alt2() + return LoyaltyUpdate( + loyaltyPoints, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/MessageGameDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/MessageGameDecoder.kt new file mode 100644 index 00000000..bad79365 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/MessageGameDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.MessageGame +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessageGameDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_GAME + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessageGame { + val type = buffer.gSmart1or2() + val channel = buffer.g4() + val flags = buffer.g1() + val sender = if (flags and 1 != 0) buffer.readNativeString() else null + val alternateSender = if (flags and 3 == 3) buffer.readNativeString() else null + val message = buffer.readNativeString() + return MessageGame(type, channel, flags, sender, alternateSender, message) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/RunClientScriptDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/RunClientScriptDecoder.kt new file mode 100644 index 00000000..bb996fbd --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/RunClientScriptDecoder.kt @@ -0,0 +1,34 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.game.outgoing.model.misc.player.RunClientScript +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class RunClientScriptDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.RUNCLIENTSCRIPT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): RunClientScript { + val types = buffer.readNativeString() + val values = ArrayDeque(types.length) + for (char in types.reversed()) { + when (char) { + 's' -> values.addFirst(buffer.readNativeString()) + 'l' -> values.addFirst(buffer.g8()) + else -> values.addFirst(buffer.g4()) + } + } + val id = buffer.g4() + return RunClientScript( + id, + types.toCharArray(), + values, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetMapFlagDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetMapFlagDecoder.kt new file mode 100644 index 00000000..36e10480 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetMapFlagDecoder.kt @@ -0,0 +1,34 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.SetMapFlag +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SetMapFlagDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SET_MAP_FLAG + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SetMapFlag { + val id = buffer.g4Alt2() + val type = buffer.g1Alt3().toByte().toInt() + val sourceZ = buffer.g1Alt3() + val targetZ = buffer.g1Alt1() + val sourceX = buffer.g1Alt1() + val targetX = buffer.g1() + val flags = buffer.g1Alt2() + return SetMapFlag( + targetX, + type, + flags, + sourceZ, + id, + sourceX, + targetZ, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetMoveActionDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetMoveActionDecoder.kt new file mode 100644 index 00000000..8178371e --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetMoveActionDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.SetMoveAction +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SetMoveActionDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SET_MOVEACTION + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SetMoveAction { + val length = buffer.readableBytes() + require(length == 0 || length in 2..255) { "Invalid move-action payload length: $length" } + val action = if (length >= 3) buffer.gjstr() else null + val cursor = if (length == 0) -1 else buffer.g2().let { if (it == 65535) -1 else it } + return SetMoveAction( + action, + cursor, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetNpcAttackPriorityDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetNpcAttackPriorityDecoder.kt new file mode 100644 index 00000000..ca962195 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetNpcAttackPriorityDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.SetNpcAttackPriority +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SetNpcAttackPriorityDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SET_NPC_ATTACK_PRIORITY + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SetNpcAttackPriority { + val priority = buffer.g1() + return SetNpcAttackPriority( + priority, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetPlayerAttackPriorityDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetPlayerAttackPriorityDecoder.kt new file mode 100644 index 00000000..37f93075 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetPlayerAttackPriorityDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.SetPlayerAttackPriority +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SetPlayerAttackPriorityDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SET_PLAYER_ATTACK_PRIORITY + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SetPlayerAttackPriority { + val priority = buffer.g1Alt3() + return SetPlayerAttackPriority( + priority, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetPlayerOpDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetPlayerOpDecoder.kt new file mode 100644 index 00000000..40cea309 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetPlayerOpDecoder.kt @@ -0,0 +1,29 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.SetPlayerOp +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SetPlayerOpDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SET_PLAYER_OP + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SetPlayerOp { + val rawCursor = buffer.g2Alt3() + val priority = buffer.g1() == 0x80 + val slot = buffer.g1Alt3() - 1 + val text = buffer.gjstr() + val cursor = if (rawCursor == 0xFFFF) -1 else rawCursor + return SetPlayerOp( + slot, + priority, + text, + cursor, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetTargetDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetTargetDecoder.kt new file mode 100644 index 00000000..c26e1aa0 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/SetTargetDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.SetTarget +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SetTargetDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SET_TARGET + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SetTarget { + val target = buffer.g3() + return SetTarget( + target, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateRunEnergyDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateRunEnergyDecoder.kt new file mode 100644 index 00000000..5f017d14 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateRunEnergyDecoder.kt @@ -0,0 +1,20 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.UpdateRunEnergy +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateRunEnergyDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_RUNENERGY + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateRunEnergy { + val energy = buffer.g1() + return UpdateRunEnergy(energy) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateRunWeightDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateRunWeightDecoder.kt new file mode 100644 index 00000000..c05e0878 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateRunWeightDecoder.kt @@ -0,0 +1,20 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.UpdateRunWeight +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateRunWeightDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_RUNWEIGHT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateRunWeight { + val weight = buffer.g2s() + return UpdateRunWeight(weight) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateStatDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateStatDecoder.kt new file mode 100644 index 00000000..890a9bb2 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateStatDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.UpdateStat +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateStatDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_STAT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateStat { + val skillId = buffer.g1Alt3() + val xp = buffer.g4Alt3() + val level = buffer.g1Alt1() + return UpdateStat( + skillId, + level, + xp, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateStockmarketSlotV2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateStockmarketSlotV2Decoder.kt new file mode 100644 index 00000000..fea88c9c --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/misc/player/UpdateStockmarketSlotV2Decoder.kt @@ -0,0 +1,61 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.misc.player.UpdateStockmarketSlotV2 +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateStockmarketSlotV2Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_STOCKMARKET_SLOT_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateStockmarketSlotV2 { + val group = buffer.g1() + val slot = buffer.g1() + require(slot < 8) { "Invalid stock-market slot $slot" } + val state = buffer.g1() + val version = if (state and 7 == 7) buffer.g1() else null + val updatedState = buffer.g1() + val objectId = if (version != null && version >= 3) buffer.g3() else buffer.g2() + val wide = version != null && version >= 2 + val price = if (wide) buffer.g8() else buffer.g4().toLong() and 0xFFFF_FFFFL + val quantity = buffer.g4() + val completedQuantity = buffer.g4() + val total = if (wide) buffer.g8() else buffer.g4().toLong() and 0xFFFF_FFFFL + val extensionLength = if (wide) buffer.g4() else null + val extensionCapacity = if (version == 2) 1 else 0 + if (extensionLength != null) { + require(extensionLength in 0..extensionCapacity) { "Offer extension exceeds its fixed envelope" } + } + val extension = List(extensionLength ?: 0) { buffer.g1() } + val reservedCount = + when { + version == null -> 14 + version < 2 -> 13 + version == 2 -> 1 - requireNotNull(extensionLength) + else -> 0 + } + val reserved = List(reservedCount) { buffer.g1() } + return UpdateStockmarketSlotV2( + group, + slot, + state, + UpdateStockmarketSlotV2.Offer( + version, + updatedState, + objectId, + price, + quantity, + completedQuantity, + total, + extensionLength, + extension, + ), + reserved, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/LocSelectAddDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/LocSelectAddDecoder.kt new file mode 100644 index 00000000..978c88ff --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/LocSelectAddDecoder.kt @@ -0,0 +1,47 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.selection + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.selection.LocSelectAdd +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LocSelectAddDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOCSELECT_ADD + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LocSelectAdd { + val coordinate = buffer.g2Alt1() + val shapeRotation = buffer.g1() + val id = buffer.g4Alt2() + val transform = + if (shapeRotation and 0x80 != 0) { + val flags = buffer.g1() + val quaternion = if (flags and 1 != 0) List(4) { buffer.g2s() } else null + val translateX = if (flags and 2 != 0) buffer.g2s() else null + val translateY = if (flags and 4 != 0) buffer.g2s() else null + val translateZ = if (flags and 8 != 0) buffer.g2s() else null + val uniformScale = if (flags and 16 != 0) buffer.g2s() else null + val scaleX = if (uniformScale == null && flags and 32 != 0) buffer.g2s() else null + val scaleY = if (uniformScale == null && flags and 64 != 0) buffer.g2s() else null + val scaleZ = if (uniformScale == null && flags and 128 != 0) buffer.g2s() else null + LocSelectAdd.Transform( + flags, + quaternion, + translateX, + translateY, + translateZ, + uniformScale, + scaleX, + scaleY, + scaleZ, + ) + } else { + null + } + return LocSelectAdd(coordinate, id, shapeRotation, transform) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/LocSelectClearDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/LocSelectClearDecoder.kt new file mode 100644 index 00000000..45605ed1 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/LocSelectClearDecoder.kt @@ -0,0 +1,17 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.selection + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.selection.LocSelectClear +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LocSelectClearDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOCSELECT_CLEAR + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LocSelectClear = LocSelectClear +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/LocSelectConfigureDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/LocSelectConfigureDecoder.kt new file mode 100644 index 00000000..c5807873 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/LocSelectConfigureDecoder.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.selection + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.selection.LocSelectConfigure +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LocSelectConfigureDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOCSELECT_CONFIGURE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LocSelectConfigure { + val to = buffer.g4Alt2() + val enabled = buffer.g1Alt2() == 1 + val id = buffer.g4Alt1() + val from = buffer.g4Alt3() + val count = buffer.g1Alt1() + return LocSelectConfigure( + id, + enabled, + from, + count, + to, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/SetLocOpOverrideDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/SetLocOpOverrideDecoder.kt new file mode 100644 index 00000000..a23be4b7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/selection/SetLocOpOverrideDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.selection + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.selection.SetLocOpOverride +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SetLocOpOverrideDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SET_LOC_OP_OVERRIDE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SetLocOpOverride { + val operation = buffer.g1Alt3() + val rawCursor = buffer.g2Alt3() + val cursor = if (rawCursor == 65535) -1 else rawCursor + val label = buffer.gjstr() + val overrideStart = buffer.g4Alt3() + val overrideEnd = buffer.g4() + return SetLocOpOverride(overrideStart, operation, label, cursor, overrideEnd) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageClanchannelDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageClanchannelDecoder.kt new file mode 100644 index 00000000..06f3d157 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageClanchannelDecoder.kt @@ -0,0 +1,37 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessageClanchannel +import net.rsprox.protocol.rs3v950beta.buffer.readNativeHuffman +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessageClanchannelDecoder( + private val huffmanCodec: HuffmanCodec?, +) : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_CLANCHANNEL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessageClanchannel { + val channel = buffer.g1s() + val sender = buffer.readNativeString() + val messageWorld = buffer.g2() + val messageCounter = buffer.g3() + val playerType = buffer.g1() + val message = buffer.readNativeHuffman(huffmanCodec) + return MessageClanchannel( + channel, + sender, + messageWorld, + messageCounter, + playerType, + message, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageClanchannelSystemDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageClanchannelSystemDecoder.kt new file mode 100644 index 00000000..c8fd34e1 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageClanchannelSystemDecoder.kt @@ -0,0 +1,32 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessageClanchannelSystem +import net.rsprox.protocol.rs3v950beta.buffer.readNativeHuffman +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessageClanchannelSystemDecoder( + private val huffmanCodec: HuffmanCodec?, +) : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_CLANCHANNEL_SYSTEM + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessageClanchannelSystem { + val channel = buffer.g1s() + val messageWorld = buffer.g2() + val messageCounter = buffer.g3() + val message = buffer.readNativeHuffman(huffmanCodec) + return MessageClanchannelSystem( + channel, + messageWorld, + messageCounter, + message, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageFriendchannelDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageFriendchannelDecoder.kt new file mode 100644 index 00000000..b51c81a3 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageFriendchannelDecoder.kt @@ -0,0 +1,41 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessageFriendchannel +import net.rsprox.protocol.rs3v950beta.buffer.readNativeHuffman +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessageFriendchannelDecoder( + private val huffmanCodec: HuffmanCodec?, +) : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_FRIENDCHANNEL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessageFriendchannel { + val alternateSenderFlag = buffer.g1() + val sender = buffer.readNativeString() + val alternateSender = if (alternateSenderFlag == 1) buffer.readNativeString() else null + val channelName = buffer.readNativeString() + val messageWorld = buffer.g2() + val messageCounter = buffer.g3() + val playerType = buffer.g1() + val message = buffer.readNativeHuffman(huffmanCodec) + return MessageFriendchannel( + alternateSenderFlag, + sender, + alternateSender, + channelName, + messageWorld, + messageCounter, + playerType, + message, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePlayerGroupDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePlayerGroupDecoder.kt new file mode 100644 index 00000000..f9fd455f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePlayerGroupDecoder.kt @@ -0,0 +1,37 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessagePlayerGroup +import net.rsprox.protocol.rs3v950beta.buffer.readNativeHuffman +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessagePlayerGroupDecoder( + private val huffmanCodec: HuffmanCodec?, +) : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_PLAYER_GROUP + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessagePlayerGroup { + val sender = buffer.readNativeString() + val messageWorld = buffer.g2() + val messageCounter = buffer.g3() + val playerType = buffer.g1() + val broadcast = buffer.g1() + val message = buffer.readNativeHuffman(huffmanCodec) + return MessagePlayerGroup( + sender, + messageWorld, + messageCounter, + playerType, + broadcast, + message, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePrivateDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePrivateDecoder.kt new file mode 100644 index 00000000..b8b821e5 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePrivateDecoder.kt @@ -0,0 +1,39 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessagePrivate +import net.rsprox.protocol.rs3v950beta.buffer.readNativeHuffman +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessagePrivateDecoder( + private val huffmanCodec: HuffmanCodec?, +) : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_PRIVATE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessagePrivate { + val alternateSenderFlag = buffer.g1() + val sender = buffer.readNativeString() + val alternateSender = if (alternateSenderFlag == 1) buffer.readNativeString() else null + val messageWorld = buffer.g2() + val messageCounter = buffer.g3() + val playerType = buffer.g1() + val message = buffer.readNativeHuffman(huffmanCodec) + return MessagePrivate( + alternateSenderFlag, + sender, + alternateSender, + messageWorld, + messageCounter, + playerType, + message, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePrivateEchoDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePrivateEchoDecoder.kt new file mode 100644 index 00000000..87609806 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePrivateEchoDecoder.kt @@ -0,0 +1,29 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessagePrivateEcho +import net.rsprox.protocol.rs3v950beta.buffer.readNativeHuffman +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessagePrivateEchoDecoder( + private val huffmanCodec: HuffmanCodec?, +) : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_PRIVATE_ECHO + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessagePrivateEcho { + val recipient = buffer.readNativeString() + val message = buffer.readNativeHuffman(huffmanCodec) + return MessagePrivateEcho( + recipient, + message, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePublicDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePublicDecoder.kt new file mode 100644 index 00000000..f0d4035d --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessagePublicDecoder.kt @@ -0,0 +1,38 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.compression.HuffmanCodec +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessagePublic +import net.rsprox.protocol.rs3v950beta.buffer.readNativeHuffman +import net.rsprox.protocol.rs3v950beta.cache.readQuickChat +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessagePublicDecoder( + private val huffmanCodec: HuffmanCodec?, +) : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_PUBLIC + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessagePublic { + val playerIndex = buffer.g2() + val colourEffectAndQuickFlag = buffer.g2() + val playerType = buffer.g1() + if (colourEffectAndQuickFlag and 32768 != 0) { + val phraseId = buffer.g2() + return MessagePublic( + playerIndex, + colourEffectAndQuickFlag, + playerType, + null, + phraseId, + buffer.readQuickChat(session, phraseId), + ) + } + return MessagePublic(playerIndex, colourEffectAndQuickFlag, playerType, buffer.readNativeHuffman(huffmanCodec)) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatClanchannelDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatClanchannelDecoder.kt new file mode 100644 index 00000000..4e2eb669 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatClanchannelDecoder.kt @@ -0,0 +1,35 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessageQuickchatClanchannel +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.cache.readQuickChat +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessageQuickchatClanchannelDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_QUICKCHAT_CLANCHANNEL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessageQuickchatClanchannel { + val channel = buffer.g1s() + val sender = buffer.readNativeString() + val messageWorld = buffer.g2() + val messageCounter = buffer.g3() + val playerType = buffer.g1() + val phraseId = buffer.g2() + return MessageQuickchatClanchannel( + channel, + sender, + messageWorld, + messageCounter, + playerType, + phraseId, + buffer.readQuickChat(session, phraseId), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatFriendchatDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatFriendchatDecoder.kt new file mode 100644 index 00000000..cd426422 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatFriendchatDecoder.kt @@ -0,0 +1,39 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessageQuickchatFriendchat +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.cache.readQuickChat +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessageQuickchatFriendchatDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_QUICKCHAT_FRIENDCHAT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessageQuickchatFriendchat { + val alternateSenderFlag = buffer.g1() + val sender = buffer.readNativeString() + val alternateSender = if (alternateSenderFlag == 1) buffer.readNativeString() else null + val channelName = buffer.readNativeString() + val messageWorld = buffer.g2() + val messageCounter = buffer.g3() + val playerType = buffer.g1() + val phraseId = buffer.g2() + return MessageQuickchatFriendchat( + alternateSenderFlag, + sender, + alternateSender, + channelName, + messageWorld, + messageCounter, + playerType, + phraseId, + buffer.readQuickChat(session, phraseId), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatPlayerGroupDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatPlayerGroupDecoder.kt new file mode 100644 index 00000000..1b7597c4 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatPlayerGroupDecoder.kt @@ -0,0 +1,35 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessageQuickchatPlayerGroup +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.cache.readQuickChat +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessageQuickchatPlayerGroupDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_QUICKCHAT_PLAYER_GROUP + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessageQuickchatPlayerGroup { + val sender = buffer.readNativeString() + val messageWorld = buffer.g2() + val messageCounter = buffer.g3() + val playerType = buffer.g1() + val broadcast = buffer.g1() + val phraseId = buffer.g2() + return MessageQuickchatPlayerGroup( + sender, + messageWorld, + messageCounter, + playerType, + broadcast, + phraseId, + buffer.readQuickChat(session, phraseId), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatPrivateDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatPrivateDecoder.kt new file mode 100644 index 00000000..6462a077 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatPrivateDecoder.kt @@ -0,0 +1,37 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessageQuickchatPrivate +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.cache.readQuickChat +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessageQuickchatPrivateDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_QUICKCHAT_PRIVATE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessageQuickchatPrivate { + val alternateSenderFlag = buffer.g1() + val sender = buffer.readNativeString() + val alternateSender = if (alternateSenderFlag == 1) buffer.readNativeString() else null + val messageWorld = buffer.g2() + val messageCounter = buffer.g3() + val playerType = buffer.g1() + val phraseId = buffer.g2() + return MessageQuickchatPrivate( + alternateSenderFlag, + sender, + alternateSender, + messageWorld, + messageCounter, + playerType, + phraseId, + buffer.readQuickChat(session, phraseId), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatPrivateEchoDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatPrivateEchoDecoder.kt new file mode 100644 index 00000000..05134dad --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/MessageQuickchatPrivateEchoDecoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.MessageQuickchatPrivateEcho +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.cache.readQuickChat +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MessageQuickchatPrivateEchoDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MESSAGE_QUICKCHAT_PRIVATE_ECHO + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MessageQuickchatPrivateEcho { + val recipient = buffer.readNativeString() + val phraseId = buffer.g2() + return MessageQuickchatPrivateEcho( + recipient, + phraseId, + buffer.readQuickChat(session, phraseId), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/SocialNetworkLogoutDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/SocialNetworkLogoutDecoder.kt new file mode 100644 index 00000000..1ac04299 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/SocialNetworkLogoutDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.crypto.cipher.StreamCipher +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.SocialNetworkLogout +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.readNativeIsaacString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SocialNetworkLogoutDecoder( + private val cipher: () -> StreamCipher?, +) : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SOCIAL_NETWORK_LOGOUT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SocialNetworkLogout { + val activeCipher = checkNotNull(cipher()) { "SOCIAL_NETWORK_LOGOUT requires the inbound opcode cipher" } + return SocialNetworkLogout(buffer.readNativeIsaacString(activeCipher, buffer.readableBytes().toLong())) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateFriendchatChannelFullDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateFriendchatChannelFullDecoder.kt new file mode 100644 index 00000000..8c9e6c6d --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateFriendchatChannelFullDecoder.kt @@ -0,0 +1,44 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.UpdateFriendchatChannelFull +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateFriendchatChannelFullDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_FRIENDCHAT_CHANNEL_FULL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateFriendchatChannelFull { + if (!buffer.isReadable) return UpdateFriendchatChannelFull(null) + val owner = buffer.readNativeString() + val aliasFlag = buffer.g1() + val alias = if (aliasFlag == 1) buffer.readNativeString() else null + val name = buffer.readNativeString() + val minimumKickRank = buffer.g1s() + val memberCount = buffer.gSmart1or2() - 1 + require(memberCount <= buffer.readableBytes() / 6) { "Truncated friend-chat member list" } + val members = + if (memberCount == -1) { + null // Preserve the existing members, unlike an empty replacement list. + } else { + List(memberCount) { + val memberName = buffer.readNativeString() + val memberAliasFlag = buffer.g1() + val memberAlias = if (memberAliasFlag == 1) buffer.readNativeString() else null + val world = buffer.g2() + val rank = buffer.g1s() + val worldName = buffer.readNativeString() + UpdateFriendchatChannelFull.Member(memberName, memberAliasFlag, memberAlias, world, rank, worldName) + } + } + return UpdateFriendchatChannelFull( + UpdateFriendchatChannelFull.Channel(owner, aliasFlag, alias, name, minimumKickRank, memberCount, members), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateFriendchatChannelSingleUserDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateFriendchatChannelSingleUserDecoder.kt new file mode 100644 index 00000000..10d147d3 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateFriendchatChannelSingleUserDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.UpdateFriendchatChannelSingleUser +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateFriendchatChannelSingleUserDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_FRIENDCHAT_CHANNEL_SINGLEUSER + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateFriendchatChannelSingleUser { + val name = buffer.readNativeString() + val aliasFlag = buffer.g1() + val alias = if (aliasFlag == 1) buffer.readNativeString() else null + val world = buffer.g2() + val rank = buffer.g1s() + val worldName = if (rank == -128) null else buffer.readNativeString() + return UpdateFriendchatChannelSingleUser(name, aliasFlag, alias, world, rank, worldName) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateFriendlistDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateFriendlistDecoder.kt new file mode 100644 index 00000000..8682c407 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateFriendlistDecoder.kt @@ -0,0 +1,46 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.UpdateFriendlist +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateFriendlistDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_FRIENDLIST + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateFriendlist { + val friends = mutableListOf() + while (buffer.isReadable) { + val rename = buffer.g1() + val name = buffer.readNativeString() + val previousName = buffer.readNativeString() + val world = buffer.g2() + val rank = buffer.g1() + val flags = buffer.g1() + val worldName = if (world != 0) buffer.readNativeString() else null + val platform = if (world != 0) buffer.g1() else null + val worldMetadata = if (world != 0) buffer.g4() else null + val note = buffer.readNativeString() + friends += + UpdateFriendlist.Friend( + rename, + name, + previousName, + world, + rank, + flags, + worldName, + platform, + worldMetadata, + note, + ) + } + return UpdateFriendlist(friends) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateIgnorelistDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateIgnorelistDecoder.kt new file mode 100644 index 00000000..c2500c47 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UpdateIgnorelistDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.UpdateIgnorelist +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateIgnorelistDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_IGNORELIST + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateIgnorelist { + val ignores = mutableListOf() + while (buffer.isReadable) { + val flags = buffer.g1() + val name = buffer.readNativeString() + val previousName = buffer.readNativeString() + val note = buffer.readNativeString() + ignores += UpdateIgnorelist.Ignore(flags, name, previousName, note) + } + return UpdateIgnorelist(ignores) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UrlOpenDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UrlOpenDecoder.kt new file mode 100644 index 00000000..c4fec0f4 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/social/UrlOpenDecoder.kt @@ -0,0 +1,35 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.crypto.cipher.StreamCipher +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.social.UrlOpen +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.readNativeIsaacString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UrlOpenDecoder( + private val cipher: () -> StreamCipher?, +) : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.URL_OPEN + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UrlOpen { + val activeCipher = checkNotNull(cipher()) { "URL_OPEN requires the inbound opcode cipher" } + val length = buffer.readableBytes() + val mode = buffer.g1() + val url = buffer.readNativeIsaacString(activeCipher, (length - 1).toLong()) + val preferredUrl = + if (mode == 1) { + // Native budget uses decoded UTF-8 length, not the first string's consumed wire length. + val budget = (length - 1 - url.toByteArray(Charsets.UTF_8).size).toUInt().toLong() + buffer.readNativeIsaacString(activeCipher, budget) + } else { + null + } + return UrlOpen(mode, url, preferredUrl) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/MidiJingleDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/MidiJingleDecoder.kt new file mode 100644 index 00000000..8d0a65cd --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/MidiJingleDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.MidiJingle +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MidiJingleDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MIDI_JINGLE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MidiJingle { + val song = buffer.g4Alt2() + val volume = buffer.g1() + return MidiJingle( + song = song, + volume = volume, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/MidiSongDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/MidiSongDecoder.kt new file mode 100644 index 00000000..56c54c65 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/MidiSongDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.MidiSong +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MidiSongDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MIDI_SONG + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MidiSong { + val volume = buffer.g1Alt3() + val id = buffer.g4Alt2() + return MidiSong( + id = id, + volume = volume, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/MidiSongStopDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/MidiSongStopDecoder.kt new file mode 100644 index 00000000..89ffd3d0 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/MidiSongStopDecoder.kt @@ -0,0 +1,19 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.MidiSongStop +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MidiSongStopDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MIDI_SONG_STOP + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MidiSongStop { + return MidiSongStop + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SongPreloadDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SongPreloadDecoder.kt new file mode 100644 index 00000000..f947aae3 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SongPreloadDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.SongPreload +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SongPreloadDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SONG_PRELOAD + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SongPreload { + val id = buffer.g4Alt3() + return SongPreload( + id = id, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SoundMixbussAddDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SoundMixbussAddDecoder.kt new file mode 100644 index 00000000..490a22ef --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SoundMixbussAddDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.SoundMixbussAdd +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SoundMixbussAddDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SOUND_MIXBUSS_ADD + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SoundMixbussAdd { + val bus = buffer.g2() + val parent = buffer.g2() + val level = buffer.g2() + return SoundMixbussAdd( + bus = bus, + parent = parent, + level = level, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SoundMixbussSetLevelDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SoundMixbussSetLevelDecoder.kt new file mode 100644 index 00000000..9a43efa4 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SoundMixbussSetLevelDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.SoundMixbussSetLevel +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SoundMixbussSetLevelDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SOUND_MIXBUSS_SETLEVEL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SoundMixbussSetLevel { + val bus = buffer.g2() + val level = buffer.g2() + return SoundMixbussSetLevel( + bus = bus, + level = level, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SoundStopDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SoundStopDecoder.kt new file mode 100644 index 00000000..b333e125 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SoundStopDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.SoundStop +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SoundStopDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SOUND_STOP + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SoundStop { + val id = buffer.g4() + val group = buffer.g2() + return SoundStop( + id = id, + group = group, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SynthSoundDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SynthSoundDecoder.kt new file mode 100644 index 00000000..07a08553 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/SynthSoundDecoder.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.SynthSound +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SynthSoundDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SYNTH_SOUND + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SynthSound { + val id = buffer.g4() + val loops = buffer.g1() + val delay = buffer.g2() + val volume = buffer.g1() + val rate = buffer.g2() + return SynthSound( + id = id, + loops = loops, + delay = delay, + volume = volume, + rate = rate, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisPreloadSoundsDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisPreloadSoundsDecoder.kt new file mode 100644 index 00000000..e5d11e07 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisPreloadSoundsDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.VorbisPreloadSounds +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VorbisPreloadSoundsDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VORBIS_PRELOAD_SOUNDS + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VorbisPreloadSounds { + val id = buffer.g4() + return VorbisPreloadSounds( + id = id, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundDecoder.kt new file mode 100644 index 00000000..6d8f5537 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundDecoder.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.VorbisSound +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VorbisSoundDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VORBIS_SOUND + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VorbisSound { + val soundId = buffer.g4() + val loops = buffer.g1() + val delay = buffer.g2() + val volume = buffer.g1() + val pitch = buffer.g2() + return VorbisSound( + soundId, + loops, + delay, + volume, + pitch, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundGroupDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundGroupDecoder.kt new file mode 100644 index 00000000..460c2da4 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundGroupDecoder.kt @@ -0,0 +1,32 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.VorbisSoundGroup +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VorbisSoundGroupDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VORBIS_SOUND_GROUP + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VorbisSoundGroup { + val id = buffer.g4() + val loops = buffer.g1() + val delay = buffer.g2() + val volume = buffer.g1() + val rate = buffer.g2() + val group = buffer.g2() + return VorbisSoundGroup( + id = id, + loops = loops, + delay = delay, + volume = volume, + rate = rate, + group = group, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundGroupStartDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundGroupStartDecoder.kt new file mode 100644 index 00000000..8f25d902 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundGroupStartDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.VorbisSoundGroupStart +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VorbisSoundGroupStartDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VORBIS_SOUND_GROUP_START + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VorbisSoundGroupStart { + val group = buffer.g2() + return VorbisSoundGroupStart( + group = group, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundGroupStopDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundGroupStopDecoder.kt new file mode 100644 index 00000000..a2cf35c5 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSoundGroupStopDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.VorbisSoundGroupStop +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VorbisSoundGroupStopDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VORBIS_SOUND_GROUP_STOP + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VorbisSoundGroupStop { + val group = buffer.g2() + return VorbisSoundGroupStop( + group = group, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSpeechSoundDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSpeechSoundDecoder.kt new file mode 100644 index 00000000..3a1563a6 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSpeechSoundDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.VorbisSpeechSound +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VorbisSpeechSoundDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VORBIS_SPEECH_SOUND + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VorbisSpeechSound { + val id = buffer.g4() + val loops = buffer.g1() + val delay = buffer.g2() + val volume = buffer.g1() + return VorbisSpeechSound( + id = id, + loops = loops, + delay = delay, + volume = volume, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSpeechStopDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSpeechStopDecoder.kt new file mode 100644 index 00000000..4f9bd936 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/sound/VorbisSpeechStopDecoder.kt @@ -0,0 +1,19 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.sound.VorbisSpeechStop +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VorbisSpeechStopDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VORBIS_SPEECH_STOP + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VorbisSpeechStop { + return VorbisSpeechStop + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/LocAnimSpecificDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/LocAnimSpecificDecoder.kt new file mode 100644 index 00000000..960e2f1f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/LocAnimSpecificDecoder.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.specific.LocAnimSpecific +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LocAnimSpecificDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOC_ANIM_SPECIFIC + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LocAnimSpecific { + val shapeRotation = buffer.g1Alt2() + // This fixed-size packet only carries the base location-shape encoding. + require(shapeRotation and 0x80 == 0) { "Extended location shape in fixed-size LOC_ANIM_SPECIFIC" } + val animation = buffer.g4Alt3() + val coordinate = buffer.g4Alt3() + val delay = buffer.g1() + return LocAnimSpecific( + shapeRotation, + delay, + animation, + coordinate, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/NpcAnimSpecificDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/NpcAnimSpecificDecoder.kt new file mode 100644 index 00000000..9f22ecce --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/NpcAnimSpecificDecoder.kt @@ -0,0 +1,32 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.specific.NpcAnimSpecific +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class NpcAnimSpecificDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.NPC_ANIM_SPECIFIC + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): NpcAnimSpecific { + val delay = buffer.g1Alt2() + val npc = buffer.g2Alt1() + val animation0 = buffer.g4Alt3() + val animation1 = buffer.g4Alt3() + val animation2 = buffer.g4Alt3() + val animation3 = buffer.g4Alt3() + return NpcAnimSpecific( + animation0, + animation1, + animation2, + animation3, + delay, + npc, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/NpcHeadiconSpecificDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/NpcHeadiconSpecificDecoder.kt new file mode 100644 index 00000000..8d878672 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/NpcHeadiconSpecificDecoder.kt @@ -0,0 +1,28 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.specific.NpcHeadiconSpecific +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class NpcHeadiconSpecificDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.NPC_HEADICON_SPECIFIC + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): NpcHeadiconSpecific { + val id = buffer.g4() + val slot = buffer.g1Alt3() + val spriteIndex = buffer.g2().toShort().toInt() + val npcIndex = buffer.g2Alt3() + return NpcHeadiconSpecific( + slot, + id, + npcIndex, + spriteIndex, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/NpcSaySpecificDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/NpcSaySpecificDecoder.kt new file mode 100644 index 00000000..2c614185 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/NpcSaySpecificDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.specific.NpcSaySpecific +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class NpcSaySpecificDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.NPC_SAY_SPECIFIC + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): NpcSaySpecific { + val colour = buffer.g1Alt1() + val effect = buffer.g1Alt3() + val npcIndex = buffer.g2Alt1() + val text = buffer.gjstr() + return NpcSaySpecific(text, colour, npcIndex, effect) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/PlayerAnimSpecificDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/PlayerAnimSpecificDecoder.kt new file mode 100644 index 00000000..ec7926cd --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/PlayerAnimSpecificDecoder.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.specific.PlayerAnimSpecific +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class PlayerAnimSpecificDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.PLAYER_ANIM_SPECIFIC + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): PlayerAnimSpecific { + val animation0 = buffer.g4Alt1() + val animation1 = buffer.g4Alt1() + val animation2 = buffer.g4Alt1() + val animation3 = buffer.g4Alt1() + val delay = buffer.g1Alt3() + return PlayerAnimSpecific( + delay, + animation0, + animation1, + animation2, + animation3, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/ProjAnimSpecificDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/ProjAnimSpecificDecoder.kt new file mode 100644 index 00000000..fb5ff9d6 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/ProjAnimSpecificDecoder.kt @@ -0,0 +1,50 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.specific.ProjAnimSpecific +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ProjAnimSpecificDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.PROJANIM_SPECIFIC + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ProjAnimSpecific { + val progress = buffer.g2Alt3() + val startHeight = buffer.g1Alt3().toByte().toInt() + val startZ = buffer.g2Alt1() + val level = buffer.g1Alt3() + val source = buffer.g3() + val angle = buffer.g1().let { if (it == 255) -1 else it } + val flags = buffer.g1() + val startX = buffer.g2Alt2() + val deltaZ = buffer.g1Alt3().toByte().toInt() + val endHeight = buffer.g1Alt2().toByte().toInt() + val target = buffer.g3() + val deltaX = buffer.g1Alt1().toByte().toInt() + val endTime = buffer.g2() + val startTime = buffer.g2Alt3() + val id = buffer.g2() + return ProjAnimSpecific( + progress = progress, + startHeight = startHeight, + startZ = startZ, + level = level, + source = source, + angle = angle, + flags = flags, + startX = startX, + deltaZ = deltaZ, + endHeight = endHeight, + target = target, + deltaX = deltaX, + endTime = endTime, + startTime = startTime, + id = id, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/ProjAnimSpecificV2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/ProjAnimSpecificV2Decoder.kt new file mode 100644 index 00000000..336911ca --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/ProjAnimSpecificV2Decoder.kt @@ -0,0 +1,55 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.specific.ProjAnimSpecificV2 +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ProjectileOffset +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ProjAnimSpecificV2Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.PROJANIM_SPECIFIC_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ProjAnimSpecificV2 { + val endTime = buffer.g2Alt3() + val deltaZ = buffer.g1Alt1().toByte().toInt() + val startX = buffer.g2Alt1() + val endOffset = buffer.g3() + val angle = buffer.g1Alt2().let { if (it == 255) -1 else it } + val startHeight = buffer.g2sAlt1() + val flags = buffer.g1() + val target = buffer.g3Alt1() + val startZ = buffer.g2Alt2() + val deltaX = buffer.g1Alt3().toByte().toInt() + val id = buffer.g2Alt1() + val source = buffer.g3Alt2() + val level = buffer.g1Alt3() + val startTime = buffer.g2Alt1() + val endHeight = buffer.g2sAlt3() + val progress = buffer.g2() + val startOffset = buffer.g3Alt2() + return ProjAnimSpecificV2( + endTime = endTime, + deltaZ = deltaZ, + startX = startX, + endOffset = ProjectileOffset(endOffset), + angle = angle, + startHeight = startHeight, + flags = flags, + target = target, + startZ = startZ, + deltaX = deltaX, + id = id, + source = source, + level = level, + startTime = startTime, + endHeight = endHeight, + progress = progress, + startOffset = ProjectileOffset(startOffset), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/SpotanimSpecificDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/SpotanimSpecificDecoder.kt new file mode 100644 index 00000000..04f31b3f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/SpotanimSpecificDecoder.kt @@ -0,0 +1,32 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.specific.SpotanimSpecific +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SpotanimSpecificDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SPOTANIM_SPECIFIC + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SpotanimSpecific { + val packedDelay = buffer.g2Alt2() + val id = buffer.g2().let { if (it == 65535) -1 else it } + val target = buffer.g4() + val height = buffer.g2s() + val rotationFlags = buffer.g1() + val slot = buffer.g1Alt3() + return SpotanimSpecific( + height, + packedDelay, + rotationFlags, + target, + id, + slot, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/SpotanimSpecificV2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/SpotanimSpecificV2Decoder.kt new file mode 100644 index 00000000..570239d7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/specific/SpotanimSpecificV2Decoder.kt @@ -0,0 +1,35 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.specific.SpotanimSpecificV2 +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ProjectileOffset +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SpotanimSpecificV2Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SPOTANIM_SPECIFIC_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SpotanimSpecificV2 { + val packedDelay = buffer.g2Alt2() + val id = buffer.g2Alt1().let { if (it == 65535) -1 else it } + val offset = ProjectileOffset(buffer.g3()) + val height = buffer.g2sAlt2() + val target = buffer.g4Alt1() + val slot = buffer.g1Alt3() + val rotationFlags = buffer.g1Alt1() + return SpotanimSpecificV2( + target, + rotationFlags, + offset, + slot, + height, + id, + packedDelay, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryClearGridValueDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryClearGridValueDecoder.kt new file mode 100644 index 00000000..2b7f5e9c --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryClearGridValueDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryClearGridValue +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryClearGridValueDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_CLEAR_GRID_VALUE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryClearGridValue { + val group = buffer.g1Alt2() + val column = buffer.g1Alt2() + val row = buffer.g1Alt2() + return TelemetryClearGridValue( + group, + column, + row, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridAddColumnDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridAddColumnDecoder.kt new file mode 100644 index 00000000..75babc28 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridAddColumnDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryGridAddColumn +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryGridAddColumnDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_GRID_ADD_COLUMN + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryGridAddColumn { + val group = buffer.g1Alt1() + val id = buffer.g4() + val index = buffer.g1Alt3() + return TelemetryGridAddColumn( + group, + id, + index, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridAddGroupDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridAddGroupDecoder.kt new file mode 100644 index 00000000..a59247c0 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridAddGroupDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryGridAddGroup +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryGridAddGroupDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_GRID_ADD_GROUP + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryGridAddGroup { + val index = buffer.g1() + val id = buffer.g4Alt1() + return TelemetryGridAddGroup( + id, + index, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridAddRowDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridAddRowDecoder.kt new file mode 100644 index 00000000..1f33c803 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridAddRowDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryGridAddRow +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryGridAddRowDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_GRID_ADD_ROW + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryGridAddRow { + val id = buffer.g4Alt3() + val index = buffer.g1Alt2() + val group = buffer.g1Alt3() + return TelemetryGridAddRow( + group, + id, + index, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridFullDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridFullDecoder.kt new file mode 100644 index 00000000..3a520e2a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridFullDecoder.kt @@ -0,0 +1,48 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryGridFull +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryGridFullDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_GRID_FULL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryGridFull { + val groupCount = buffer.g1() + require(groupCount <= buffer.readableBytes() / 6) { "Truncated telemetry group headers" } + val groups = + List(groupCount) { + val id = buffer.g4() + val rowCount = buffer.g1() + require(rowCount <= 40 && rowCount <= buffer.readableBytes() / 4) { "Invalid telemetry row count" } + val rowIds = List(rowCount) { buffer.g4() } + val columnCount = buffer.g1() + require( + columnCount <= 8 && columnCount <= buffer.readableBytes() / 4, + ) { "Invalid telemetry column count" } + val columnIds = List(columnCount) { buffer.g4() } + require(rowIds.distinct().size == rowCount && columnIds.distinct().size == columnCount) { + "Duplicate telemetry row/column key" + } + val rows = + List(rowCount) { + val pin = buffer.g1s() + val cells = + List(columnCount) { + val present = buffer.g1() + val value = if (present != 0) buffer.g4() else null + TelemetryGridFull.Cell(present, value) + } + TelemetryGridFull.Row(pin, cells) + } + TelemetryGridFull.Group(id, rowIds, columnIds, rows) + } + return TelemetryGridFull(groups) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridMoveColumnDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridMoveColumnDecoder.kt new file mode 100644 index 00000000..ea1aed06 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridMoveColumnDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryGridMoveColumn +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryGridMoveColumnDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_GRID_MOVE_COLUMN + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryGridMoveColumn { + val group = buffer.g1Alt3() + val source = buffer.g1Alt3() + val destination = buffer.g1() + return TelemetryGridMoveColumn( + source, + group, + destination, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridMoveRowDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridMoveRowDecoder.kt new file mode 100644 index 00000000..9cd3a6d8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridMoveRowDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryGridMoveRow +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryGridMoveRowDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_GRID_MOVE_ROW + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryGridMoveRow { + val destination = buffer.g1Alt2() + val group = buffer.g1Alt1() + val source = buffer.g1Alt2() + return TelemetryGridMoveRow( + group, + source, + destination, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridRemoveColumnDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridRemoveColumnDecoder.kt new file mode 100644 index 00000000..49b7566d --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridRemoveColumnDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryGridRemoveColumn +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryGridRemoveColumnDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_GRID_REMOVE_COLUMN + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryGridRemoveColumn { + val group = buffer.g1Alt2() + val column = buffer.g1Alt1() + return TelemetryGridRemoveColumn( + column, + group, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridRemoveGroupDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridRemoveGroupDecoder.kt new file mode 100644 index 00000000..b2804cdf --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridRemoveGroupDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryGridRemoveGroup +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryGridRemoveGroupDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_GRID_REMOVE_GROUP + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryGridRemoveGroup { + val group = buffer.g1Alt3() + return TelemetryGridRemoveGroup( + group, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridRemoveRowDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridRemoveRowDecoder.kt new file mode 100644 index 00000000..eb74d919 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridRemoveRowDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryGridRemoveRow +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryGridRemoveRowDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_GRID_REMOVE_ROW + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryGridRemoveRow { + val row = buffer.g1() + val group = buffer.g1Alt2() + return TelemetryGridRemoveRow( + group, + row, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridSetRowPinnedDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridSetRowPinnedDecoder.kt new file mode 100644 index 00000000..167be6d8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridSetRowPinnedDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryGridSetRowPinned +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryGridSetRowPinnedDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_GRID_SET_ROW_PINNED + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryGridSetRowPinned { + val group = buffer.g1Alt2() + val row = buffer.g1() + val enabled = buffer.g1Alt2() == 1 + return TelemetryGridSetRowPinned( + group, + row, + enabled, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridValuesDeltaDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridValuesDeltaDecoder.kt new file mode 100644 index 00000000..620371f7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/telemetry/TelemetryGridValuesDeltaDecoder.kt @@ -0,0 +1,40 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.telemetry.TelemetryGridValuesDelta +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TelemetryGridValuesDeltaDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TELEMETRY_GRID_VALUES_DELTA + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TelemetryGridValuesDelta { + val groups = mutableListOf() + while (true) { + val group = buffer.g1s() + if (group == -1) break + require(group >= 0) { "Invalid telemetry group index $group" } + val rows = mutableListOf() + while (true) { + val row = buffer.g1s() + if (row == -1) break + require(row >= 0) { "Invalid telemetry row index $row" } + val cells = mutableListOf() + while (true) { + val column = buffer.g1s() + if (column == -1) break + require(column >= 0) { "Invalid telemetry column index $column" } + cells += TelemetryGridValuesDelta.Cell(column, buffer.g4()) + } + rows += TelemetryGridValuesDelta.Row(row, cells) + } + groups += TelemetryGridValuesDelta.Group(group, rows) + } + return TelemetryGridValuesDelta(groups) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varbit/VarbitDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varbit/VarbitDecoder.kt new file mode 100644 index 00000000..26b97229 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varbit/VarbitDecoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varbit + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varbit.Varbit +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.gVarIntLE +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo.updateNpcMorphVarbit +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarbitDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VARBIT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): Varbit { + val id = buffer.gVarIntLE() + val value = buffer.gVarIntLE() + session.updateNpcMorphVarbit(id, value) + return Varbit( + id = id, + value = value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varbit/VarbitLargeDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varbit/VarbitLargeDecoder.kt new file mode 100644 index 00000000..ef7d1579 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varbit/VarbitLargeDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varbit + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varbit.VarbitLarge +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo.updateNpcMorphVarbit +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarbitLargeDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VARBIT_LARGE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarbitLarge { + val id = buffer.g2Alt1() + val value = buffer.g4() + session.updateNpcMorphVarbit(id, value) + return VarbitLarge( + id, + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varbit/VarbitSmallDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varbit/VarbitSmallDecoder.kt new file mode 100644 index 00000000..8691217f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varbit/VarbitSmallDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varbit + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varbit.VarbitSmall +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo.updateNpcMorphVarbit +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarbitSmallDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VARBIT_SMALL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarbitSmall { + val value = buffer.g1Alt2() + val id = buffer.g2Alt3() + session.updateNpcMorphVarbit(id, value) + return VarbitSmall( + id, + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/ResetClientVarcacheDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/ResetClientVarcacheDecoder.kt new file mode 100644 index 00000000..daa13f29 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/ResetClientVarcacheDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprot.protocol.metadata.Consistent +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varc.ResetClientVarcache +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo.npcMorphVariables +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +@Consistent +internal class ResetClientVarcacheDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.RESET_CLIENT_VARCACHE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ResetClientVarcache { + session.npcMorphVariables().clear() + return ResetClientVarcache + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcBitDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcBitDecoder.kt new file mode 100644 index 00000000..0a3e16d8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcBitDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varc.VarcBit +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.gVarIntLE +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarcBitDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLIENT_SETVARCBIT + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarcBit { + val id = buffer.gVarIntLE() + val value = buffer.gVarIntLE() + return VarcBit( + id = id, + value = value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcBitLargeDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcBitLargeDecoder.kt new file mode 100644 index 00000000..f9e823f7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcBitLargeDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varc.VarcBitLarge +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarcBitLargeDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLIENT_SETVARCBIT_LARGE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarcBitLarge { + val id = buffer.g2Alt2() + val value = buffer.g4Alt1() + return VarcBitLarge( + id, + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcBitSmallDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcBitSmallDecoder.kt new file mode 100644 index 00000000..e774bdc5 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcBitSmallDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varc.VarcBitSmall +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarcBitSmallDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLIENT_SETVARCBIT_SMALL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarcBitSmall { + val id = buffer.g2Alt3() + val value = buffer.g1sAlt3() + return VarcBitSmall( + id, + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcLargeDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcLargeDecoder.kt new file mode 100644 index 00000000..bcfcb15e --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcLargeDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varc.VarcLarge +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarcLargeDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLIENT_SETVARC_LARGE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarcLarge { + val value = buffer.g4() + val id = buffer.g2Alt2() + return VarcLarge( + id, + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcLongDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcLongDecoder.kt new file mode 100644 index 00000000..e938acda --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcLongDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varc.VarcLong +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarcLongDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLIENT_SETVARC_LONG + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarcLong { + val high = buffer.g4Alt2().toLong() and 0xFFFF_FFFFL + val low = buffer.g4Alt2().toLong() and 0xFFFF_FFFFL + val value = (high shl 32) or low + val id = buffer.g2Alt3() + return VarcLong( + id, + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcSmallDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcSmallDecoder.kt new file mode 100644 index 00000000..b3e776f9 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcSmallDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varc.VarcSmall +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarcSmallDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLIENT_SETVARC_SMALL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarcSmall { + val id = buffer.g2Alt1() + // Native sign-extends after the byte negation, including 0x80 -> -128. + val value = buffer.g1Alt2().toByte().toInt() + return VarcSmall( + id, + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcStrLargeDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcStrLargeDecoder.kt new file mode 100644 index 00000000..35cef17b --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcStrLargeDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varc.VarcStrLarge +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarcStrLargeDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLIENT_SETVARCSTR_LARGE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarcStrLarge { + val id = buffer.g2() + val value = buffer.gjstr() + return VarcStrLarge( + id = id, + value = value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcStrSmallDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcStrSmallDecoder.kt new file mode 100644 index 00000000..9ff509a1 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varc/VarcStrSmallDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varc.VarcStrSmall +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarcStrSmallDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.CLIENT_SETVARCSTR_SMALL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarcStrSmall { + val value = buffer.gjstr() + val id = buffer.g2() + return VarcStrSmall( + id, + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varclan/VarclanDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varclan/VarclanDecoder.kt new file mode 100644 index 00000000..73a1c24e --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varclan/VarclanDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varclan + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.cache.api.rs3.Rs3VariableDomain +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varclan.Varclan +import net.rsprox.protocol.rs3v950beta.cache.readTypedVariable +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarclanDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VARCLAN + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): Varclan { + val variable = buffer.readTypedVariable(session, Rs3VariableDomain.CLAN) + return Varclan(variable.id, variable) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varclan/VarclanDisableDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varclan/VarclanDisableDecoder.kt new file mode 100644 index 00000000..663f0758 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varclan/VarclanDisableDecoder.kt @@ -0,0 +1,17 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varclan + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varclan.VarclanDisable +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarclanDisableDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VARCLAN_DISABLE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarclanDisable = VarclanDisable +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varclan/VarclanEnableDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varclan/VarclanEnableDecoder.kt new file mode 100644 index 00000000..6f067b1a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varclan/VarclanEnableDecoder.kt @@ -0,0 +1,17 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varclan + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varclan.VarclanEnable +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarclanEnableDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VARCLAN_ENABLE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarclanEnable = VarclanEnable +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varp/VarpLargeDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varp/VarpLargeDecoder.kt new file mode 100644 index 00000000..42d90844 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varp/VarpLargeDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varp + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varp.VarpLarge +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo.npcMorphVariables +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarpLargeDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VARP_LARGE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarpLarge { + val value = buffer.g4Alt2() + val id = buffer.g2() + session.npcMorphVariables().set(id, value) + return VarpLarge( + id, + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varp/VarpLongDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varp/VarpLongDecoder.kt new file mode 100644 index 00000000..45df8efa --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varp/VarpLongDecoder.kt @@ -0,0 +1,26 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varp + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varp.VarpLong +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarpLongDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VARP_LONG + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarpLong { + val high = buffer.g4Alt3().toLong() and 0xFFFF_FFFFL + val low = buffer.g4Alt3().toLong() and 0xFFFF_FFFFL + val value = (high shl 32) or low + val id = buffer.g2Alt1() + return VarpLong( + id, + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varp/VarpSmallDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varp/VarpSmallDecoder.kt new file mode 100644 index 00000000..c13f7efb --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/varp/VarpSmallDecoder.kt @@ -0,0 +1,27 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varp + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.varp.VarpSmall +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo.npcMorphVariables +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class VarpSmallDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.VARP_SMALL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): VarpSmall { + // Native sign-extends after the byte negation, including 0x80 -> -128. + val value = buffer.g1Alt2().toByte().toInt() + val id = buffer.g2Alt1() + session.npcMorphVariables().set(id, value) + return VarpSmall( + id, + value, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/world/WorldlistFetchReplyDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/world/WorldlistFetchReplyDecoder.kt new file mode 100644 index 00000000..5506e318 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/world/WorldlistFetchReplyDecoder.kt @@ -0,0 +1,107 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.world + +import io.netty.buffer.Unpooled +import net.rsprot.buffer.JagByteBuf +import net.rsprot.buffer.extensions.toJagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.world.WorldlistFetchReply +import net.rsprox.protocol.rs3.game.outgoing.model.world.WorldlistFetchReply.Country +import net.rsprox.protocol.rs3.game.outgoing.model.world.WorldlistFetchReply.Definitions +import net.rsprox.protocol.rs3.game.outgoing.model.world.WorldlistFetchReply.MarkedString +import net.rsprox.protocol.rs3.game.outgoing.model.world.WorldlistFetchReply.Population +import net.rsprox.protocol.rs3.game.outgoing.model.world.WorldlistFetchReply.Reply +import net.rsprox.protocol.rs3.game.outgoing.model.world.WorldlistFetchReply.World +import net.rsprox.protocol.rs3v950beta.buffer.readNativeString +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session +import net.rsprox.protocol.session.attribute + +internal class WorldlistFetchReplyDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.WORLDLIST_FETCH_REPLY + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): WorldlistFetchReply { + val completeFlag = buffer.g1() + val previous = session.pendingWorldList ?: byteArrayOf() + val chunkLength = buffer.readableBytes() + require(previous.size + chunkLength <= 20_000) { + "World list exceeds the native 20000-byte accumulator; refusing to silently discard its tail" + } + val accumulated = previous.copyOf(previous.size + chunkLength) + // This is the protocol's chunk payload, not a snapshot of already decoded packet bytes. + buffer.buffer.readBytes(accumulated, previous.size, chunkLength) + if (completeFlag != 1) { + session.pendingWorldList = accumulated + return WorldlistFetchReply(completeFlag, chunkLength, accumulated.size, null) + } + session.pendingWorldList = null + val input = Unpooled.wrappedBuffer(accumulated) + try { + val data = input.toJagByteBuf() + // TODO(beta): Native chunk envelope is verified; audit the reused live-950 nested list parser separately. + val version = data.g1() + require(version == 2) { "Unsupported world-list version $version" } + val definitionsFlag = data.g1() + val definitions = if (definitionsFlag == 1) readDefinitions(data) else null + val worldCount = definitions?.worlds?.size ?: session.worldListCount + // The client can already have definitions from before this proxy session. + // A completed reply still frames its population records; keep their relative indices. + val populations = + buildList { + while (data.readableBytes() > 0 && (worldCount == null || size < worldCount)) { + require(data.readableBytes() >= 3) { "Truncated world population record" } + val index = data.gSmart1or2() + require(data.readableBytes() >= 2) { "Truncated world population value" } + val population = data.g2() + add(Population(index, if (population == 65535) -1 else population)) + } + } + require(worldCount == null || populations.size == worldCount) { "Truncated world populations" } + require(data.readableBytes() == 0) { "Unexpected bytes after world list" } + session.worldListCount = worldCount + return WorldlistFetchReply( + completeFlag, + chunkLength, + accumulated.size, + Reply(version, definitionsFlag, definitions, populations), + ) + } finally { + input.release() + } + } + + private fun readDefinitions(buffer: JagByteBuf): Definitions { + val countryCount = buffer.gSmart1or2() + require(countryCount <= buffer.readableBytes() / 2) { "Truncated world countries" } + val countries = List(countryCount) { Country(buffer.gSmart1or2(), readString(buffer)) } + val minimumWorldId = buffer.gSmart1or2() + val maximumWorldId = buffer.gSmart1or2() + val worldCount = buffer.gSmart1or2() + require(worldCount <= buffer.readableBytes() / 9) { "Truncated world definitions" } + val worlds = + List(worldCount) { + val index = buffer.gSmart1or2() + val countryIndex = buffer.g1() + val properties = buffer.g4() + val extraId = buffer.gSmart1or2() + val extraName = if (extraId != 0) readString(buffer) else null + val activity = readString(buffer) + val hostname = readString(buffer) + World(index, countryIndex, properties, extraId, extraName, activity, hostname) + } + return Definitions(countries, minimumWorldId, maximumWorldId, worlds, buffer.g4()) + } + + private fun readString(buffer: JagByteBuf): MarkedString { + val marker = buffer.g1() + return MarkedString(marker, if (marker == 0) buffer.readNativeString() else null) + } + + private companion object { + private var Session.pendingWorldList: ByteArray? by attribute() + private var Session.worldListCount: Int? by attribute() + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/header/UpdateZoneFullFollowsDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/header/UpdateZoneFullFollowsDecoder.kt new file mode 100644 index 00000000..252fcd66 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/header/UpdateZoneFullFollowsDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.header + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.header.UpdateZoneFullFollows +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateZoneFullFollowsDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_ZONE_FULL_FOLLOWS + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateZoneFullFollows { + val zoneZ = buffer.g1Alt2().toByte().toInt() + val zoneX = buffer.g1Alt1().toByte().toInt() + val level = buffer.g1Alt2() + return UpdateZoneFullFollows(level, zoneX, zoneZ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/header/UpdateZonePartialEnclosedDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/header/UpdateZonePartialEnclosedDecoder.kt new file mode 100644 index 00000000..c2b6fbfe --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/header/UpdateZonePartialEnclosedDecoder.kt @@ -0,0 +1,82 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.header + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.game.outgoing.model.IncomingServerGameMessage +import net.rsprox.protocol.rs3.game.outgoing.model.zone.header.UpdateZonePartialEnclosed +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.LocAddChangeDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.LocAnimDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.LocCustomiseDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.LocDelDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.LocPrefetchDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapAnimV1Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapAnimV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapProjAnimDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapProjAnimHalfsqDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapProjAnimHalfsqV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapProjAnimV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.ObjAddV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.ObjAddV3Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.ObjCountV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.ObjCountV3Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.ObjDelDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.ObjRevealDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.ObjRevealV3Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.SoundAreaV1Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.SoundAreaV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateZonePartialEnclosedDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_ZONE_PARTIAL_ENCLOSED + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateZonePartialEnclosed { + val zoneX = buffer.g1Alt2().toByte().toInt() + val zoneZ = buffer.g1Alt1().toByte().toInt() + val level = buffer.g1Alt1() + val packets = + buildList { + while (buffer.isReadable) { + val selector = buffer.g1() + val decoder = + requireNotNull(decoders[selector]) { + "Unverified or invalid revision 950-beta zone selector $selector at byte ${buffer.buffer.readerIndex() - 1}" + } + add(decoder.decode(buffer, session) as IncomingServerGameMessage) + } + } + return UpdateZonePartialEnclosed(level, zoneX, zoneZ, packets) + } + + private companion object { + // Add only beta-verified routes; never fall back to live-950 selector ordering. + val decoders: Map> = + mapOf( + 0 to LocAnimDecoder(), + 1 to MapProjAnimV2Decoder(), + 2 to MapProjAnimDecoder(), + 3 to LocPrefetchDecoder(), + 4 to ObjDelDecoder(), + 5 to ObjAddV3Decoder(), + 6 to MapProjAnimHalfsqV2Decoder(), + 7 to MapAnimV1Decoder(), + 8 to SoundAreaV1Decoder(), + 9 to SoundAreaV2Decoder(), + 10 to LocCustomiseDecoder(), + 11 to ObjCountV2Decoder(), + 12 to ObjCountV3Decoder(), + 13 to LocDelDecoder(), + 14 to ObjRevealDecoder(), + 15 to LocPrefetchDecoder(), + 16 to ObjRevealV3Decoder(), + 17 to LocAddChangeDecoder(), + 18 to MapProjAnimHalfsqDecoder(), + 19 to MapAnimV2Decoder(), + 20 to ObjAddV2Decoder(), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/header/UpdateZonePartialFollowsDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/header/UpdateZonePartialFollowsDecoder.kt new file mode 100644 index 00000000..2f670352 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/header/UpdateZonePartialFollowsDecoder.kt @@ -0,0 +1,22 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.header + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.header.UpdateZonePartialFollows +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class UpdateZonePartialFollowsDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.UPDATE_ZONE_PARTIAL_FOLLOWS + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): UpdateZonePartialFollows { + val zoneX = buffer.g1Alt1().toByte().toInt() + val zoneZ = buffer.g1Alt1().toByte().toInt() + val level = buffer.g1Alt1() + return UpdateZonePartialFollows(level, zoneX, zoneZ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocAddChangeDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocAddChangeDecoder.kt new file mode 100644 index 00000000..75ad94bd --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocAddChangeDecoder.kt @@ -0,0 +1,102 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.LocAddChange +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LocAddChangeDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOC_ADD_CHANGE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LocAddChange { + val packedCoord = buffer.g1Alt2() + val zInZone = packedCoord and 0x7 + val xInZone = (packedCoord ushr 4) and 0x7 + + val locId = buffer.g4Alt3() + + val shapeRotationByte = buffer.g1Alt2() + val shape = (shapeRotationByte ushr 2) and 0x1F + val rotation = shapeRotationByte and 0x3 + val hasExtendedTransform = (shapeRotationByte and 0x80) != 0 + + var rotationX = 0f + var rotationY = 0f + var rotationZ = 0f + var rotationW = 1f + var translationX = 0f + var translationY = 0f + var translationZ = 0f + var scaleX = 1f + var scaleY = 1f + var scaleZ = 1f + + if (hasExtendedTransform) { + val innerFlags = buffer.g1() + if ((innerFlags and 0x1) != 0) { + val a = buffer.g2s() + val b = buffer.g2s() + val c = buffer.g2s() + val d = buffer.g2s() + rotationX = -(a * ROTATION_SCALE) + rotationY = b * ROTATION_SCALE + rotationZ = -(c * ROTATION_SCALE) + rotationW = d * ROTATION_SCALE + } + if ((innerFlags and 0x2) != 0) { + translationX = buffer.g2s().toFloat() + } + if ((innerFlags and 0x4) != 0) { + translationY = -(buffer.g2s().toFloat()) + } + if ((innerFlags and 0x8) != 0) { + translationZ = buffer.g2s().toFloat() + } + if ((innerFlags and 0x10) != 0) { + val uniform = buffer.g2s() * SCALE_SCALE + scaleX = uniform + scaleY = uniform + scaleZ = uniform + } else { + if ((innerFlags and 0x20) != 0) { + scaleX = buffer.g2s() * SCALE_SCALE + } + if ((innerFlags and 0x40) != 0) { + scaleY = buffer.g2s() * SCALE_SCALE + } + if ((innerFlags and 0x80) != 0) { + scaleZ = buffer.g2s() * SCALE_SCALE + } + } + } + + return LocAddChange( + locId, + shape, + rotation, + xInZone, + zInZone, + hasExtendedTransform, + rotationX, + rotationY, + rotationZ, + rotationW, + translationX, + translationY, + translationZ, + scaleX, + scaleY, + scaleZ, + ) + } + + private companion object { + const val ROTATION_SCALE = 3.0517578e-05f + const val SCALE_SCALE = 0.0078125f + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocAnimDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocAnimDecoder.kt new file mode 100644 index 00000000..13ed5e83 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocAnimDecoder.kt @@ -0,0 +1,103 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.LocAnim +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LocAnimDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOC_ANIM + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LocAnim { + val id = buffer.g4() + val delay = buffer.g1Alt2() + val packedCoord = buffer.g1() + val shapeRot = buffer.g1Alt3() + val shape = (shapeRot ushr 2) and 0x1F + val rotation = shapeRot and 0x3 + val zInZone = packedCoord and 0x7 + val xInZone = (packedCoord ushr 4) and 0x7 + + // Extensions follow all seven base bytes, not the shape byte itself. + val hasExtendedTransform = shapeRot and 0x80 != 0 + var rotationX = 0f + var rotationY = 0f + var rotationZ = 0f + var rotationW = 1f + var translationX = 0f + var translationY = 0f + var translationZ = 0f + var scaleX = 1f + var scaleY = 1f + var scaleZ = 1f + + if (hasExtendedTransform) { + val innerFlags = buffer.g1() + if ((innerFlags and 0x1) != 0) { + val a = buffer.g2s() + val b = buffer.g2s() + val c = buffer.g2s() + val d = buffer.g2s() + rotationX = -(a * ROTATION_SCALE) + rotationY = b * ROTATION_SCALE + rotationZ = -(c * ROTATION_SCALE) + rotationW = d * ROTATION_SCALE + } + if ((innerFlags and 0x2) != 0) { + translationX = buffer.g2s().toFloat() + } + if ((innerFlags and 0x4) != 0) { + translationY = -(buffer.g2s().toFloat()) + } + if ((innerFlags and 0x8) != 0) { + translationZ = buffer.g2s().toFloat() + } + if ((innerFlags and 0x10) != 0) { + val uniform = buffer.g2s() * SCALE_SCALE + scaleX = uniform + scaleY = uniform + scaleZ = uniform + } else { + if ((innerFlags and 0x20) != 0) { + scaleX = buffer.g2s() * SCALE_SCALE + } + if ((innerFlags and 0x40) != 0) { + scaleY = buffer.g2s() * SCALE_SCALE + } + if ((innerFlags and 0x80) != 0) { + scaleZ = buffer.g2s() * SCALE_SCALE + } + } + } + + return LocAnim( + id, + xInZone, + zInZone, + shape, + rotation, + delay, + hasExtendedTransform, + rotationX, + rotationY, + rotationZ, + rotationW, + translationX, + translationY, + translationZ, + scaleX, + scaleY, + scaleZ, + ) + } + + private companion object { + const val ROTATION_SCALE = 3.0517578e-05f + const val SCALE_SCALE = 0.0078125f + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocCustomiseDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocCustomiseDecoder.kt new file mode 100644 index 00000000..d2c610b7 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocCustomiseDecoder.kt @@ -0,0 +1,123 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.LocCustomise +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LocCustomiseDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOC_CUSTOMISE + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LocCustomise { + val flagsByte = buffer.g1() + val coordByte = buffer.g1Alt3() + val shapeRotationByte = buffer.g1() + val locId = buffer.g4Alt3() + val zInZone = coordByte and 0x7 + val xInZone = (coordByte ushr 4) and 0x7 + val shape = (shapeRotationByte ushr 2) and 0x1F + val rotation = shapeRotationByte and 0x3 + + val hasExtendedTransform = (shapeRotationByte and 0x80) != 0 + var rotationX = 0f + var rotationY = 0f + var rotationZ = 0f + var rotationW = 1f + var translationX = 0f + var translationY = 0f + var translationZ = 0f + var scaleX = 1f + var scaleY = 1f + var scaleZ = 1f + if (hasExtendedTransform) { + val innerFlags = buffer.g1() + if ((innerFlags and 0x1) != 0) { + val a = buffer.g2s() + val b = buffer.g2s() + val c = buffer.g2s() + val d = buffer.g2s() + rotationX = -(a * ROTATION_SCALE) + rotationY = b * ROTATION_SCALE + rotationZ = -(c * ROTATION_SCALE) + rotationW = d * ROTATION_SCALE + } + if ((innerFlags and 0x2) != 0) { + translationX = buffer.g2s().toFloat() + } + if ((innerFlags and 0x4) != 0) { + translationY = -(buffer.g2s().toFloat()) + } + if ((innerFlags and 0x8) != 0) { + translationZ = buffer.g2s().toFloat() + } + if ((innerFlags and 0x10) != 0) { + val uniform = buffer.g2s() * SCALE_SCALE + scaleX = uniform + scaleY = uniform + scaleZ = uniform + } else { + if ((innerFlags and 0x20) != 0) { + scaleX = buffer.g2s() * SCALE_SCALE + } + if ((innerFlags and 0x40) != 0) { + scaleY = buffer.g2s() * SCALE_SCALE + } + if ((innerFlags and 0x80) != 0) { + scaleZ = buffer.g2s() * SCALE_SCALE + } + } + } + + var models: IntArray? = null + var recolours: IntArray? = null + var retextures: IntArray? = null + + if ((flagsByte and 0x1) == 0) { + if ((flagsByte and 0x2) != 0) { + val count = buffer.g1() + models = IntArray(count) { buffer.g4() } + } + if ((flagsByte and 0x4) != 0) { + val count = buffer.g1() + recolours = IntArray(count) { buffer.g2() } + } + if ((flagsByte and 0x8) != 0) { + val count = buffer.g1() + retextures = IntArray(count) { buffer.g2() } + } + } + + return LocCustomise( + locId, + xInZone, + zInZone, + shape, + rotation, + hasExtendedTransform, + rotationX, + rotationY, + rotationZ, + rotationW, + translationX, + translationY, + translationZ, + scaleX, + scaleY, + scaleZ, + models, + recolours, + retextures, + flagsByte, + ) + } + + private companion object { + const val ROTATION_SCALE = 3.0517578e-05f + const val SCALE_SCALE = 0.0078125f + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocDelDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocDelDecoder.kt new file mode 100644 index 00000000..0158817a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocDelDecoder.kt @@ -0,0 +1,99 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.LocDel +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LocDelDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOC_DEL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LocDel { + val shapeRotationByte = buffer.g1Alt2() + val packedCoord = buffer.g1Alt2() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + val shape = (shapeRotationByte ushr 2) and 0x1F + val rotation = shapeRotationByte and 0x3 + // The shared native shape reader also accepts an extension in enclosed updates. + // Standalone framing stays two bytes; an incomplete extension must fail normally. + val hasExtendedTransform = shapeRotationByte and 0x80 != 0 + var rotationX = 0f + var rotationY = 0f + var rotationZ = 0f + var rotationW = 1f + var translationX = 0f + var translationY = 0f + var translationZ = 0f + var scaleX = 1f + var scaleY = 1f + var scaleZ = 1f + + if (hasExtendedTransform) { + val innerFlags = buffer.g1() + if ((innerFlags and 0x1) != 0) { + val a = buffer.g2s() + val b = buffer.g2s() + val c = buffer.g2s() + val d = buffer.g2s() + rotationX = -(a * ROTATION_SCALE) + rotationY = b * ROTATION_SCALE + rotationZ = -(c * ROTATION_SCALE) + rotationW = d * ROTATION_SCALE + } + if ((innerFlags and 0x2) != 0) { + translationX = buffer.g2s().toFloat() + } + if ((innerFlags and 0x4) != 0) { + translationY = -(buffer.g2s().toFloat()) + } + if ((innerFlags and 0x8) != 0) { + translationZ = buffer.g2s().toFloat() + } + if ((innerFlags and 0x10) != 0) { + val uniform = buffer.g2s() * SCALE_SCALE + scaleX = uniform + scaleY = uniform + scaleZ = uniform + } else { + if ((innerFlags and 0x20) != 0) { + scaleX = buffer.g2s() * SCALE_SCALE + } + if ((innerFlags and 0x40) != 0) { + scaleY = buffer.g2s() * SCALE_SCALE + } + if ((innerFlags and 0x80) != 0) { + scaleZ = buffer.g2s() * SCALE_SCALE + } + } + } + + return LocDel( + xInZone, + zInZone, + shape, + rotation, + hasExtendedTransform, + rotationX, + rotationY, + rotationZ, + rotationW, + translationX, + translationY, + translationZ, + scaleX, + scaleY, + scaleZ, + ) + } + + private companion object { + const val ROTATION_SCALE = 3.0517578e-05f + const val SCALE_SCALE = 0.0078125f + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocPrefetchDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocPrefetchDecoder.kt new file mode 100644 index 00000000..cb941c2e --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/LocPrefetchDecoder.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.LocPrefetch +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class LocPrefetchDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.LOC_PREFETCH + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): LocPrefetch { + val id = buffer.g4() + val shape = buffer.g1() + return LocPrefetch(id, shape) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapAnimV1Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapAnimV1Decoder.kt new file mode 100644 index 00000000..5be54162 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapAnimV1Decoder.kt @@ -0,0 +1,41 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.MapAnimV1 +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MapAnimV1Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MAP_ANIM_V1 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MapAnimV1 { + val packedCoord = buffer.g1() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + + val id = buffer.g2() + val height = buffer.g2s() + val packedDelay = buffer.g2() + val rotation = buffer.g1() + val unused0 = buffer.g1() + val unused1 = buffer.g1() + val unused2 = buffer.g1() + + return MapAnimV1( + id = id, + xInZone = xInZone, + zInZone = zInZone, + height = height, + packedDelay = packedDelay, + rotation = rotation, + unused0 = unused0, + unused1 = unused1, + unused2 = unused2, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapAnimV2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapAnimV2Decoder.kt new file mode 100644 index 00000000..d732a6ec --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapAnimV2Decoder.kt @@ -0,0 +1,41 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.MapAnimV2 +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MapAnimV2Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MAP_ANIM_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MapAnimV2 { + val packedCoord = buffer.g1() + val id = buffer.g2() + val height = buffer.g2s() + val packedDelay = buffer.g2() + val rotation = buffer.g1() + val unused0 = buffer.g1() + val unused1 = buffer.g1() + val unused2 = buffer.g1() + val packedOffsets = buffer.g3() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + return MapAnimV2( + xInZone = xInZone, + zInZone = zInZone, + id = id, + height = height, + packedDelay = packedDelay, + rotation = rotation, + packedOffsets = packedOffsets, + unused0 = unused0, + unused1 = unused1, + unused2 = unused2, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimDecoder.kt new file mode 100644 index 00000000..c9536057 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimDecoder.kt @@ -0,0 +1,48 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.MapProjAnim +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MapProjAnimDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MAP_PROJANIM + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MapProjAnim { + val coordinate = buffer.g1() + val deltaX = buffer.g1s() + val deltaZ = buffer.g1s() + val target = buffer.g3() + val id = buffer.g2() + val startHeight = buffer.g1s() + val endHeight = buffer.g1s() + val startTime = buffer.g2() + val endTime = buffer.g2() + val angle = buffer.g1().let { if (it == 255) -1 else it } + val progress = buffer.g2() + val unused0 = buffer.g1() + val unused1 = buffer.g1() + val unused2 = buffer.g1() + return MapProjAnim( + coordinate = coordinate, + deltaX = deltaX, + deltaZ = deltaZ, + target = target, + id = id, + startHeight = startHeight, + endHeight = endHeight, + startTime = startTime, + endTime = endTime, + angle = angle, + progress = progress, + unused0 = unused0, + unused1 = unused1, + unused2 = unused2, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimHalfsqDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimHalfsqDecoder.kt new file mode 100644 index 00000000..cc939bb4 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimHalfsqDecoder.kt @@ -0,0 +1,47 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.MapProjAnimHalfsq +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MapProjAnimHalfsqDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MAP_PROJANIM_HALFSQ + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MapProjAnimHalfsq { + val coordinate = buffer.g1() + val flags = buffer.g1() + val deltaX = buffer.g1s() + val deltaZ = buffer.g1s() + val source = buffer.g3() + val target = buffer.g3() + val id = buffer.g2() + val startHeight = buffer.g1() + val endHeight = buffer.g1() + val startTime = buffer.g2() + val endTime = buffer.g2() + // The native handler maps 255 to -1; this does not establish a straight-line flight mode. + val angle = buffer.g1().let { if (it == 255) -1 else it } + val progress = buffer.g2() + return MapProjAnimHalfsq( + coordinate = coordinate, + flags = flags, + deltaX = deltaX, + deltaZ = deltaZ, + source = source, + target = target, + id = id, + startHeight = startHeight, + endHeight = endHeight, + startTime = startTime, + endTime = endTime, + angle = angle, + progress = progress, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimHalfsqV2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimHalfsqV2Decoder.kt new file mode 100644 index 00000000..02cdcb1b --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimHalfsqV2Decoder.kt @@ -0,0 +1,51 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.MapProjAnimHalfsqV2 +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ProjectileOffset +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MapProjAnimHalfsqV2Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MAP_PROJANIM_HALFSQ_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MapProjAnimHalfsqV2 { + val coordinate = buffer.g1() + val flags = buffer.g1() + val deltaX = buffer.g1s() + val deltaZ = buffer.g1s() + val source = buffer.g3() + val target = buffer.g3() + val id = buffer.g2() + val startHeight = buffer.g2s() + val endHeight = buffer.g2s() + val startTime = buffer.g2() + val endTime = buffer.g2() + val angle = buffer.g1().let { if (it == 255) -1 else it } + val progress = buffer.g2() + val startOffset = buffer.g3() + val endOffset = buffer.g3() + return MapProjAnimHalfsqV2( + coordinate = coordinate, + flags = flags, + deltaX = deltaX, + deltaZ = deltaZ, + source = source, + target = target, + id = id, + startHeight = startHeight, + endHeight = endHeight, + startTime = startTime, + endTime = endTime, + angle = angle, + progress = progress, + startOffset = ProjectileOffset(startOffset), + endOffset = ProjectileOffset(endOffset), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimV2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimV2Decoder.kt new file mode 100644 index 00000000..ba5d5ac2 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MapProjAnimV2Decoder.kt @@ -0,0 +1,53 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.MapProjAnimV2 +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ProjectileOffset +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MapProjAnimV2Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MAP_PROJANIM_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MapProjAnimV2 { + val coordinate = buffer.g1() + val deltaX = buffer.g1s() + val deltaZ = buffer.g1s() + val target = buffer.g3() + val id = buffer.g2() + val startHeight = buffer.g2s() + val endHeight = buffer.g2s() + val startTime = buffer.g2() + val endTime = buffer.g2() + val angle = buffer.g1().let { if (it == 255) -1 else it } + val progress = buffer.g2() + val unused0 = buffer.g1() + val unused1 = buffer.g1() + val unused2 = buffer.g1() + val startOffset = buffer.g3() + val endOffset = buffer.g3() + return MapProjAnimV2( + coordinate = coordinate, + deltaX = deltaX, + deltaZ = deltaZ, + target = target, + id = id, + startHeight = startHeight, + endHeight = endHeight, + startTime = startTime, + endTime = endTime, + angle = angle, + progress = progress, + unused0 = unused0, + unused1 = unused1, + unused2 = unused2, + startOffset = ProjectileOffset(startOffset), + endOffset = ProjectileOffset(endOffset), + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MidiSongLocationDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MidiSongLocationDecoder.kt new file mode 100644 index 00000000..f680adb1 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/MidiSongLocationDecoder.kt @@ -0,0 +1,30 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.MidiSongLocation +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class MidiSongLocationDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.MIDI_SONG_LOCATION + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): MidiSongLocation { + val volume = buffer.g1Alt2() + val id = buffer.g4Alt3() + val range = buffer.g1Alt2() + val coordinate = buffer.g4Alt3() + val radius = buffer.g1Alt1() + return MidiSongLocation( + volume = volume, + id = id, + range = range, + coordinate = coordinate, + radius = radius, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjAddDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjAddDecoder.kt new file mode 100644 index 00000000..95358b75 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjAddDecoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ObjAdd +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ObjAddDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.OBJ_ADD_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ObjAdd { + val objId = buffer.g3Alt1() + val packedCoord = buffer.g1Alt3() + val count = buffer.g2() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + return ObjAdd(true, objId, count, xInZone, zInZone) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjAddV2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjAddV2Decoder.kt new file mode 100644 index 00000000..da02999a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjAddV2Decoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ObjAdd +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameZoneProt +import net.rsprox.protocol.session.Session + +internal class ObjAddV2Decoder : ProxyMessageDecoder { + // Six-byte zone payload; the standalone decoder separately consumes its fixed frame tail. + override val prot: ClientProt = GameZoneProt.OBJ_ADD_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ObjAdd { + val count = buffer.g2Alt1() + val packedCoord = buffer.g1Alt2() + val objId = buffer.g3Alt3() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + return ObjAdd(true, objId, count, xInZone, zInZone, coordinateFlags = packedCoord ushr 7) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjAddV3Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjAddV3Decoder.kt new file mode 100644 index 00000000..0cd0e034 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjAddV3Decoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ObjAdd +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ObjAddV3Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.OBJ_ADD_V3 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ObjAdd { + val packedCoord = buffer.g1() + val objId = buffer.g3() + val count = buffer.gSmart2or4() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + val coordinateFlags = packedCoord ushr 7 + return ObjAdd(true, objId, count, xInZone, zInZone, version = 3, coordinateFlags = coordinateFlags) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjCountDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjCountDecoder.kt new file mode 100644 index 00000000..e42dc8d5 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjCountDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ObjCount +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ObjCountDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.OBJ_COUNT_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ObjCount { + val packedCoord = buffer.g1() + val objId = buffer.g3() + val oldQuantity = buffer.g2() + val newQuantity = buffer.g2() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + return ObjCount(true, objId, oldQuantity, newQuantity, xInZone, zInZone) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjCountV2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjCountV2Decoder.kt new file mode 100644 index 00000000..bee3ac7a --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjCountV2Decoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ObjCount +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ObjCountV2Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.OBJ_COUNT_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ObjCount { + val packedCoord = buffer.g1() + val objId = buffer.g3() + val oldQuantity = buffer.g2() + val newQuantity = buffer.g2() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + return ObjCount(true, objId, oldQuantity, newQuantity, xInZone, zInZone, coordinateFlags = packedCoord ushr 7) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjCountV3Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjCountV3Decoder.kt new file mode 100644 index 00000000..dc916377 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjCountV3Decoder.kt @@ -0,0 +1,35 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ObjCount +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ObjCountV3Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.OBJ_COUNT_V3 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ObjCount { + val packedCoord = buffer.g1() + val objId = buffer.g3() + val oldQuantity = buffer.gSmart2or4() + val newQuantity = buffer.gSmart2or4() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + val coordinateFlags = packedCoord ushr 7 + return ObjCount( + true, + objId, + oldQuantity, + newQuantity, + xInZone, + zInZone, + version = 3, + coordinateFlags = coordinateFlags, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjDelDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjDelDecoder.kt new file mode 100644 index 00000000..702ac9d8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjDelDecoder.kt @@ -0,0 +1,23 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ObjDel +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class ObjDelDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.OBJ_DEL_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ObjDel { + val packedCoord = buffer.g1Alt1() + val objId = buffer.g3Alt3() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + return ObjDel(true, objId, xInZone, zInZone, coordinateFlags = packedCoord ushr 7) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjRevealDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjRevealDecoder.kt new file mode 100644 index 00000000..a1b0d3e5 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjRevealDecoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ObjReveal +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameZoneProt +import net.rsprox.protocol.session.Session + +internal class ObjRevealDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameZoneProt.OBJ_REVEAL + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ObjReveal { + val packedCoord = buffer.g1() + val excludedPlayerIndex = buffer.g2Alt1() + val count = buffer.g2Alt2() + val objId = buffer.g3() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + return ObjReveal(true, objId, count, excludedPlayerIndex, xInZone, zInZone) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjRevealV3Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjRevealV3Decoder.kt new file mode 100644 index 00000000..a9b96a45 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/ObjRevealV3Decoder.kt @@ -0,0 +1,25 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ObjReveal +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameZoneProt +import net.rsprox.protocol.session.Session + +internal class ObjRevealV3Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameZoneProt.OBJ_REVEAL_V3 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ObjReveal { + val packedCoord = buffer.g1() + val objId = buffer.g3() + val count = buffer.gSmart2or4() + val excludedPlayerIndex = buffer.g2() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + return ObjReveal(true, objId, count, excludedPlayerIndex, xInZone, zInZone, version = 3) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/SoundAreaV1Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/SoundAreaV1Decoder.kt new file mode 100644 index 00000000..96824d44 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/SoundAreaV1Decoder.kt @@ -0,0 +1,32 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.SoundAreaV1 +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class SoundAreaV1Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.SOUND_AREA_V1 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SoundAreaV1 { + val coordinate = buffer.g1() + val id = buffer.g4() + val loopsAndRange = buffer.g1() + val delay = buffer.g1() + val volume = buffer.g1() + val rate = buffer.g2() + return SoundAreaV1( + coordinate = coordinate, + id = id, + loopsAndRange = loopsAndRange, + delay = delay, + volume = volume, + rate = rate, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/SoundAreaV2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/SoundAreaV2Decoder.kt new file mode 100644 index 00000000..e28bddf8 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/SoundAreaV2Decoder.kt @@ -0,0 +1,35 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.SoundAreaV2 +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameZoneProt +import net.rsprox.protocol.session.Session + +internal class SoundAreaV2Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameZoneProt.SOUND_AREA_V2 + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): SoundAreaV2 { + val coordinate = buffer.g1() + val id = buffer.g4() + val loopsAndRange = buffer.g1() + val delay = buffer.g1() + val volume = buffer.g1() + val rate = buffer.g2() + // Exactly 1 selects the speech mixer bus; every other value selects sound effects. + val speech = buffer.g1() == 1 + return SoundAreaV2( + coordinate = coordinate, + id = id, + loopsAndRange = loopsAndRange, + delay = delay, + volume = volume, + rate = rate, + speech = speech, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/StandaloneObjAddV2Decoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/StandaloneObjAddV2Decoder.kt new file mode 100644 index 00000000..ce0ae09f --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/StandaloneObjAddV2Decoder.kt @@ -0,0 +1,24 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.ObjAdd +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class StandaloneObjAddV2Decoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.OBJ_ADD_V2 + private val payload = ObjAddV2Decoder() + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): ObjAdd { + val message = payload.decode(buffer, session) + // The standalone descriptor includes one byte which the native callback never reads. + // Enclosed-zone OBJ_ADD_V2 has no such byte. + buffer.g1() + return message + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/TextCoordDecoder.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/TextCoordDecoder.kt new file mode 100644 index 00000000..2315dca4 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/codec/zone/payload/TextCoordDecoder.kt @@ -0,0 +1,37 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload + +import net.rsprot.buffer.JagByteBuf +import net.rsprot.protocol.ClientProt +import net.rsprox.protocol.ProxyMessageDecoder +import net.rsprox.protocol.rs3.game.outgoing.model.zone.payload.TextCoord +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt +import net.rsprox.protocol.session.Session + +internal class TextCoordDecoder : ProxyMessageDecoder { + override val prot: ClientProt = GameServerProt.TEXT_COORD + + override fun decode( + buffer: JagByteBuf, + session: Session, + ): TextCoord { + val ignored = buffer.g1() + val packedCoord = buffer.g1() + val xInZone = (packedCoord ushr 4) and 0x7 + val zInZone = packedCoord and 0x7 + + val duration = buffer.g2() + val height = buffer.g1() + val rgb = buffer.g3() + val text = buffer.gjstr() + + return TextCoord( + duration = duration, + xInZone = xInZone, + zInZone = zInZone, + height = height, + rgb = rgb, + text = text, + ignored = ignored, + ) + } +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/GameServerProt.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/GameServerProt.kt new file mode 100644 index 00000000..c2841d60 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/GameServerProt.kt @@ -0,0 +1,232 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot + +import net.rsprot.protocol.ClientProt +import net.rsprot.protocol.Prot + +public enum class GameServerProt( + override val opcode: Int, + override val size: Int, +) : ClientProt { + HINT_ARROW(GameServerProtId.HINT_ARROW, 14), + PLAYER_INFO(GameServerProtId.PLAYER_INFO, Prot.VAR_SHORT), + IF_SETANIM(GameServerProtId.IF_SETANIM, 8), + NPC_ANIM_SPECIFIC(GameServerProtId.NPC_ANIM_SPECIFIC, 19), + MESSAGE_PRIVATE(GameServerProtId.MESSAGE_PRIVATE, Prot.VAR_SHORT), + LOC_ANIM(GameServerProtId.LOC_ANIM, 7), + UPDATE_FRIENDCHAT_CHANNEL_FULL(GameServerProtId.UPDATE_FRIENDCHAT_CHANNEL_FULL, Prot.VAR_SHORT), + IF_SETTEXTANTIMACRO(GameServerProtId.IF_SETTEXTANTIMACRO, 5), + MESSAGE_QUICKCHAT_PRIVATE_ECHO(GameServerProtId.MESSAGE_QUICKCHAT_PRIVATE_ECHO, Prot.VAR_BYTE), + UPDATE_RUNENERGY(GameServerProtId.UPDATE_RUNENERGY, 1), + CLIENT_SETVARCSTR_SMALL(GameServerProtId.CLIENT_SETVARCSTR_SMALL, Prot.VAR_BYTE), + CLIENT_SETVARCSTR_LARGE(GameServerProtId.CLIENT_SETVARCSTR_LARGE, Prot.VAR_SHORT), + SET_PLAYER_OP(GameServerProtId.SET_PLAYER_OP, Prot.VAR_BYTE), + IF_SETPOSITION(GameServerProtId.IF_SETPOSITION, 8), + UPDATE_RUNWEIGHT(GameServerProtId.UPDATE_RUNWEIGHT, 2), + UPDATE_IGNORELIST(GameServerProtId.UPDATE_IGNORELIST, Prot.VAR_SHORT), + MESSAGE_QUICKCHAT_FRIENDCHAT(GameServerProtId.MESSAGE_QUICKCHAT_FRIENDCHAT, Prot.VAR_BYTE), + MESSAGE_PRIVATE_ECHO(GameServerProtId.MESSAGE_PRIVATE_ECHO, Prot.VAR_SHORT), + IF_SETMODEL(GameServerProtId.IF_SETMODEL, 8), + TRIGGER_ONDIALOGABORT(GameServerProtId.TRIGGER_ONDIALOGABORT, 0), + VARBIT_SMALL(GameServerProtId.VARBIT_SMALL, 3), + SPOTANIM_SPECIFIC(GameServerProtId.SPOTANIM_SPECIFIC, 12), + UPDATE_INV_PARTIAL(GameServerProtId.UPDATE_INV_PARTIAL, Prot.VAR_SHORT), + IF_OPENSUB(GameServerProtId.IF_OPENSUB, 23), + UPDATE_FRIENDCHAT_CHANNEL_SINGLEUSER(GameServerProtId.UPDATE_FRIENDCHAT_CHANNEL_SINGLEUSER, Prot.VAR_BYTE), + IF_SETGRAPHIC(GameServerProtId.IF_SETGRAPHIC, 8), + IF_CLOSESUB(GameServerProtId.IF_CLOSESUB, 4), + HINT_TRAIL(GameServerProtId.HINT_TRAIL, Prot.VAR_SHORT), + CAM_LOOKAT(GameServerProtId.CAM_LOOKAT, 6), + IF_SETOBJECT_V2(GameServerProtId.IF_SETOBJECT_V2, 11), + DEBUG_SERVER_TRIGGERS(GameServerProtId.DEBUG_SERVER_TRIGGERS, Prot.VAR_BYTE), + MESSAGE_GAME(GameServerProtId.MESSAGE_GAME, Prot.VAR_BYTE), + CHAT_FILTER_SETTINGS(GameServerProtId.CHAT_FILTER_SETTINGS, 2), + IF_SETTEXT(GameServerProtId.IF_SETTEXT, Prot.VAR_SHORT), + IF_SETPLAYERMODEL_OTHER(GameServerProtId.IF_SETPLAYERMODEL_OTHER, 10), + REBUILD_NORMAL(GameServerProtId.REBUILD_NORMAL, Prot.VAR_SHORT), + MESSAGE_CLANCHANNEL_SYSTEM(GameServerProtId.MESSAGE_CLANCHANNEL_SYSTEM, Prot.VAR_BYTE), + UPDATE_UID192(GameServerProtId.UPDATE_UID192, 28), + CAM_SHAKE(GameServerProtId.CAM_SHAKE, 6), + IF_MOVESUB(GameServerProtId.IF_MOVESUB, 8), + MIDI_SONG(GameServerProtId.MIDI_SONG, 5), + UPDATE_ZONE_FULL_FOLLOWS(GameServerProtId.UPDATE_ZONE_FULL_FOLLOWS, 3), + MESSAGE_QUICKCHAT_PRIVATE(GameServerProtId.MESSAGE_QUICKCHAT_PRIVATE, Prot.VAR_BYTE), + LOC_ADD_CHANGE(GameServerProtId.LOC_ADD_CHANGE, Prot.VAR_BYTE), + LOGOUT(GameServerProtId.LOGOUT, 1), + IF_OPENSUB_ACTIVE_OBJ_V2(GameServerProtId.IF_OPENSUB_ACTIVE_OBJ_V2, 30), + UPDATE_INV_FULL(GameServerProtId.UPDATE_INV_FULL, Prot.VAR_SHORT), + VARBIT(GameServerProtId.VARBIT, Prot.VAR_BYTE), + MESSAGE_PUBLIC(GameServerProtId.MESSAGE_PUBLIC, Prot.VAR_BYTE), + CLIENT_SETVARCBIT_LARGE(GameServerProtId.CLIENT_SETVARCBIT_LARGE, 6), + IF_SETTARGETPARAM(GameServerProtId.IF_SETTARGETPARAM, 10), + RESET_ANIMS(GameServerProtId.RESET_ANIMS, 0), + CLIENT_SETVARCBIT_SMALL(GameServerProtId.CLIENT_SETVARCBIT_SMALL, 3), + UPDATE_ZONE_PARTIAL_ENCLOSED(GameServerProtId.UPDATE_ZONE_PARTIAL_ENCLOSED, Prot.VAR_SHORT), + CLANCHANNEL_DELTA(GameServerProtId.CLANCHANNEL_DELTA, Prot.VAR_SHORT), + CAM_RESET(GameServerProtId.CAM_RESET, 0), + CAM2_ENABLE(GameServerProtId.CAM2_ENABLE, 1), + CLIENT_SETVARC_LARGE(GameServerProtId.CLIENT_SETVARC_LARGE, 6), + LAST_LOGIN_INFO(GameServerProtId.LAST_LOGIN_INFO, 4), + IF_OPENSUB_ACTIVE_PLAYER(GameServerProtId.IF_OPENSUB_ACTIVE_PLAYER, 25), + UPDATE_ZONE_PARTIAL_FOLLOWS(GameServerProtId.UPDATE_ZONE_PARTIAL_FOLLOWS, 3), + IF_SETANGLE(GameServerProtId.IF_SETANGLE, 10), + REBUILD_REGION(GameServerProtId.REBUILD_REGION, Prot.VAR_SHORT), + CLIENT_SETVARCBIT(GameServerProtId.CLIENT_SETVARCBIT, Prot.VAR_BYTE), + IF_SETPLAYERHEAD_IGNOREWORN(GameServerProtId.IF_SETPLAYERHEAD_IGNOREWORN, 10), + MIDI_JINGLE(GameServerProtId.MIDI_JINGLE, 5), + VORBIS_SPEECH_SOUND(GameServerProtId.VORBIS_SPEECH_SOUND, 8), + VARCLAN_ENABLE(GameServerProtId.VARCLAN_ENABLE, 0), + UPDATE_STOCKMARKET_SLOT_V2(GameServerProtId.UPDATE_STOCKMARKET_SLOT_V2, 36), + IF_SETSCROLLPOS(GameServerProtId.IF_SETSCROLLPOS, 6), + OBJ_ADD_V2(GameServerProtId.OBJ_ADD_V2, 7), + MAP_ANIM_V1(GameServerProtId.MAP_ANIM_V1, 11), + IF_SETNPCHEAD(GameServerProtId.IF_SETNPCHEAD, 8), + FRIENDLIST_LOADED(GameServerProtId.FRIENDLIST_LOADED, 0), + VORBIS_SOUND(GameServerProtId.VORBIS_SOUND, 10), + CLANCHANNEL_FULL(GameServerProtId.CLANCHANNEL_FULL, Prot.VAR_SHORT), + IF_SETEVENTS(GameServerProtId.IF_SETEVENTS, 12), + IF_SETHIDE(GameServerProtId.IF_SETHIDE, 5), + LOC_CUSTOMISE(GameServerProtId.LOC_CUSTOMISE, Prot.VAR_BYTE), + MINIMAP_TOGGLE(GameServerProtId.MINIMAP_TOGGLE, 1), + MESSAGE_CLANCHANNEL(GameServerProtId.MESSAGE_CLANCHANNEL, Prot.VAR_BYTE), + UPDATE_INV_STOP_TRANSMIT(GameServerProtId.UPDATE_INV_STOP_TRANSMIT, 3), + CLANSETTINGS_FULL(GameServerProtId.CLANSETTINGS_FULL, Prot.VAR_SHORT), + VARP_LARGE(GameServerProtId.VARP_LARGE, 6), + UPDATE_FRIENDLIST(GameServerProtId.UPDATE_FRIENDLIST, Prot.VAR_SHORT), + IF_SET_HTTP_IMAGE(GameServerProtId.IF_SET_HTTP_IMAGE, 8), + CLANSETTINGS_DELTA(GameServerProtId.CLANSETTINGS_DELTA, Prot.VAR_SHORT), + CAM_REMOVEROOF(GameServerProtId.CAM_REMOVEROOF, 4), + SET_MOVEACTION(GameServerProtId.SET_MOVEACTION, Prot.VAR_BYTE), + VARCLAN_DISABLE(GameServerProtId.VARCLAN_DISABLE, 0), + PROJANIM_SPECIFIC(GameServerProtId.PROJANIM_SPECIFIC, 25), + UPDATE_SITESETTINGS(GameServerProtId.UPDATE_SITESETTINGS, Prot.VAR_BYTE), + VARP_SMALL(GameServerProtId.VARP_SMALL, 3), + LOC_DEL(GameServerProtId.LOC_DEL, 2), + CAM_MOVETO(GameServerProtId.CAM_MOVETO, 6), + UPDATE_REBOOT_TIMER(GameServerProtId.UPDATE_REBOOT_TIMER, 2), + LOC_ANIM_SPECIFIC(GameServerProtId.LOC_ANIM_SPECIFIC, 10), + CAM_SMOOTHRESET(GameServerProtId.CAM_SMOOTHRESET, 0), + VARBIT_LARGE(GameServerProtId.VARBIT_LARGE, 6), + VARCLAN(GameServerProtId.VARCLAN, Prot.VAR_BYTE), + SET_MAP_FLAG(GameServerProtId.SET_MAP_FLAG, 10), + CHAT_FILTER_SETTINGS_PRIVATECHAT(GameServerProtId.CHAT_FILTER_SETTINGS_PRIVATECHAT, 1), + SYNTH_SOUND(GameServerProtId.SYNTH_SOUND, 10), + LOGOUT_FULL(GameServerProtId.LOGOUT_FULL, 1), + IF_SETPLAYERHEAD(GameServerProtId.IF_SETPLAYERHEAD, 4), + MAP_PROJANIM(GameServerProtId.MAP_PROJANIM, 20), + RESET_CLIENT_VARCACHE(GameServerProtId.RESET_CLIENT_VARCACHE, 0), + MIDI_SONG_LOCATION(GameServerProtId.MIDI_SONG_LOCATION, 11), + URL_OPEN(GameServerProtId.URL_OPEN, Prot.VAR_SHORT), + IF_SETPLAYERHEAD_OTHER(GameServerProtId.IF_SETPLAYERHEAD_OTHER, 10), + UPDATE_STAT(GameServerProtId.UPDATE_STAT, 6), + IF_OPENTOP(GameServerProtId.IF_OPENTOP, 19), + NPC_INFO_V2(GameServerProtId.NPC_INFO_V2, Prot.VAR_SHORT), + IF_SETTEXTFONT(GameServerProtId.IF_SETTEXTFONT, 8), + MESSAGE_FRIENDCHANNEL(GameServerProtId.MESSAGE_FRIENDCHANNEL, Prot.VAR_BYTE), + VORBIS_SPEECH_STOP(GameServerProtId.VORBIS_SPEECH_STOP, 0), + IF_OPENSUB_ACTIVE_LOC(GameServerProtId.IF_OPENSUB_ACTIVE_LOC, 32), + OBJ_DEL_V2(GameServerProtId.OBJ_DEL_V2, 4), + CAMERA_UPDATE(GameServerProtId.CAMERA_UPDATE, Prot.VAR_SHORT), + MESSAGE_QUICKCHAT_CLANCHANNEL(GameServerProtId.MESSAGE_QUICKCHAT_CLANCHANNEL, Prot.VAR_BYTE), + IF_SETCOLOUR(GameServerProtId.IF_SETCOLOUR, 6), + CLIENT_SETVARC_SMALL(GameServerProtId.CLIENT_SETVARC_SMALL, 3), + IF_OPENSUB_ACTIVE_NPC(GameServerProtId.IF_OPENSUB_ACTIVE_NPC, 25), + OBJ_ADD_V3(GameServerProtId.OBJ_ADD_V3, Prot.VAR_BYTE), + RUNCLIENTSCRIPT(GameServerProtId.RUNCLIENTSCRIPT, Prot.VAR_SHORT), + IF_SETPLAYERMODEL_SELF(GameServerProtId.IF_SETPLAYERMODEL_SELF, 4), + CAM_FORCEANGLE(GameServerProtId.CAM_FORCEANGLE, 4), + SONG_PRELOAD(GameServerProtId.SONG_PRELOAD, 4), + UNNAMED_1(GameServerProtId.UNNAMED_1, Prot.VAR_BYTE), + MAP_PROJANIM_HALFSQ_V2(GameServerProtId.MAP_PROJANIM_HALFSQ_V2, 29), + OBJ_COUNT_V3(GameServerProtId.OBJ_COUNT_V3, Prot.VAR_BYTE), + LOCSELECT_CLEAR(GameServerProtId.LOCSELECT_CLEAR, 0), + LOC_PREFETCH(GameServerProtId.LOC_PREFETCH, 5), + POINTLIGHT_INTENSITYSCALE(GameServerProtId.POINTLIGHT_INTENSITYSCALE, 5), + SETDRAWORDER(GameServerProtId.SETDRAWORDER, 1), + TELEMETRY_GRID_REMOVE_COLUMN(GameServerProtId.TELEMETRY_GRID_REMOVE_COLUMN, 2), + SHOW_FACE_HERE(GameServerProtId.SHOW_FACE_HERE, 1), + SOUND_MIXBUSS_ADD(GameServerProtId.SOUND_MIXBUSS_ADD, 6), + PROJANIM_SPECIFIC_V2(GameServerProtId.PROJANIM_SPECIFIC_V2, 33), + IF_SETRECOL(GameServerProtId.IF_SETRECOL, 9), + PLAYER_GROUP_VARPS(GameServerProtId.PLAYER_GROUP_VARPS, Prot.VAR_SHORT), + VARP_LONG(GameServerProtId.VARP_LONG, 10), + SET_PLAYER_ATTACK_PRIORITY(GameServerProtId.SET_PLAYER_ATTACK_PRIORITY, 1), + SET_LOC_OP_OVERRIDE(GameServerProtId.SET_LOC_OP_OVERRIDE, Prot.VAR_BYTE), + TELEMETRY_GRID_SET_ROW_PINNED(GameServerProtId.TELEMETRY_GRID_SET_ROW_PINNED, 3), + POINTLIGHT_EXTEND_ABOVE(GameServerProtId.POINTLIGHT_EXTEND_ABOVE, 3), + POINTLIGHT_COLOUR(GameServerProtId.POINTLIGHT_COLOUR, 8), + CHANGE_LOBBY(GameServerProtId.CHANGE_LOBBY, Prot.VAR_BYTE), + MIDI_SONG_STOP(GameServerProtId.MIDI_SONG_STOP, 0), + CUTSCENE2D_PLAY(GameServerProtId.CUTSCENE2D_PLAY, 2), + NO_TIMEOUT(GameServerProtId.NO_TIMEOUT, 0), + IF_SETCLICKMASK(GameServerProtId.IF_SETCLICKMASK, 5), + TELEMETRY_GRID_VALUES_DELTA(GameServerProtId.TELEMETRY_GRID_VALUES_DELTA, Prot.VAR_SHORT), + JCOINS_UPDATE(GameServerProtId.JCOINS_UPDATE, 4), + TELEMETRY_GRID_REMOVE_GROUP(GameServerProtId.TELEMETRY_GRID_REMOVE_GROUP, 1), + VORBIS_SOUND_GROUP_STOP(GameServerProtId.VORBIS_SOUND_GROUP_STOP, 2), + TELEMETRY_GRID_ADD_ROW(GameServerProtId.TELEMETRY_GRID_ADD_ROW, 6), + CREATE_ACCOUNT_REPLY(GameServerProtId.CREATE_ACCOUNT_REPLY, 1), + WORLDLIST_FETCH_REPLY(GameServerProtId.WORLDLIST_FETCH_REPLY, Prot.VAR_SHORT), + SOUND_AREA_V1(GameServerProtId.SOUND_AREA_V1, 10), + VORBIS_SOUND_GROUP(GameServerProtId.VORBIS_SOUND_GROUP, 12), + SERVER_TICK_END(GameServerProtId.SERVER_TICK_END, 0), + VORBIS_PRELOAD_SOUNDS(GameServerProtId.VORBIS_PRELOAD_SOUNDS, 4), + TELEMETRY_GRID_MOVE_ROW(GameServerProtId.TELEMETRY_GRID_MOVE_ROW, 3), + SOUND_MIXBUSS_SETLEVEL(GameServerProtId.SOUND_MIXBUSS_SETLEVEL, 4), + CREATE_CHECK_NAME_REPLY(GameServerProtId.CREATE_CHECK_NAME_REPLY, 1), + POINTLIGHT_ATTENUATION_FALLOFF(GameServerProtId.POINTLIGHT_ATTENUATION_FALLOFF, 4), + POINTLIGHT_SHADOW(GameServerProtId.POINTLIGHT_SHADOW, 3), + POINTLIGHT_ENABLED(GameServerProtId.POINTLIGHT_ENABLED, 3), + NPC_HEADICON_SPECIFIC(GameServerProtId.NPC_HEADICON_SPECIFIC, 9), + TELEMETRY_GRID_FULL(GameServerProtId.TELEMETRY_GRID_FULL, Prot.VAR_SHORT), + VORBIS_SOUND_GROUP_START(GameServerProtId.VORBIS_SOUND_GROUP_START, 2), + IF_SETPLAYERHEAD_SNAPSHOT(GameServerProtId.IF_SETPLAYERHEAD_SNAPSHOT, 5), + CREATE_SUGGEST_NAME_REPLY(GameServerProtId.CREATE_SUGGEST_NAME_REPLY, Prot.VAR_BYTE), + PLAYER_GROUP_DELTA(GameServerProtId.PLAYER_GROUP_DELTA, Prot.VAR_SHORT), + TELEMETRY_GRID_REMOVE_ROW(GameServerProtId.TELEMETRY_GRID_REMOVE_ROW, 2), + IF_SETPLAYERMODEL_SNAPSHOT(GameServerProtId.IF_SETPLAYERMODEL_SNAPSHOT, 5), + PLAYER_SNAPSHOT(GameServerProtId.PLAYER_SNAPSHOT, Prot.VAR_SHORT), + PLAYER_GROUP_FULL(GameServerProtId.PLAYER_GROUP_FULL, Prot.VAR_SHORT), + POINTLIGHT_EXTEND_BELOW(GameServerProtId.POINTLIGHT_EXTEND_BELOW, 3), + MAP_PROJANIM_HALFSQ(GameServerProtId.MAP_PROJANIM_HALFSQ, 21), + NPC_SAY_SPECIFIC(GameServerProtId.NPC_SAY_SPECIFIC, Prot.VAR_SHORT), + STORE_SERVERPERM_VARCS_ACK(GameServerProtId.STORE_SERVERPERM_VARCS_ACK, 0), + DO_CHEAT(GameServerProtId.DO_CHEAT, Prot.VAR_BYTE), + CONSOLE_FEEDBACK(GameServerProtId.CONSOLE_FEEDBACK, Prot.VAR_SHORT), + EXECUTE_CLIENT_CHEAT(GameServerProtId.EXECUTE_CLIENT_CHEAT, 2), + SET_NPC_ATTACK_PRIORITY(GameServerProtId.SET_NPC_ATTACK_PRIORITY, 1), + LOBBY_APPEARANCE(GameServerProtId.LOBBY_APPEARANCE, Prot.VAR_SHORT), + IF_SETOBJECT_LONG_V2(GameServerProtId.IF_SETOBJECT_LONG_V2, 15), + OBJ_COUNT_V2(GameServerProtId.OBJ_COUNT_V2, 8), + CREATE_CHECK_EMAIL_REPLY(GameServerProtId.CREATE_CHECK_EMAIL_REPLY, 1), + LOCSELECT_ADD(GameServerProtId.LOCSELECT_ADD, Prot.VAR_BYTE), + SEND_PING(GameServerProtId.SEND_PING, 8), + MESSAGE_PLAYER_GROUP(GameServerProtId.MESSAGE_PLAYER_GROUP, Prot.VAR_BYTE), + MAP_PROJANIM_V2(GameServerProtId.MAP_PROJANIM_V2, 28), + SOUND_STOP(GameServerProtId.SOUND_STOP, 6), + STORE_RESET(GameServerProtId.STORE_RESET, 0), + ENVIRONMENT_OVERRIDE(GameServerProtId.ENVIRONMENT_OVERRIDE, Prot.VAR_BYTE), + MESSAGE_QUICKCHAT_PLAYER_GROUP(GameServerProtId.MESSAGE_QUICKCHAT_PLAYER_GROUP, Prot.VAR_BYTE), + SOCIAL_NETWORK_LOGOUT(GameServerProtId.SOCIAL_NETWORK_LOGOUT, Prot.VAR_SHORT), + MAP_ANIM_V2(GameServerProtId.MAP_ANIM_V2, 14), + DBFILTER_DEBUG(GameServerProtId.DBFILTER_DEBUG, Prot.VAR_SHORT), + TELEMETRY_GRID_ADD_COLUMN(GameServerProtId.TELEMETRY_GRID_ADD_COLUMN, 6), + TELEMETRY_CLEAR_GRID_VALUE(GameServerProtId.TELEMETRY_CLEAR_GRID_VALUE, 3), + TELEMETRY_GRID_MOVE_COLUMN(GameServerProtId.TELEMETRY_GRID_MOVE_COLUMN, 3), + LOGOUT_TRANSFER(GameServerProtId.LOGOUT_TRANSFER, Prot.VAR_BYTE), + UPDATE_DOB(GameServerProtId.UPDATE_DOB, 4), + CLIENT_SETVARC_LONG(GameServerProtId.CLIENT_SETVARC_LONG, 10), + TELEMETRY_GRID_ADD_GROUP(GameServerProtId.TELEMETRY_GRID_ADD_GROUP, 5), + SPOTANIM_SPECIFIC_V2(GameServerProtId.SPOTANIM_SPECIFIC_V2, 15), + CREATE_SUGGEST_NAME_ERROR(GameServerProtId.CREATE_SUGGEST_NAME_ERROR, 1), + IF_SETRETEX(GameServerProtId.IF_SETRETEX, 9), + JS5_RELOAD(GameServerProtId.JS5_RELOAD, 0), + LOYALTY_UPDATE(GameServerProtId.LOYALTY_UPDATE, 4), + LOCSELECT_CONFIGURE(GameServerProtId.LOCSELECT_CONFIGURE, 14), + CLEAR_PLAYER_SNAPSHOT(GameServerProtId.CLEAR_PLAYER_SNAPSHOT, 1), + PLAYER_ANIM_SPECIFIC(GameServerProtId.PLAYER_ANIM_SPECIFIC, 17), + TEXT_COORD(GameServerProtId.TEXT_COORD, Prot.VAR_BYTE), + SET_TARGET(GameServerProtId.SET_TARGET, 3), + UNNAMED_2(GameServerProtId.UNNAMED_2, Prot.VAR_SHORT), + SYNC_CLOCK(GameServerProtId.SYNC_CLOCK, 8), + RECONNECT(0xFF, Prot.VAR_SHORT), +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/GameServerProtId.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/GameServerProtId.kt new file mode 100644 index 00000000..25eae926 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/GameServerProtId.kt @@ -0,0 +1,226 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot + +internal object GameServerProtId { + const val HINT_ARROW: Int = 0 + const val PLAYER_INFO: Int = 1 + const val IF_SETANIM: Int = 2 + const val NPC_ANIM_SPECIFIC: Int = 3 + const val MESSAGE_PRIVATE: Int = 4 + const val LOC_ANIM: Int = 5 + const val UPDATE_FRIENDCHAT_CHANNEL_FULL: Int = 6 + const val IF_SETTEXTANTIMACRO: Int = 7 + const val MESSAGE_QUICKCHAT_PRIVATE_ECHO: Int = 8 + const val UPDATE_RUNENERGY: Int = 9 + const val CLIENT_SETVARCSTR_SMALL: Int = 10 + const val CLIENT_SETVARCSTR_LARGE: Int = 11 + const val SET_PLAYER_OP: Int = 12 + const val IF_SETPOSITION: Int = 13 + const val UPDATE_RUNWEIGHT: Int = 14 + const val UPDATE_IGNORELIST: Int = 15 + const val MESSAGE_QUICKCHAT_FRIENDCHAT: Int = 16 + const val MESSAGE_PRIVATE_ECHO: Int = 17 + const val IF_SETMODEL: Int = 18 + const val TRIGGER_ONDIALOGABORT: Int = 19 + const val VARBIT_SMALL: Int = 20 + const val SPOTANIM_SPECIFIC: Int = 21 + const val UPDATE_INV_PARTIAL: Int = 22 + const val IF_OPENSUB: Int = 23 + const val UPDATE_FRIENDCHAT_CHANNEL_SINGLEUSER: Int = 24 + const val IF_SETGRAPHIC: Int = 25 + const val IF_CLOSESUB: Int = 26 + const val HINT_TRAIL: Int = 27 + const val CAM_LOOKAT: Int = 28 + const val IF_SETOBJECT_V2: Int = 29 + const val DEBUG_SERVER_TRIGGERS: Int = 30 + const val MESSAGE_GAME: Int = 31 + const val CHAT_FILTER_SETTINGS: Int = 32 + const val IF_SETTEXT: Int = 33 + const val IF_SETPLAYERMODEL_OTHER: Int = 34 + const val REBUILD_NORMAL: Int = 35 + const val MESSAGE_CLANCHANNEL_SYSTEM: Int = 36 + const val UPDATE_UID192: Int = 37 + const val CAM_SHAKE: Int = 38 + const val IF_MOVESUB: Int = 39 + const val MIDI_SONG: Int = 40 + const val UPDATE_ZONE_FULL_FOLLOWS: Int = 41 + const val MESSAGE_QUICKCHAT_PRIVATE: Int = 42 + const val LOC_ADD_CHANGE: Int = 43 + const val LOGOUT: Int = 44 + const val IF_OPENSUB_ACTIVE_OBJ_V2: Int = 45 + const val UPDATE_INV_FULL: Int = 46 + const val VARBIT: Int = 47 + const val MESSAGE_PUBLIC: Int = 48 + const val CLIENT_SETVARCBIT_LARGE: Int = 49 + const val IF_SETTARGETPARAM: Int = 50 + const val RESET_ANIMS: Int = 51 + const val CLIENT_SETVARCBIT_SMALL: Int = 52 + const val UPDATE_ZONE_PARTIAL_ENCLOSED: Int = 53 + const val CLANCHANNEL_DELTA: Int = 54 + const val CAM_RESET: Int = 55 + const val CAM2_ENABLE: Int = 56 + const val CLIENT_SETVARC_LARGE: Int = 57 + const val LAST_LOGIN_INFO: Int = 58 + const val IF_OPENSUB_ACTIVE_PLAYER: Int = 59 + const val UPDATE_ZONE_PARTIAL_FOLLOWS: Int = 60 + const val IF_SETANGLE: Int = 61 + const val REBUILD_REGION: Int = 62 + const val CLIENT_SETVARCBIT: Int = 63 + const val IF_SETPLAYERHEAD_IGNOREWORN: Int = 64 + const val MIDI_JINGLE: Int = 65 + const val VORBIS_SPEECH_SOUND: Int = 66 + const val VARCLAN_ENABLE: Int = 67 + const val UPDATE_STOCKMARKET_SLOT_V2: Int = 68 + const val IF_SETSCROLLPOS: Int = 69 + const val OBJ_ADD_V2: Int = 70 + const val MAP_ANIM_V1: Int = 71 + const val IF_SETNPCHEAD: Int = 72 + const val FRIENDLIST_LOADED: Int = 73 + // Note: 74/103 have identical native handlers; names were identified by comparing packet dumps. + const val VORBIS_SOUND: Int = 74 + const val CLANCHANNEL_FULL: Int = 75 + const val IF_SETEVENTS: Int = 76 + const val IF_SETHIDE: Int = 77 + const val LOC_CUSTOMISE: Int = 78 + const val MINIMAP_TOGGLE: Int = 79 + const val MESSAGE_CLANCHANNEL: Int = 80 + const val UPDATE_INV_STOP_TRANSMIT: Int = 81 + const val CLANSETTINGS_FULL: Int = 82 + const val VARP_LARGE: Int = 83 + const val UPDATE_FRIENDLIST: Int = 84 + const val IF_SET_HTTP_IMAGE: Int = 85 + const val CLANSETTINGS_DELTA: Int = 86 + const val CAM_REMOVEROOF: Int = 87 + const val SET_MOVEACTION: Int = 88 + const val VARCLAN_DISABLE: Int = 89 + const val PROJANIM_SPECIFIC: Int = 90 + const val UPDATE_SITESETTINGS: Int = 91 + const val VARP_SMALL: Int = 92 + const val LOC_DEL: Int = 94 + const val CAM_MOVETO: Int = 95 + const val UPDATE_REBOOT_TIMER: Int = 96 + const val LOC_ANIM_SPECIFIC: Int = 97 + const val CAM_SMOOTHRESET: Int = 98 + const val VARBIT_LARGE: Int = 99 + const val VARCLAN: Int = 100 + const val SET_MAP_FLAG: Int = 101 + const val CHAT_FILTER_SETTINGS_PRIVATECHAT: Int = 102 + const val SYNTH_SOUND: Int = 103 + const val LOGOUT_FULL: Int = 104 + const val IF_SETPLAYERHEAD: Int = 105 + const val MAP_PROJANIM: Int = 106 + const val RESET_CLIENT_VARCACHE: Int = 107 + const val MIDI_SONG_LOCATION: Int = 108 + const val URL_OPEN: Int = 109 + const val IF_SETPLAYERHEAD_OTHER: Int = 110 + const val UPDATE_STAT: Int = 111 + const val IF_OPENTOP: Int = 112 + const val NPC_INFO_V2: Int = 113 + const val IF_SETTEXTFONT: Int = 114 + const val MESSAGE_FRIENDCHANNEL: Int = 115 + const val VORBIS_SPEECH_STOP: Int = 116 + const val IF_OPENSUB_ACTIVE_LOC: Int = 117 + const val OBJ_DEL_V2: Int = 118 + const val CAMERA_UPDATE: Int = 119 + const val MESSAGE_QUICKCHAT_CLANCHANNEL: Int = 120 + const val IF_SETCOLOUR: Int = 121 + const val CLIENT_SETVARC_SMALL: Int = 122 + const val IF_OPENSUB_ACTIVE_NPC: Int = 123 + const val OBJ_ADD_V3: Int = 124 + const val RUNCLIENTSCRIPT: Int = 125 + const val IF_SETPLAYERMODEL_SELF: Int = 126 + const val CAM_FORCEANGLE: Int = 127 + const val SONG_PRELOAD: Int = 128 + const val UNNAMED_1: Int = 129 + const val MAP_PROJANIM_HALFSQ_V2: Int = 130 + const val OBJ_COUNT_V3: Int = 131 + const val LOCSELECT_CLEAR: Int = 132 + const val LOC_PREFETCH: Int = 133 + const val POINTLIGHT_INTENSITYSCALE: Int = 134 + const val SETDRAWORDER: Int = 135 + const val TELEMETRY_GRID_REMOVE_COLUMN: Int = 136 + const val SHOW_FACE_HERE: Int = 137 + const val SOUND_MIXBUSS_ADD: Int = 138 + const val PROJANIM_SPECIFIC_V2: Int = 140 + const val IF_SETRECOL: Int = 141 + const val PLAYER_GROUP_VARPS: Int = 142 + const val VARP_LONG: Int = 143 + const val SET_PLAYER_ATTACK_PRIORITY: Int = 144 + const val SET_LOC_OP_OVERRIDE: Int = 145 + const val TELEMETRY_GRID_SET_ROW_PINNED: Int = 146 + const val POINTLIGHT_EXTEND_ABOVE: Int = 147 + const val POINTLIGHT_COLOUR: Int = 148 + const val CHANGE_LOBBY: Int = 149 + const val MIDI_SONG_STOP: Int = 150 + const val CUTSCENE2D_PLAY: Int = 151 + const val NO_TIMEOUT: Int = 152 + const val IF_SETCLICKMASK: Int = 153 + const val TELEMETRY_GRID_VALUES_DELTA: Int = 154 + const val JCOINS_UPDATE: Int = 155 + const val TELEMETRY_GRID_REMOVE_GROUP: Int = 156 + const val VORBIS_SOUND_GROUP_STOP: Int = 157 + const val TELEMETRY_GRID_ADD_ROW: Int = 158 + const val CREATE_ACCOUNT_REPLY: Int = 159 + const val WORLDLIST_FETCH_REPLY: Int = 160 + const val SOUND_AREA_V1: Int = 161 + const val VORBIS_SOUND_GROUP: Int = 162 + const val SERVER_TICK_END: Int = 163 + const val VORBIS_PRELOAD_SOUNDS: Int = 164 + const val TELEMETRY_GRID_MOVE_ROW: Int = 165 + const val SOUND_MIXBUSS_SETLEVEL: Int = 166 + const val CREATE_CHECK_NAME_REPLY: Int = 168 + const val POINTLIGHT_ATTENUATION_FALLOFF: Int = 169 + const val POINTLIGHT_SHADOW: Int = 170 + const val POINTLIGHT_ENABLED: Int = 171 + const val NPC_HEADICON_SPECIFIC: Int = 172 + const val TELEMETRY_GRID_FULL: Int = 173 + const val VORBIS_SOUND_GROUP_START: Int = 174 + const val IF_SETPLAYERHEAD_SNAPSHOT: Int = 175 + const val CREATE_SUGGEST_NAME_REPLY: Int = 177 + const val PLAYER_GROUP_DELTA: Int = 178 + const val TELEMETRY_GRID_REMOVE_ROW: Int = 179 + const val IF_SETPLAYERMODEL_SNAPSHOT: Int = 180 + const val PLAYER_SNAPSHOT: Int = 181 + const val PLAYER_GROUP_FULL: Int = 182 + const val POINTLIGHT_EXTEND_BELOW: Int = 183 + const val MAP_PROJANIM_HALFSQ: Int = 184 + const val NPC_SAY_SPECIFIC: Int = 185 + const val STORE_SERVERPERM_VARCS_ACK: Int = 186 + const val DO_CHEAT: Int = 187 + const val CONSOLE_FEEDBACK: Int = 188 + const val EXECUTE_CLIENT_CHEAT: Int = 189 + const val SET_NPC_ATTACK_PRIORITY: Int = 190 + const val LOBBY_APPEARANCE: Int = 191 + const val IF_SETOBJECT_LONG_V2: Int = 192 + const val OBJ_COUNT_V2: Int = 193 + const val CREATE_CHECK_EMAIL_REPLY: Int = 194 + const val LOCSELECT_ADD: Int = 195 + const val SEND_PING: Int = 196 + const val MESSAGE_PLAYER_GROUP: Int = 197 + const val MAP_PROJANIM_V2: Int = 198 + const val SOUND_STOP: Int = 199 + const val STORE_RESET: Int = 200 + const val ENVIRONMENT_OVERRIDE: Int = 201 + const val MESSAGE_QUICKCHAT_PLAYER_GROUP: Int = 202 + const val SOCIAL_NETWORK_LOGOUT: Int = 204 + const val MAP_ANIM_V2: Int = 205 + const val DBFILTER_DEBUG: Int = 206 + const val TELEMETRY_GRID_ADD_COLUMN: Int = 207 + const val TELEMETRY_CLEAR_GRID_VALUE: Int = 208 + const val TELEMETRY_GRID_MOVE_COLUMN: Int = 209 + const val LOGOUT_TRANSFER: Int = 210 + const val UPDATE_DOB: Int = 211 + const val CLIENT_SETVARC_LONG: Int = 212 + const val TELEMETRY_GRID_ADD_GROUP: Int = 213 + const val SPOTANIM_SPECIFIC_V2: Int = 214 + const val CREATE_SUGGEST_NAME_ERROR: Int = 215 + const val IF_SETRETEX: Int = 216 + const val JS5_RELOAD: Int = 217 + const val LOYALTY_UPDATE: Int = 218 + const val LOCSELECT_CONFIGURE: Int = 219 + const val CLEAR_PLAYER_SNAPSHOT: Int = 220 + const val PLAYER_ANIM_SPECIFIC: Int = 221 + const val TEXT_COORD: Int = 222 + const val SET_TARGET: Int = 223 + const val UNNAMED_2: Int = 224 + const val SYNC_CLOCK: Int = 225 +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/GameZoneProt.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/GameZoneProt.kt new file mode 100644 index 00000000..1bda2976 --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/GameZoneProt.kt @@ -0,0 +1,14 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot + +import net.rsprot.protocol.ClientProt +import net.rsprot.protocol.Prot + +internal enum class GameZoneProt( + override val opcode: Int, + override val size: Int, +) : ClientProt { + SOUND_AREA_V2(9, 11), + OBJ_REVEAL(14, 8), + OBJ_REVEAL_V3(16, Prot.VAR_BYTE), + OBJ_ADD_V2(20, 6), +} diff --git a/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/ServerMessageDecodeRepository.kt b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/ServerMessageDecodeRepository.kt new file mode 100644 index 00000000..ea0e4ddc --- /dev/null +++ b/protocol/rs3-950-beta/src/main/kotlin/net/rsprox/protocol/rs3v950beta/game/outgoing/decoder/prot/ServerMessageDecodeRepository.kt @@ -0,0 +1,460 @@ +package net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot + +import net.rsprot.compression.HuffmanCodec +import net.rsprot.crypto.cipher.StreamCipher +import net.rsprot.protocol.ProtRepository +import net.rsprox.protocol.MessageDecoderRepository +import net.rsprox.protocol.MessageDecoderRepositoryBuilder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account.CreateAccountReplyDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account.CreateCheckEmailReplyDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account.CreateCheckNameReplyDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account.CreateSuggestNameErrorDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account.CreateSuggestNameReplyDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account.FriendlistLoadedDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.account.UpdateDobDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.appearance.LobbyAppearanceDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.appearance.PlayerSnapshotDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera.Cam2EnableDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera.CamForceAngleDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera.CamLookAtDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera.CamMoveToDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera.CamRemoveRoofDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera.CamResetDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera.CamShakeDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera.CamSmoothResetDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.camera.CameraUpdateDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.clan.ClanChannelDeltaDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.clan.ClanChannelFullDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.clan.ClanSettingsDeltaDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.clan.ClanSettingsFullDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.debug.DbFilterDebugDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.group.PlayerGroupDeltaDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.group.PlayerGroupFullDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.group.PlayerGroupVarpsDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.npcinfo.NpcInfoClient +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.info.playerinfo.PlayerInfoDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfCloseSubDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfMoveSubDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfOpenSubActiveLocDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfOpenSubActiveNpcDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfOpenSubActiveObjDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfOpenSubActivePlayerDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfOpenSubDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfOpenTopDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetAngleDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetAnimDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetClickMaskDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetColourDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetEventsDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetGraphicDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetHideDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetHttpImageDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetModelDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetNpcHeadDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetObjectDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetObjectLongV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetPlayerHeadDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetPlayerHeadIgnoreWornDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetPlayerHeadOtherDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetPlayerHeadSnapshotDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetPlayerModelOtherDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetPlayerModelSelfDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetPlayerModelSnapshotDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetPositionDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetRecolDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetRetexDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetScrollPosDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetTargetParamDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetTextAntiMacroDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetTextDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.interfaces.IfSetTextFontDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.inv.UpdateInvFullDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.inv.UpdateInvPartialDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.inv.UpdateInvStopTransmitDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.EnvironmentOverrideDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.RebuildNormalDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.RebuildRegionDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.ReconnectDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting.PointLightAttenuationFalloffDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting.PointLightColourDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting.PointLightEnabledDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting.PointLightExtendAboveDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting.PointLightExtendBelowDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting.PointLightIntensityScaleDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.map.lighting.PointLightShadowDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.ChangeLobbyDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.ConsoleFeedbackDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.Cutscene2dPlayDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.DebugServerTriggersDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.DoCheatDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.ExecuteClientCheatDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.HintArrowDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.HintTrailDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.Js5ReloadDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.LogoutDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.LogoutFullDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.LogoutTransferDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.MinimapToggleDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.NoTimeoutDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.ResetAnimsDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.SendPingDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.SetDrawOrderDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.ShowFaceHereDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.StoreResetDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.StoreServerpermVarcsAckDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.SyncClockDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.TickEndDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.TriggerOnDialogAbortDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.Unnamed1Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.Unnamed2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.UpdateRebootTimerDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.client.UpdateUid192Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.ChatFilterSettingsDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.ChatFilterSettingsPrivateChatDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.ClearPlayerSnapshotDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.JcoinsUpdateDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.LastLoginInfoDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.LoyaltyUpdateDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.MessageGameDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.RunClientScriptDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.SetMapFlagDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.SetMoveActionDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.SetNpcAttackPriorityDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.SetPlayerAttackPriorityDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.SetPlayerOpDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.SetTargetDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.UpdateRunEnergyDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.UpdateRunWeightDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.UpdateStatDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.misc.player.UpdateStockmarketSlotV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.selection.LocSelectAddDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.selection.LocSelectClearDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.selection.LocSelectConfigureDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.selection.SetLocOpOverrideDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessageClanchannelDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessageClanchannelSystemDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessageFriendchannelDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessagePlayerGroupDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessagePrivateDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessagePrivateEchoDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessagePublicDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessageQuickchatClanchannelDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessageQuickchatFriendchatDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessageQuickchatPlayerGroupDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessageQuickchatPrivateDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.MessageQuickchatPrivateEchoDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.SocialNetworkLogoutDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.UpdateFriendchatChannelFullDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.UpdateFriendchatChannelSingleUserDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.UpdateFriendlistDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.UpdateIgnorelistDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.social.UrlOpenDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.MidiJingleDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.MidiSongDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.MidiSongStopDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.SongPreloadDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.SoundMixbussAddDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.SoundMixbussSetLevelDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.SoundStopDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.SynthSoundDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.VorbisPreloadSoundsDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.VorbisSoundDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.VorbisSoundGroupDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.VorbisSoundGroupStartDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.VorbisSoundGroupStopDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.VorbisSpeechSoundDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.sound.VorbisSpeechStopDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific.LocAnimSpecificDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific.NpcAnimSpecificDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific.NpcHeadiconSpecificDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific.NpcSaySpecificDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific.PlayerAnimSpecificDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific.ProjAnimSpecificDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific.ProjAnimSpecificV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific.SpotanimSpecificDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.specific.SpotanimSpecificV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryClearGridValueDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryGridAddColumnDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryGridAddGroupDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryGridAddRowDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryGridFullDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryGridMoveColumnDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryGridMoveRowDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryGridRemoveColumnDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryGridRemoveGroupDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryGridRemoveRowDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryGridSetRowPinnedDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.telemetry.TelemetryGridValuesDeltaDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varbit.VarbitDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varbit.VarbitLargeDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varbit.VarbitSmallDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc.ResetClientVarcacheDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc.VarcBitDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc.VarcBitLargeDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc.VarcBitSmallDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc.VarcLargeDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc.VarcLongDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc.VarcSmallDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc.VarcStrLargeDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varc.VarcStrSmallDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varclan.VarclanDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varclan.VarclanDisableDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varclan.VarclanEnableDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varp.VarpLargeDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varp.VarpLongDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.varp.VarpSmallDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.world.WorldlistFetchReplyDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.header.UpdateZoneFullFollowsDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.header.UpdateZonePartialEnclosedDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.header.UpdateZonePartialFollowsDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.LocAddChangeDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.LocAnimDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.LocCustomiseDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.LocDelDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.LocPrefetchDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapAnimV1Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapAnimV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapProjAnimDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapProjAnimHalfsqDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapProjAnimHalfsqV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MapProjAnimV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.MidiSongLocationDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.ObjAddV3Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.ObjCountV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.ObjCountV3Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.ObjDelDecoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.SoundAreaV1Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.StandaloneObjAddV2Decoder +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.codec.zone.payload.TextCoordDecoder + +internal object ServerMessageDecoderRepository { + @ExperimentalStdlibApi + fun build( + huffmanCodec: HuffmanCodec? = null, + cipher: () -> StreamCipher? = { null }, + ): MessageDecoderRepository = + MessageDecoderRepositoryBuilder(ProtRepository.of()) + .apply { + bind(ChatFilterSettingsPrivateChatDecoder()) + bind(UpdateUid192Decoder()) + bind(Cutscene2dPlayDecoder()) + bind(CamShakeDecoder()) + bind(CamLookAtDecoder()) + bind(SoundMixbussSetLevelDecoder()) + bind(CamMoveToDecoder()) + bind(TriggerOnDialogAbortDecoder()) + bind(CamSmoothResetDecoder()) + bind(CamForceAngleDecoder()) + bind(FriendlistLoadedDecoder()) + bind(MidiJingleDecoder()) + bind(MidiSongDecoder()) + bind(MidiSongStopDecoder()) + bind(SongPreloadDecoder()) + bind(SoundMixbussAddDecoder()) + bind(VorbisPreloadSoundsDecoder()) + bind(VorbisSoundGroupDecoder()) + bind(VorbisSoundGroupStartDecoder()) + bind(VorbisSoundGroupStopDecoder()) + bind(VorbisSpeechSoundDecoder()) + bind(VorbisSpeechStopDecoder()) + bind(ObjAddV3Decoder()) + bind(ObjCountV2Decoder()) + bind(ObjDelDecoder()) + bind(LocPrefetchDecoder()) + bind(LocAnimDecoder()) + bind(LocAddChangeDecoder()) + bind(LocCustomiseDecoder()) + bind(LocDelDecoder()) + bind(MapAnimV1Decoder()) + bind(MapAnimV2Decoder()) + bind(MapProjAnimDecoder()) + bind(MapProjAnimV2Decoder()) + bind(MapProjAnimHalfsqDecoder()) + bind(MapProjAnimHalfsqV2Decoder()) + bind(SoundAreaV1Decoder()) + bind(ObjCountV3Decoder()) + bind(UpdateZonePartialEnclosedDecoder()) + bind(UpdateZonePartialFollowsDecoder()) + bind(SetPlayerAttackPriorityDecoder()) + bind(SetNpcAttackPriorityDecoder()) + bind(SetTargetDecoder()) + bind(UpdateRunEnergyDecoder()) + bind(UpdateRunWeightDecoder()) + bind(ChatFilterSettingsDecoder()) + bind(UpdateRebootTimerDecoder()) + bind(CamResetDecoder()) + bind(Cam2EnableDecoder()) + bind(MinimapToggleDecoder()) + bind(SetDrawOrderDecoder()) + bind(ShowFaceHereDecoder()) + bind(IfSetPlayerHeadSnapshotDecoder()) + bind(IfSetPlayerModelSnapshotDecoder()) + bind(IfSetPlayerHeadIgnoreWornDecoder()) + bind(IfSetPlayerHeadOtherDecoder()) + bind(IfSetPlayerHeadDecoder()) + bind(IfSetNpcHeadDecoder()) + bind(IfSetModelDecoder()) + bind(IfSetPlayerModelSelfDecoder()) + bind(IfSetPlayerModelOtherDecoder()) + bind(IfSetAngleDecoder()) + bind(IfSetTextAntiMacroDecoder()) + bind(IfSetClickMaskDecoder()) + bind(IfSetColourDecoder()) + bind(IfSetTextFontDecoder()) + bind(IfSetAnimDecoder()) + bind(IfSetGraphicDecoder()) + bind(IfSetHideDecoder()) + bind(IfSetScrollPosDecoder()) + bind(IfSetPositionDecoder()) + bind(IfSetEventsDecoder()) + bind(IfSetTargetParamDecoder()) + bind(IfSetRecolDecoder()) + bind(IfSetRetexDecoder()) + bind(VarpSmallDecoder()) + bind(VarpLargeDecoder()) + bind(VarpLongDecoder()) + bind(VarcSmallDecoder()) + bind(VarcLargeDecoder()) + bind(VarcLongDecoder()) + bind(VarbitSmallDecoder()) + bind(VarbitLargeDecoder()) + bind(VarcBitSmallDecoder()) + bind(VarcBitLargeDecoder()) + bind(UpdateDobDecoder()) + bind(CreateSuggestNameErrorDecoder()) + bind(CreateCheckNameReplyDecoder()) + bind(CreateCheckEmailReplyDecoder()) + bind(CreateAccountReplyDecoder()) + bind(VarclanEnableDecoder()) + bind(VarclanDisableDecoder()) + bind(LogoutDecoder()) + bind(LogoutFullDecoder()) + bind(LoyaltyUpdateDecoder()) + bind(LastLoginInfoDecoder()) + bind(JcoinsUpdateDecoder()) + bind(SyncClockDecoder()) + bind(StoreServerpermVarcsAckDecoder()) + bind(StoreResetDecoder()) + bind(CamRemoveRoofDecoder()) + bind(UpdateInvStopTransmitDecoder()) + bind(ResetClientVarcacheDecoder()) + bind(SetMapFlagDecoder()) + bind(ResetAnimsDecoder()) + bind(SetMoveActionDecoder()) + bind(TelemetryClearGridValueDecoder()) + bind(TelemetryGridMoveColumnDecoder()) + bind(TelemetryGridMoveRowDecoder()) + bind(TelemetryGridSetRowPinnedDecoder()) + bind(TelemetryGridAddColumnDecoder()) + bind(TelemetryGridAddGroupDecoder()) + bind(TelemetryGridAddRowDecoder()) + bind(TelemetryGridRemoveColumnDecoder()) + bind(TelemetryGridRemoveGroupDecoder()) + bind(TelemetryGridRemoveRowDecoder()) + bind(TelemetryGridValuesDeltaDecoder()) + bind(TelemetryGridFullDecoder()) + bind(SetPlayerOpDecoder()) + bind(SetLocOpOverrideDecoder()) + bind(IfSetTextDecoder()) + bind(VarcStrSmallDecoder()) + bind(VarcStrLargeDecoder()) + bind(CreateSuggestNameReplyDecoder()) + bind(ChangeLobbyDecoder()) + bind(LogoutTransferDecoder()) + bind(NpcSaySpecificDecoder()) + bind(NpcAnimSpecificDecoder()) + bind(IfCloseSubDecoder()) + bind(IfSetObjectDecoder()) + bind(IfMoveSubDecoder()) + bind(VarbitDecoder()) + bind(VarcBitDecoder()) + bind(IfSetHttpImageDecoder()) + bind(NpcHeadiconSpecificDecoder()) + bind(IfSetObjectLongV2Decoder()) + bind(PlayerAnimSpecificDecoder()) + bind(IfOpenTopDecoder()) + bind(IfOpenSubDecoder()) + bind(IfOpenSubActiveNpcDecoder()) + bind(IfOpenSubActivePlayerDecoder()) + bind(IfOpenSubActiveObjDecoder()) + bind(PointLightExtendAboveDecoder()) + bind(PointLightExtendBelowDecoder()) + bind(PointLightAttenuationFalloffDecoder()) + bind(PointLightIntensityScaleDecoder()) + bind(PointLightColourDecoder()) + bind(PointLightEnabledDecoder()) + bind(PointLightShadowDecoder()) + bind(ClearPlayerSnapshotDecoder()) + bind(ProjAnimSpecificDecoder()) + bind(ProjAnimSpecificV2Decoder()) + bind(MidiSongLocationDecoder()) + bind(SpotanimSpecificDecoder()) + bind(SpotanimSpecificV2Decoder()) + bind(DebugServerTriggersDecoder()) + bind(LocSelectClearDecoder()) + bind(MessagePrivateEchoDecoder(huffmanCodec)) + bind(MessageQuickchatPrivateEchoDecoder()) + bind(Unnamed1Decoder()) + bind(Unnamed2Decoder()) + bind(Js5ReloadDecoder()) + bind(IfOpenSubActiveLocDecoder()) + bind(MessagePrivateDecoder(huffmanCodec)) + bind(MessageQuickchatPrivateDecoder()) + bind(MessagePlayerGroupDecoder(huffmanCodec)) + bind(MessageFriendchannelDecoder(huffmanCodec)) + bind(SendPingDecoder()) + bind(MessageQuickchatFriendchatDecoder()) + bind(MessageQuickchatPlayerGroupDecoder()) + bind(MessageQuickchatClanchannelDecoder()) + bind(MessageClanchannelDecoder(huffmanCodec)) + bind(MessageClanchannelSystemDecoder(huffmanCodec)) + bind(UpdateZoneFullFollowsDecoder()) + bind(UpdateInvFullDecoder()) + bind(UpdateInvPartialDecoder()) + bind(UpdateFriendchatChannelFullDecoder()) + bind(LocAnimSpecificDecoder()) + bind(LocSelectAddDecoder()) + bind(UpdateFriendchatChannelSingleUserDecoder()) + bind(ClanChannelFullDecoder()) + bind(ExecuteClientCheatDecoder()) + bind(MessageGameDecoder()) + bind(UpdateStatDecoder()) + bind(UpdateStockmarketSlotV2Decoder()) + bind(LocSelectConfigureDecoder()) + bind(SoundStopDecoder()) + bind(WorldlistFetchReplyDecoder()) + bind(TickEndDecoder(GameServerProt.SERVER_TICK_END)) + bind(ClanChannelDeltaDecoder()) + bind(PlayerGroupVarpsDecoder()) + bind(DoCheatDecoder()) + bind(HintTrailDecoder()) + bind(RunClientScriptDecoder()) + bind(MessagePublicDecoder(huffmanCodec)) + bind(SocialNetworkLogoutDecoder(cipher)) + bind(UpdateFriendlistDecoder()) + bind(UpdateIgnorelistDecoder()) + bind(UrlOpenDecoder(cipher)) + bind(VarclanDecoder()) + bind(HintArrowDecoder()) + bind(StandaloneObjAddV2Decoder()) + bind(ClanSettingsFullDecoder()) + bind(ConsoleFeedbackDecoder()) + bind(DbFilterDebugDecoder()) + bind(LobbyAppearanceDecoder()) + bind(PlayerSnapshotDecoder()) + bind(PlayerGroupDeltaDecoder()) + bind(PlayerGroupFullDecoder()) + bind(ClanSettingsDeltaDecoder()) + bind(EnvironmentOverrideDecoder()) + bind(TextCoordDecoder()) + bind(CameraUpdateDecoder()) + bind(PlayerInfoDecoder()) + bind(NpcInfoClient()) + bind(RebuildNormalDecoder()) + bind(RebuildRegionDecoder()) + bind(SynthSoundDecoder()) + bind(VorbisSoundDecoder()) + bind(NoTimeoutDecoder()) + bind(ReconnectDecoder()) + }.build() +} diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/incoming/model/events/GameLogEvent.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/incoming/model/events/GameLogEvent.kt new file mode 100644 index 00000000..b2d53249 --- /dev/null +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/incoming/model/events/GameLogEvent.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3.game.incoming.model.events + +import net.rsprot.protocol.ClientProtCategory +import net.rsprot.protocol.message.IncomingGameMessage +import net.rsprox.protocol.game.incoming.model.GameClientProtCategory +import net.rsprox.protocol.rs3.common.TypedVariable + +public data class GameLogEvent( + public val id: Int, + public val value16: Int, + public val script: Int, + public val arguments: List, +) : IncomingGameMessage { + override val category: ClientProtCategory + get() = GameClientProtCategory.CLIENT_EVENT + + public data class Argument( + public val scriptType: Int, + public val value: TypedVariable.Value, + ) +} diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/incoming/model/events/UnnamedBatch80.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/incoming/model/events/UnnamedBatch80.kt new file mode 100644 index 00000000..67f520ac --- /dev/null +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/incoming/model/events/UnnamedBatch80.kt @@ -0,0 +1,21 @@ +package net.rsprox.protocol.rs3.game.incoming.model.events + +import net.rsprot.protocol.ClientProtCategory +import net.rsprot.protocol.message.IncomingGameMessage +import net.rsprox.protocol.game.incoming.model.GameClientProtCategory + +/** Lua-plugin report; field meanings remain under investigation. */ +public data class UnnamedBatch80( + public val complete: Boolean, + public val entries: List, +) : IncomingGameMessage { + override val category: ClientProtCategory + get() = GameClientProtCategory.CLIENT_EVENT + + public data class Entry( + public val field0: Int, + public val field1: Int, + public val field2: Int, + public val field3: Int, + ) +} diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/incoming/model/events/UnnamedEvent92.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/incoming/model/events/UnnamedEvent92.kt new file mode 100644 index 00000000..4826e489 --- /dev/null +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/incoming/model/events/UnnamedEvent92.kt @@ -0,0 +1,17 @@ +package net.rsprox.protocol.rs3.game.incoming.model.events + +import net.rsprot.protocol.ClientProtCategory +import net.rsprot.protocol.message.IncomingGameMessage +import net.rsprox.protocol.game.incoming.model.GameClientProtCategory + +/** Lua-plugin event; field meanings remain under investigation. */ +public data class UnnamedEvent92( + public val field0: Int, + public val field1: Int, + public val field2: Int, + public val field3: Int, + public val field4: Int, +) : IncomingGameMessage { + override val category: ClientProtCategory + get() = GameClientProtCategory.CLIENT_EVENT +} diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/info/npcinfo/extendedinfo/UnusedExtendedInfo.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/info/npcinfo/extendedinfo/UnusedExtendedInfo.kt new file mode 100644 index 00000000..4429d158 --- /dev/null +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/info/npcinfo/extendedinfo/UnusedExtendedInfo.kt @@ -0,0 +1,7 @@ +package net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.extendedinfo + +/** Parsed native-discarded fields without an established cross-revision identity. */ +public data class UnusedExtendedInfo( + public val bit: Int, + public val fields: List, +) : NpcExtendedInfo diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/info/playerinfo/extendedinfo/PlayerExtendedInfo.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/info/playerinfo/extendedinfo/PlayerExtendedInfo.kt index 1f4eed5d..e69e6e93 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/info/playerinfo/extendedinfo/PlayerExtendedInfo.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/info/playerinfo/extendedinfo/PlayerExtendedInfo.kt @@ -226,6 +226,12 @@ public sealed interface PlayerExtendedInfo { } } + /** Discarded fields without an established cross-revision identity. Bit is the wire mask index. */ + public data class UnusedFields( + public val bit: Int, + public val fields: List, + ) : PlayerExtendedInfo + public data class SayV2( public val text: String, public val chatbox: Boolean, diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSub.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSub.kt index 8752733f..6234c516 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSub.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSub.kt @@ -10,4 +10,6 @@ public data class IfOpenSub( public val legacyWord1: Int? = null, public val legacyWord2: Int? = null, public val legacyWord3: Int? = null, + // Native-skipped bytes in revisions which no longer read the legacy words. + public val reserved: List = emptyList(), ) : IncomingServerGameMessage diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveLoc.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveLoc.kt index b7d6c13f..55ed3fc2 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveLoc.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveLoc.kt @@ -10,10 +10,11 @@ public class IfOpenSubActiveLoc( public val shape: Int, public val rotation: Int, public val coord: Int, - public val extra1: Int, - public val extra2: Int, - public val extra3: Int, - public val extra4: Int, + public val extra1: Int?, + public val extra2: Int?, + public val extra3: Int?, + public val extra4: Int?, + public val reserved: List = emptyList(), ) : IncomingServerGameMessage { override fun equals(other: Any?): Boolean { if (this === other) return true @@ -33,6 +34,8 @@ public class IfOpenSubActiveLoc( if (extra3 != other.extra3) return false if (extra4 != other.extra4) return false + if (reserved != other.reserved) return false + return true } @@ -44,16 +47,17 @@ public class IfOpenSubActiveLoc( result = 31 * result + shape result = 31 * result + rotation result = 31 * result + coord - result = 31 * result + extra1 - result = 31 * result + extra2 - result = 31 * result + extra3 - result = 31 * result + extra4 + result = 31 * result + (extra1 ?: 0) + result = 31 * result + (extra2 ?: 0) + result = 31 * result + (extra3 ?: 0) + result = 31 * result + (extra4 ?: 0) + result = 31 * result + reserved.hashCode() return result } override fun toString(): String { return "IfOpenSubActiveLoc(componentHash=$componentHash, locId=$locId, childId=$childId, " + "layer=$layer, shape=$shape, rotation=$rotation, coord=$coord, " + - "extra1=$extra1, extra2=$extra2, extra3=$extra3, extra4=$extra4)" + "extra1=$extra1, extra2=$extra2, extra3=$extra3, extra4=$extra4, reserved=$reserved)" } } diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveNpc.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveNpc.kt index f4dc4d65..914a8f51 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveNpc.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveNpc.kt @@ -3,12 +3,14 @@ package net.rsprox.protocol.rs3.game.outgoing.model.interfaces import net.rsprox.protocol.game.outgoing.model.IncomingServerGameMessage public data class IfOpenSubActiveNpc( - public val legacyWord0: Int, + public val legacyWord0: Int?, public val npcIndex: Int, public val childId: Int, - public val legacyWord1: Int, + public val legacyWord1: Int?, public val componentHash: Long, - public val legacyWord2: Int, - public val legacyWord3: Int, + public val legacyWord2: Int?, + public val legacyWord3: Int?, public val layer: Int, + // Native-skipped bytes in revisions which no longer read the legacy words. + public val reserved: List = emptyList(), ) : IncomingServerGameMessage diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveObj.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveObj.kt index da76c8c7..af5dce6a 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveObj.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActiveObj.kt @@ -8,10 +8,12 @@ public class IfOpenSubActiveObj( public val objId: Int, public val layer: Int, public val coord: Int, - public val extra1: Int, - public val extra2: Int, - public val extra3: Int, - public val extra4: Int, + public val extra1: Int?, + public val extra2: Int?, + public val extra3: Int?, + public val extra4: Int?, + // Native-skipped bytes in revisions which no longer read the legacy words. + public val reserved: List = emptyList(), ) : IncomingServerGameMessage { override fun equals(other: Any?): Boolean { if (this === other) return true @@ -29,6 +31,8 @@ public class IfOpenSubActiveObj( if (extra3 != other.extra3) return false if (extra4 != other.extra4) return false + if (reserved != other.reserved) return false + return true } @@ -38,15 +42,16 @@ public class IfOpenSubActiveObj( result = 31 * result + objId result = 31 * result + layer result = 31 * result + coord - result = 31 * result + extra1 - result = 31 * result + extra2 - result = 31 * result + extra3 - result = 31 * result + extra4 + result = 31 * result + (extra1 ?: 0) + result = 31 * result + (extra2 ?: 0) + result = 31 * result + (extra3 ?: 0) + result = 31 * result + (extra4 ?: 0) + result = 31 * result + reserved.hashCode() return result } override fun toString(): String { return "IfOpenSubActiveObj(componentHash=$componentHash, childId=$childId, objId=$objId, " + - "layer=$layer, coord=$coord, extra1=$extra1, extra2=$extra2, extra3=$extra3, extra4=$extra4)" + "layer=$layer, coord=$coord, extra1=$extra1, extra2=$extra2, extra3=$extra3, extra4=$extra4, reserved=$reserved)" } } diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActivePlayer.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActivePlayer.kt index f3eb6c48..b6f8663d 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActivePlayer.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenSubActivePlayer.kt @@ -3,12 +3,14 @@ package net.rsprox.protocol.rs3.game.outgoing.model.interfaces import net.rsprox.protocol.game.outgoing.model.IncomingServerGameMessage public data class IfOpenSubActivePlayer( - public val legacyWord0: Int, - public val legacyWord1: Int, + public val legacyWord0: Int?, + public val legacyWord1: Int?, public val playerIndex: Int, public val componentHash: Long, - public val legacyWord2: Int, - public val legacyWord3: Int, + public val legacyWord2: Int?, + public val legacyWord3: Int?, public val childId: Int, public val layer: Int, + // Native-skipped bytes in revisions which no longer read the legacy words. + public val reserved: List = emptyList(), ) : IncomingServerGameMessage diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenTop.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenTop.kt index 7b98e627..2398bb37 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenTop.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/interfaces/IfOpenTop.kt @@ -9,4 +9,6 @@ public data class IfOpenTop( public val legacyWord2: Int? = null, public val unused: Int? = null, public val legacyWord3: Int? = null, + // Native-skipped bytes in revisions which no longer read the legacy words. + public val reserved: List = emptyList(), ) : IncomingServerGameMessage diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/misc/client/Unnamed2.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/misc/client/Unnamed2.kt index 86931de1..2ba33e16 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/misc/client/Unnamed2.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/misc/client/Unnamed2.kt @@ -5,7 +5,8 @@ import net.rsprox.protocol.game.outgoing.model.IncomingServerGameMessage public data class Unnamed2( public val count: Int, public val records: List, - public val discardedFooter: Int, + public val discardedFooter: Int?, + public val reservedFooter: List = emptyList(), ) : IncomingServerGameMessage { public data class Record( public val unused0: Int, diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjAdd.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjAdd.kt index 76a67ae3..302d4bd7 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjAdd.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjAdd.kt @@ -8,8 +8,11 @@ public class ObjAdd( public val count: Int, public val xInZone: Int, public val zInZone: Int, + public val version: Int = if (big) 2 else 1, + public val coordinateFlags: Int? = null, ) : IncomingServerGameMessage { override fun toString(): String { - return "ObjAdd(big=$big, objId=$objId, count=$count, xInZone=$xInZone, zInZone=$zInZone)" + return "ObjAdd(big=$big, objId=$objId, count=$count, xInZone=$xInZone, zInZone=$zInZone, " + + "version=$version, coordinateFlags=$coordinateFlags)" } } diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjCount.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjCount.kt index 4424dca4..ea768c2c 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjCount.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjCount.kt @@ -9,8 +9,11 @@ public class ObjCount( public val newQuantity: Int, public val xInZone: Int, public val zInZone: Int, + public val version: Int = if (big) 2 else 1, + public val coordinateFlags: Int? = null, ) : IncomingServerGameMessage { override fun toString(): String { - return "ObjCount(big=$big, objId=$objId, oldQuantity=$oldQuantity, newQuantity=$newQuantity, xInZone=$xInZone, zInZone=$zInZone)" + return "ObjCount(big=$big, objId=$objId, oldQuantity=$oldQuantity, newQuantity=$newQuantity, " + + "xInZone=$xInZone, zInZone=$zInZone, version=$version, coordinateFlags=$coordinateFlags)" } } diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjDel.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjDel.kt index 5aff7395..af291636 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjDel.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjDel.kt @@ -7,8 +7,9 @@ public class ObjDel( public val objId: Int, public val xInZone: Int, public val zInZone: Int, + public val coordinateFlags: Int? = null, ) : IncomingServerGameMessage { override fun toString(): String { - return "ObjDel(big=$big, objId=$objId, xInZone=$xInZone, zInZone=$zInZone)" + return "ObjDel(big=$big, objId=$objId, xInZone=$xInZone, zInZone=$zInZone, coordinateFlags=$coordinateFlags)" } } diff --git a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjReveal.kt b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjReveal.kt index 2f59617c..e6f638c2 100644 --- a/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjReveal.kt +++ b/protocol/src/main/kotlin/net/rsprox/protocol/rs3/game/outgoing/model/zone/payload/ObjReveal.kt @@ -9,9 +9,10 @@ public class ObjReveal( public val excludedPlayerIndex: Int, public val xInZone: Int, public val zInZone: Int, + public val version: Int = if (big) 2 else 1, ) : IncomingServerGameMessage { override fun toString(): String { return "ObjReveal(big=$big, objId=$objId, count=$count, excludedPlayerIndex=$excludedPlayerIndex, " + - "xInZone=$xInZone, zInZone=$zInZone)" + "xInZone=$xInZone, zInZone=$zInZone, version=$version)" } } diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/ProxyService.kt b/proxy/src/main/kotlin/net/rsprox/proxy/ProxyService.kt index ada0db3d..841bd1d9 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/ProxyService.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/ProxyService.kt @@ -38,6 +38,7 @@ import net.rsprox.proxy.config.ProxyProperty.Companion.PROXY_PORT_MIN import net.rsprox.proxy.config.ProxyProperty.Companion.RUNELITE_RSPROX_CONNECTION import net.rsprox.proxy.config.ProxyProperty.Companion.SELECTED_CLIENT import net.rsprox.proxy.config.ProxyProperty.Companion.SELECTED_PROXY_TARGET +import net.rsprox.proxy.config.ProxyProperty.Companion.SELECTED_RS3_BETA import net.rsprox.proxy.config.ProxyProperty.Companion.WORLDLIST_ENDPOINT import net.rsprox.proxy.connection.ClientTypeDictionary import net.rsprox.proxy.connection.ProxyConnectionContainer @@ -55,9 +56,11 @@ import net.rsprox.proxy.replay.ReplaySession import net.rsprox.proxy.replay.ReplayTimeline import net.rsprox.proxy.replay.ReplayTranscriber import net.rsprox.proxy.replay.ReplayTranscript +import net.rsprox.proxy.rs3.Rs3BetaClientBuild import net.rsprox.proxy.rs3.Rs3ClientHandle import net.rsprox.proxy.rs3.Rs3LaunchProgress import net.rsprox.proxy.rs3.Rs3LaunchTracker +import net.rsprox.proxy.rs3.Rs3ProtocolRevision import net.rsprox.proxy.rs3.Rs3SessionMonitor import net.rsprox.proxy.rs3.config.Rs3JavConfig import net.rsprox.proxy.rs3.gameval.Rs3GamevalLookup @@ -96,6 +99,7 @@ import org.newsclub.net.unix.AFUNIXSocketAddress import java.io.File import java.io.IOException import java.math.BigInteger +import java.net.URI import java.net.URL import java.nio.file.Files import java.nio.file.LinkOption @@ -512,6 +516,15 @@ public class ProxyService( return properties.getPropertyOrNull(SELECTED_CLIENT) ?: 0 } + public fun setSelectedRs3Beta(selected: Boolean) { + properties.setProperty(SELECTED_RS3_BETA, selected) + properties.saveProperties(PROPERTIES_FILE) + } + + public fun getSelectedRs3Beta(): Boolean { + return properties.getPropertyOrNull(SELECTED_RS3_BETA) ?: false + } + public fun getSelectedProxyTarget(): Int { val lastSelected = properties.getPropertyOrNull(SELECTED_PROXY_TARGET) ?: 0 if (lastSelected in proxyTargets.indices) { @@ -966,7 +979,13 @@ public class ProxyService( character: JagexCharacter?, upstreamJavConfigUrl: String = JagexNativeClientDownloader.DEFAULT_RS3_JAV_CONFIG_URL, onProgress: (Rs3LaunchProgress) -> Unit = {}, + beta: Boolean = false, ): Rs3ClientHandle { + require(URI(upstreamJavConfigUrl).path.endsWith("/jav_config_beta.ws") == beta) { + "RS3 client channel and javconfig must match" + } + val protocolRevision = + Rs3ProtocolRevision.of(950, if (beta) 1 else 0) val renderer = when (JagexNativeClientDownloader.rs3BinaryType(upstreamJavConfigUrl)) { 2 -> "OpenGL" @@ -990,6 +1009,15 @@ public class ProxyService( upstreamJavConfigUrl, progress::update, ) + if (beta) { + progress.update(Rs3LaunchProgress("Verifying beta client build")) + check( + Rs3BetaClientBuild.verify( + downloaded, + JagexNativeClientDownloader.rs3BinaryType(upstreamJavConfigUrl), + ) == protocolRevision, + ) + } val extension = if (downloaded.extension.isNotEmpty()) ".${downloaded.extension}" else "" val stamp = System.currentTimeMillis() val path = @@ -1006,7 +1034,7 @@ public class ProxyService( NativePatchCriteria .Builder(NativeClientType.RS3_WIN) .rsaModulus(modulusHex) - .rs3LoginPorts(localPorts.primary, localPorts.alternate) + .rs3LoginPorts(localPorts.primary, localPorts.alternate, beta) .rs3WindowTitle() .build() val gameClientPatchResult = patcher.patch(patchedGameBinaryPath, gameCriteria) @@ -1021,8 +1049,8 @@ public class ProxyService( progress.update(Rs3LaunchProgress("Loading server configuration")) val upstreamConfig = Rs3JavConfig(URL(upstreamJavConfigUrl)) val targets = upstreamConfig.captureUpstreamTargets() - require(targets.revision == 950) { - "Mapped RS3 routing is currently verified only for the live revision-950 profile" + require(targets.revision == protocolRevision.wireRevision) { + "RS3 configuration revision does not match the selected protocol" } // Bootstrap on the launch worker, before relay event loops see any game packets. val cacheResolver = Rs3LiveCacheResolver(upstreamConfig.captureJs5ConnectionInfo()) @@ -1044,7 +1072,7 @@ public class ProxyService( proxyPrivateKey = proxyKey, sessionMonitor = sessionMonitor, realServerModulusHex = originalModulusHex, - revision = targets.revision, + revision = protocolRevision.value, packetDefinitions = packetDefinitions, clientScripts = clientScripts, masterIndex = cacheResolver.masterIndexSnapshot, diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/config/ProxyProperty.kt b/proxy/src/main/kotlin/net/rsprox/proxy/config/ProxyProperty.kt index 1b6a6779..3eda7f60 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/config/ProxyProperty.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/config/ProxyProperty.kt @@ -23,6 +23,7 @@ public class ProxyProperty( val APP_POSITION_Y = ProxyProperty("app.position.y", IntProperty) val FILTERS_STATUS = ProxyProperty("filters.status", IntProperty) val SELECTED_CLIENT = ProxyProperty("app.client", IntProperty) + val SELECTED_RS3_BETA = ProxyProperty("app.rs3.beta", BooleanProperty) val SELECTED_PROXY_TARGET = ProxyProperty("app.target", IntProperty) // other diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/downloader/JagexNativeClientDownloader.kt b/proxy/src/main/kotlin/net/rsprox/proxy/downloader/JagexNativeClientDownloader.kt index f352d0e1..34755a2b 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/downloader/JagexNativeClientDownloader.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/downloader/JagexNativeClientDownloader.kt @@ -27,6 +27,13 @@ public data object JagexNativeClientDownloader { public const val VULKAN_RS3_JAV_CONFIG_URL: String = "https://world5.runescape.com/jav_config.ws?binaryType=10" + // Match the official rs-launch:// beta link. HTTPS changes the resource URL parameters, + // causing resource downloads to use TLS on a beta host whose certificate does not cover it. + public const val BETA_RS3_JAV_CONFIG_URL: String = + "http://world204.runescape.com/jav_config_beta.ws?binaryType=2" + public const val BETA_VULKAN_RS3_JAV_CONFIG_URL: String = + "http://world204.runescape.com/jav_config_beta.ws?binaryType=10" + @OptIn(ExperimentalStdlibApi::class) public fun download( type: NativeClientType, @@ -127,7 +134,7 @@ public data object JagexNativeClientDownloader { ?: error("RS3 jav_config has no download_crc_0") // Both distributions advertise rs2client.exe; keep them isolated on disk. - val suffix = if (binaryType == 10) "-vulkan" else "" + val suffix = rs3CacheSuffix(upstreamJavConfigUrl) val clientPath = CLIENTS_DIRECTORY.resolve("rs2client$suffix.exe") val cacheCrcFile = CLIENTS_DIRECTORY.resolve("rs3-win$suffix-cached-crc.txt") @@ -189,7 +196,10 @@ public data object JagexNativeClientDownloader { internal fun rs3BinaryType(javConfigUrl: String): Int { val values = - URI(javConfigUrl).query.orEmpty().split('&') + URI(javConfigUrl) + .query + .orEmpty() + .split('&') .filter { it.substringBefore('=') == "binaryType" } .map { it.substringAfter('=', "").toIntOrNull() } val binaryType = values.singleOrNull() @@ -199,6 +209,11 @@ public data object JagexNativeClientDownloader { return binaryType } + internal fun rs3CacheSuffix(javConfigUrl: String): String { + val beta = URI(javConfigUrl).path.endsWith("/jav_config_beta.ws") + return (if (beta) "-beta" else "") + (if (rs3BinaryType(javConfigUrl) == 10) "-vulkan" else "") + } + private fun buildRepositoryInfo(systemShortName: String): Repository { return Repository( "osrs-$systemShortName", diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/plugin/DecoderLoader.kt b/proxy/src/main/kotlin/net/rsprox/proxy/plugin/DecoderLoader.kt index 7e211382..09541458 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/plugin/DecoderLoader.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/plugin/DecoderLoader.kt @@ -73,12 +73,12 @@ import net.rsprox.protocol.v239.GameClientProtProviderV239 import net.rsprox.protocol.v239.GameServerProtProviderV239 import net.rsprox.protocol.v239.ServerPacketDecoderServiceV239 import net.rsprox.protocol.v240.ClientPacketDecoderServiceV240 -import net.rsprox.protocol.v241.ClientPacketDecoderServiceV241 import net.rsprox.protocol.v240.GameClientProtProviderV240 -import net.rsprox.protocol.v241.GameClientProtProviderV241 import net.rsprox.protocol.v240.GameServerProtProviderV240 -import net.rsprox.protocol.v241.GameServerProtProviderV241 import net.rsprox.protocol.v240.ServerPacketDecoderServiceV240 +import net.rsprox.protocol.v241.ClientPacketDecoderServiceV241 +import net.rsprox.protocol.v241.GameClientProtProviderV241 +import net.rsprox.protocol.v241.GameServerProtProviderV241 import net.rsprox.protocol.v241.ServerPacketDecoderServiceV241 import net.rsprox.proxy.huffman.HuffmanProvider import net.rsprox.transcriber.legacy.LegacyClientProt diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3BetaClientBuild.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3BetaClientBuild.kt new file mode 100644 index 00000000..d1f85264 --- /dev/null +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3BetaClientBuild.kt @@ -0,0 +1,44 @@ +package net.rsprox.proxy.rs3 + +import java.nio.file.Files +import java.nio.file.Path +import java.security.MessageDigest + +/** A beta flag alone does not identify a packet obfuscation. */ +internal object Rs3BetaClientBuild { + // Note(revision): Add a build only after verifying its packet tables, payloads and patch sites. + private val windowsOpenGl950Beta1 = + setOf( + "e2f471f0dfca8f584f7edd4ea0321bbedb40c95331791312e19c19aa1fb8054f", + "15e711390ed2ec98efa8d203ede71c58a62e52b0a842f2feef09257ca9828163", + ) + private val windowsVulkan950Beta1 = + setOf("81c68f8f1659958916a4661569b7d30a9c7dcbbc39d509fad801a69ffae1c7db") + + fun verify( + path: Path, + binaryType: Int, + ): Rs3ProtocolRevision { + val supportedBuilds = + when (binaryType) { + 2 -> windowsOpenGl950Beta1 + 10 -> windowsVulkan950Beta1 + else -> error("Unsupported RuneScape 3 beta binary type: $binaryType") + } + val digest = MessageDigest.getInstance("SHA-256") + Files.newInputStream(path).use { input -> + val bytes = ByteArray(64 * 1024) + while (true) { + val count = input.read(bytes) + if (count == -1) break + digest.update(bytes, 0, count) + } + } + val hash = digest.digest().joinToString("") { "%02x".format(it.toInt() and 255) } + require(hash in supportedBuilds) { + "Unverified RuneScape 3 beta build (SHA-256 $hash). " + + "Its protocol must be checked before capture; no client was launched." + } + return Rs3ProtocolRevision(Rs3ProtocolRevision.BETA_950_1) + } +} diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3DecoderLoader.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3DecoderLoader.kt index 63971515..e44a5cb8 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3DecoderLoader.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3DecoderLoader.kt @@ -6,9 +6,15 @@ import net.rsprox.protocol.rs3v950.ClientPacketDecoderServiceRs3V950 import net.rsprox.protocol.rs3v950.GameClientProtProviderRs3V950 import net.rsprox.protocol.rs3v950.GameServerProtProviderRs3V950 import net.rsprox.protocol.rs3v950.ServerPacketDecoderServiceRs3V950 +import net.rsprox.protocol.rs3v950beta.ClientPacketDecoderServiceRs3V950Beta +import net.rsprox.protocol.rs3v950beta.GameClientProtProviderRs3V950Beta +import net.rsprox.protocol.rs3v950beta.GameServerProtProviderRs3V950Beta +import net.rsprox.protocol.rs3v950beta.ServerPacketDecoderServiceRs3V950Beta import net.rsprox.proxy.rs3.protocol.Rs3ProtDecoder import net.rsprox.protocol.rs3v950.game.incoming.decoder.prot.GameClientProt as GameClientProt950 import net.rsprox.protocol.rs3v950.game.outgoing.decoder.prot.GameServerProt as GameServerProt950 +import net.rsprox.protocol.rs3v950beta.game.incoming.decoder.prot.GameClientProt as GameClientProt950Beta +import net.rsprox.protocol.rs3v950beta.game.outgoing.decoder.prot.GameServerProt as GameServerProt950Beta public object Rs3DecoderLoader { public fun load( @@ -17,7 +23,7 @@ public object Rs3DecoderLoader { serverCipher: () -> StreamCipher? = { null }, ): Rs3RevisionDecoder { return when (revision) { - 950 -> + Rs3ProtocolRevision.LIVE_950 -> Rs3RevisionDecoder( revision = 950, clientPacketDecoder = ClientPacketDecoderServiceRs3V950(huffmanCodec), @@ -33,7 +39,23 @@ public object Rs3DecoderLoader { it.opcode to Rs3ProtDecoder.ProtEntry(it.size, it.name) }, ) - else -> error("Unsupported RS3 revision: $revision") + Rs3ProtocolRevision.BETA_950_1 -> + Rs3RevisionDecoder( + revision = revision, + clientPacketDecoder = ClientPacketDecoderServiceRs3V950Beta(huffmanCodec), + serverPacketDecoder = ServerPacketDecoderServiceRs3V950Beta(huffmanCodec, serverCipher), + gameClientProtProvider = GameClientProtProviderRs3V950Beta, + gameServerProtProvider = GameServerProtProviderRs3V950Beta, + clientProtTable = + GameClientProt950Beta.entries.associate { + it.opcode to Rs3ProtDecoder.ProtEntry(it.size, it.name) + }, + serverProtTable = + GameServerProt950Beta.entries.filter { it != GameServerProt950Beta.RECONNECT }.associate { + it.opcode to Rs3ProtDecoder.ProtEntry(it.size, it.name) + }, + ) + else -> error("Unsupported RS3 protocol revision key: $revision") } } } diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3LaunchProgress.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3LaunchProgress.kt index 520d9b89..5de0e4df 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3LaunchProgress.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3LaunchProgress.kt @@ -44,7 +44,7 @@ internal class Rs3LaunchTracker( private fun logDuration() { val name = stage ?: return val elapsed = (System.nanoTime() - started) / 1_000_000 - logger.info { "RS3 launch $launchId: $name finished after ${elapsed} ms" } + logger.info { "RS3 launch $launchId: $name finished after $elapsed ms" } } private companion object { diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3ProtocolRevision.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3ProtocolRevision.kt new file mode 100644 index 00000000..5deb0863 --- /dev/null +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/Rs3ProtocolRevision.kt @@ -0,0 +1,41 @@ +package net.rsprox.proxy.rs3 + +/** + * RSProx's decoder/recording key. The upper half identifies an obfuscation variant; + * it is not Jagex's build subrevision and must not be sent to login or JS5. + */ +@JvmInline +public value class Rs3ProtocolRevision( + public val value: Int, +) { + init { + require(value != -1 && value and 0xffff != 0) { "Invalid RS3 protocol revision key: $value" } + } + + public val wireRevision: Int + get() = value and 0xffff + + public val obfuscationVersion: Int + get() = value ushr 16 + + public fun display(subRevision: Int): String { + val base = "$wireRevision.$subRevision" + return if (obfuscationVersion == 0) base else "$base (beta $obfuscationVersion)" + } + + public companion object { + public const val LIVE_950: Int = 950 + public const val BETA_950_1: Int = 950 or (1 shl 16) + + public fun of( + wireRevision: Int, + obfuscationVersion: Int = 0, + ): Rs3ProtocolRevision { + require(wireRevision in 1..0xffff) { "RS3 wire revision exceeds 16 bits: $wireRevision" } + require(obfuscationVersion in 0..0xffff) { + "RS3 obfuscation version exceeds 16 bits: $obfuscationVersion" + } + return Rs3ProtocolRevision(wireRevision or (obfuscationVersion shl 16)) + } + } +} diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/binary/Rs3BinaryTranscriber.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/binary/Rs3BinaryTranscriber.kt index c153053e..5476e4bb 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/binary/Rs3BinaryTranscriber.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/binary/Rs3BinaryTranscriber.kt @@ -18,6 +18,7 @@ import net.rsprox.proxy.binary.BinaryStream import net.rsprox.proxy.cli.TranscribeCommand import net.rsprox.proxy.huffman.HuffmanProvider import net.rsprox.proxy.rs3.Rs3DecoderLoader +import net.rsprox.proxy.rs3.Rs3ProtocolRevision import net.rsprox.proxy.rs3.gameval.Rs3GamevalLookup import net.rsprox.proxy.util.TranscribeCallback import net.rsprox.shared.StreamDirection @@ -47,15 +48,18 @@ internal object Rs3BinaryTranscriber { ) { callback?.indeterminate("Resolving recorded RS3 cache definitions (local cache / OpenRS2)...") val header = binary.header - val definitions = Rs3LiveCacheResolver.loadRecordedPacketDefinitions(header.revision, header.js5MasterIndex) + val protocolRevision = Rs3ProtocolRevision(header.revision) + // Reject unknown obfuscations before cache/network work; never fall back to live 950. + HuffmanProvider.load() + // ISAAC-dependent payload bytes were already normalized when the recording was written. + val decoder = Rs3DecoderLoader.load(header.revision, HuffmanProvider.get()) { NopStreamCipher } + val definitions = + Rs3LiveCacheResolver.loadRecordedPacketDefinitions(protocolRevision.wireRevision, header.js5MasterIndex) val clientScripts = RSProxArchiveClientScriptIndex - .forRuneScape(header.revision, header.js5MasterIndex) + .forRuneScape(protocolRevision.wireRevision, header.js5MasterIndex) .also { it.preload() } if (callback?.isCancelled() == true) return - HuffmanProvider.load() - // ISAAC-dependent payload bytes were already normalized when the recording was written. - val decoder = Rs3DecoderLoader.load(header.revision, HuffmanProvider.get()) { NopStreamCipher } val textPath = binaryPath.resolveSibling(binaryPath.nameWithoutExtension + ".txt") val oldTime = if (Files.exists(textPath)) { @@ -70,7 +74,7 @@ internal object Rs3BinaryTranscriber { writer.appendLine("------------------") writer.appendLine("Header information") writer.appendLine("game: RuneScape 3") - writer.appendLine("version: ${header.revision}.${header.subRevision}") + writer.appendLine("version: ${protocolRevision.display(header.subRevision)}") writer.appendLine("world: ${header.worldId}, host: ${header.worldHost}") writer.appendLine("local player index: ${header.localPlayerIndex}") writer.appendLine("-------------------") diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/config/Rs3JavConfig.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/config/Rs3JavConfig.kt index 0eecce96..d75f04ec 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/config/Rs3JavConfig.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/config/Rs3JavConfig.kt @@ -33,6 +33,16 @@ public value class Rs3JavConfig( ?.substring(prefix.length) } + public fun getCacheVariantSuffix(): String { + val values = text.lineSequence().filter { it.startsWith("cache_variant_suffix=") }.toList() + require(values.size <= 1) { "Duplicate RS3 cache variant suffix" } + val suffix = values.singleOrNull()?.substringAfter('=') ?: "" + require(suffix.isEmpty() || suffix.matches(Regex("[A-Za-z0-9_-]{1,32}"))) { + "Invalid RS3 cache variant suffix" + } + return suffix + } + public fun getDownloadCrc(id: Int): Long? { val prefix = "download_crc_$id=" return text diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/launcher/Rs3LauncherSlot.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/launcher/Rs3LauncherSlot.kt index 8489d48d..b547f501 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/launcher/Rs3LauncherSlot.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/launcher/Rs3LauncherSlot.kt @@ -14,10 +14,11 @@ internal class Rs3LauncherSlot private constructor( val directory: Path, private val channel: FileChannel, private val lock: FileLock, + private val cacheVariantSuffix: String, ) : AutoCloseable { private val closed = AtomicBoolean() val name: String get() = directory.fileName.toString() - val client: Path get() = directory.resolve("rs2client.exe") + val client: Path get() = directory.resolve(cacheVariantSuffix).resolve("rs2client.exe") val launcher: Path get() = directory.resolve("RuneScape-rsprox.exe") override fun close() { @@ -33,7 +34,9 @@ internal class Rs3LauncherSlot private constructor( fun acquire( configuration: Path, cacheRoot: Path, + cacheVariantSuffix: String = "", ): Rs3LauncherSlot { + require(cacheVariantSuffix.isEmpty() || cacheVariantSuffix.matches(Regex("[A-Za-z0-9_-]{1,32}"))) val owner = configuration.toAbsolutePath().normalize().toString() val namespace = Rs3LauncherDistribution.sha256(owner.toByteArray()).take(5) Files.createDirectories(cacheRoot) @@ -50,7 +53,7 @@ internal class Rs3LauncherSlot private constructor( null } if (lock != null) { - val lease = Rs3LauncherSlot(directory, channel, lock) + val lease = Rs3LauncherSlot(directory, channel, lock, cacheVariantSuffix) try { val ownerFile = directory.resolve("rsprox-owner.txt") if (Files.exists(ownerFile)) { @@ -66,6 +69,7 @@ internal class Rs3LauncherSlot private constructor( Files.writeString(ownerFile, owner) } val userRoot = configuration.resolve("slots/$slot/user").toAbsolutePath() + Files.createDirectories(lease.client.parent) Files.createDirectories(userRoot) val preferences = directory.resolve("preferences.cfg") if (!Files.exists(preferences)) { diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/launcher/Rs3OfficialLauncher.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/launcher/Rs3OfficialLauncher.kt index c4e1c13b..3c55775d 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/launcher/Rs3OfficialLauncher.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/launcher/Rs3OfficialLauncher.kt @@ -129,7 +129,7 @@ internal class Rs3OfficialLauncher private constructor( ): Rs3OfficialLauncher { val source = Rs3LauncherDistribution.load(directory, onProgress) val cacheRoot = Path.of(Shell32Util.getFolderPath(ShlObj.CSIDL_COMMON_APPDATA), "Jagex") - val slot = Rs3LauncherSlot.acquire(directory, cacheRoot) + val slot = Rs3LauncherSlot.acquire(directory, cacheRoot, javConfig.getCacheVariantSuffix()) var server: Rs3LauncherConfigServer? = null try { onProgress(Rs3LaunchProgress("Preparing RuneScape launcher")) diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/privacy/Rs3LivePacketDecoder.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/privacy/Rs3LivePacketDecoder.kt index c3c03d39..84cb097a 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/privacy/Rs3LivePacketDecoder.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/privacy/Rs3LivePacketDecoder.kt @@ -26,14 +26,14 @@ internal class Rs3LivePacketDecoder( val safePayload = try { // Note(revision): Add the new revision's verified privacy policy here; otherwise GUI payloads bypass it. - if (decoder.revision == 950) { + if (sanitizer.revision == decoder.revision) { val normalized = payload.copyOf() if (server) { sanitizer.normalizeServerPayload(name, normalized) { checkNotNull(serverCipher()) } } sanitizer.sanitize(server, name, normalized) ?: return null } else { - payload + error("No privacy policy for RS3 protocol revision key") } } catch (_: Exception) { // Never retain original bytes or a nested exception from failed sanitization. diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/privacy/Rs3PacketSanitizer.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/privacy/Rs3PacketSanitizer.kt index 8cc340b8..d876439a 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/privacy/Rs3PacketSanitizer.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/privacy/Rs3PacketSanitizer.kt @@ -4,12 +4,21 @@ import io.netty.buffer.Unpooled import net.rsprot.buffer.extensions.toJagByteBuf import net.rsprot.compression.HuffmanCodec import net.rsprot.crypto.cipher.StreamCipher +import net.rsprox.proxy.rs3.Rs3ProtocolRevision import java.util.zip.CRC32 /** Revision-950 privacy policy for recording and GUI copies, after payload ISAAC normalization. */ internal class Rs3PacketSanitizer( private val huffman: HuffmanCodec, + val revision: Int = Rs3ProtocolRevision.LIVE_950, ) { + private val beta = + when (revision) { + Rs3ProtocolRevision.LIVE_950 -> false + Rs3ProtocolRevision.BETA_950_1 -> true + else -> error("No RS3 privacy policy for protocol revision key: $revision") + } + /** Mutates an observation-owned copy only; consumes the original payload's cipher draws. */ fun normalizeServerPayload( name: String, @@ -36,6 +45,8 @@ internal class Rs3PacketSanitizer( payload: ByteArray, ): ByteArray? { if (!server && name in OMITTED_CLIENT_PACKETS) return null + // Beta's name check is also encrypted with the account-flow keys, not a cleartext name. + if (!server && beta && name == "CREATE_CHECK_NAME") return null if (name !in (if (server) SERVER_PACKETS else CLIENT_PACKETS)) return payload // Never mutate transport buffers, live-decoder inputs, or the caller's original packet. @@ -129,8 +140,8 @@ internal class Rs3PacketSanitizer( input.string(mask = true) } "IGNORE_SETNOTES" -> { - input.string(mask = true) - input.string() + input.string(mask = !beta) + input.string(mask = beta) } } } @@ -154,10 +165,12 @@ internal class Rs3PacketSanitizer( val combinedId = if (name == "RESUME_PAUSEBUTTON") { require(payload.size == 6) - input.g4().also { input.g2Alt2() } + val combinedId = input.g4() + if (beta) input.g2Alt1() else input.g2Alt2() + combinedId } else { require(payload.size == 9) - input.g3() // Object id. + if (beta) input.g3Alt1() else input.g3() // Object id. input.g4Alt3().also { input.g2() } // Component id and slot. } // Digits are encoded by component identity. Cover every component/op, including diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/relay/Rs3ConnectionRecording.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/relay/Rs3ConnectionRecording.kt index bf318996..860480ee 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/relay/Rs3ConnectionRecording.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/relay/Rs3ConnectionRecording.kt @@ -2,6 +2,7 @@ package net.rsprox.proxy.rs3.relay import net.rsprot.compression.HuffmanCodec import net.rsprot.crypto.cipher.StreamCipherPair +import net.rsprox.proxy.rs3.Rs3ProtocolRevision import net.rsprox.proxy.rs3.binary.Rs3BinaryRecorder import net.rsprox.proxy.rs3.login.Rs3LoginSuccessFramer import net.rsprox.proxy.rs3.login.Rs3WorldLoginResponseFramer @@ -17,7 +18,7 @@ internal class Rs3ConnectionRecording( private val clients: Map, huffman: HuffmanCodec, ) { - private val sanitizer = Rs3PacketSanitizer(huffman) + private val sanitizer = Rs3PacketSanitizer(huffman, revision) private var ciphers: StreamCipherPair? = null private var serverStream: Rs3PacketStream? = null private var clientStream: Rs3PacketStream? = null @@ -32,7 +33,7 @@ internal class Rs3ConnectionRecording( minor: Int, ) = safely { // Note(revision): Verify/update Rs3PacketSanitizer and the live GUI policy before enabling another revision. - require(major == revision && major == 950) { "Unsupported RS3 recording revision" } + require(major == Rs3ProtocolRevision(revision).wireRevision) { "Unsupported RS3 recording revision" } require(servers.keys.none { it in 0xFC..0xFF }) { "Recording opcode collision" } this.minor = minor serverStream?.close() diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/relay/Rs3RelayServer.kt b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/relay/Rs3RelayServer.kt index f83f9c3a..f8d8043e 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/rs3/relay/Rs3RelayServer.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/rs3/relay/Rs3RelayServer.kt @@ -35,6 +35,7 @@ import net.rsprox.proxy.filters.DefaultPropertyFilterSetStore import net.rsprox.proxy.filters.UnmodifiablePropertyFilterSet import net.rsprox.proxy.huffman.HuffmanProvider import net.rsprox.proxy.rs3.Rs3DecoderLoader +import net.rsprox.proxy.rs3.Rs3ProtocolRevision import net.rsprox.proxy.rs3.Rs3SessionMonitor import net.rsprox.proxy.rs3.binary.Rs3BinaryRecorder import net.rsprox.proxy.rs3.gameval.Rs3GamevalLookup @@ -113,6 +114,12 @@ public class Rs3RelayServer( private val realServerPublicKey: RSAKeyParameters = RSAKeyParameters(false, BigInteger(realServerModulusHex, 16), Rsa.PUBLIC_EXPONENT) + init { + require(revision == Rs3ProtocolRevision.LIVE_950 || revision == Rs3ProtocolRevision.BETA_950_1) { + "Unsupported RS3 relay protocol revision key: $revision" + } + } + private val bossGroup = NioEventLoopGroup(1) // All sockets for one launched client share mutable protocol state across reconnects. @@ -308,10 +315,10 @@ public class Rs3RelayServer( val rs3Decoder = Rs3DecoderLoader.load(revision, huffman) { - if (revision == 950) NopStreamCipher else cipherHolder.pair?.decodeCipher + NopStreamCipher } val liveDecoder = - Rs3LivePacketDecoder(rs3Decoder, Rs3PacketSanitizer(huffman)) { cipherHolder.pair?.decodeCipher } + Rs3LivePacketDecoder(rs3Decoder, Rs3PacketSanitizer(huffman, revision)) { cipherHolder.pair?.decodeCipher } val initialRecording = Rs3ConnectionRecording( recordings, @@ -410,7 +417,6 @@ public class Rs3RelayServer( val transportAcknowledgement = if (mapped && isWorldConnection) Rs3WorldContinueAckSkipper() else null val transportDecoder = if (mapped) { - check(revision == 950) { "Mapped routing is currently verified only for revision 950" } Rs3DecoderLoader.load(revision, huffman) { transportCiphers?.decodeCipher } } else { null @@ -579,7 +585,7 @@ public class Rs3RelayServer( { resuming -> reconnect = resuming if (resuming) { - check(isWorldConnection && revision == 950) { "Unsupported reconnect target" } + check(isWorldConnection) { "Unsupported reconnect target" } val previous = checkNotNull(gameSession) { "Reconnect has no previous game session" } check( !previous.ended && diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/transcriber/LiveTranscriberSession.kt b/proxy/src/main/kotlin/net/rsprox/proxy/transcriber/LiveTranscriberSession.kt index a24f1c98..b266736a 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/transcriber/LiveTranscriberSession.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/transcriber/LiveTranscriberSession.kt @@ -185,7 +185,9 @@ public class LiveTranscriberSession( private sealed interface PendingEvent - private class Flush(val afterFlush: () -> Unit) : PendingEvent + private class Flush( + val afterFlush: () -> Unit, + ) : PendingEvent private class UnidentifiedPacket( val direction: StreamDirection, diff --git a/shared/src/main/kotlin/net/rsprox/shared/filters/PropertyFilter.kt b/shared/src/main/kotlin/net/rsprox/shared/filters/PropertyFilter.kt index 6ef574d0..8efd6525 100644 --- a/shared/src/main/kotlin/net/rsprox/shared/filters/PropertyFilter.kt +++ b/shared/src/main/kotlin/net/rsprox/shared/filters/PropertyFilter.kt @@ -1740,6 +1740,13 @@ public enum class PropertyFilter( true, searchTerms = "rs3,npc,unknown,opaque,extended,info", ), + PLAYER_UNUSED_FIELDS( + SERVER_TO_CLIENT, + PLAYER_EXTENDED_INFO, + "Unused Fields", + false, + searchTerms = "rs3,player,unused,beta,mask", + ), PLAYER_UNUSED_MASK_2( SERVER_TO_CLIENT, PLAYER_EXTENDED_INFO, @@ -1789,6 +1796,13 @@ public enum class PropertyFilter( true, searchTerms = "rs3,player,unused,mask,24", ), + NPC_UNUSED_FIELDS( + SERVER_TO_CLIENT, + NPC_EXTENDED_INFO, + "Unused Fields", + false, + searchTerms = "rs3,npc,unused,beta,mask", + ), NPC_UNUSED_MASK_0( SERVER_TO_CLIENT, NPC_EXTENDED_INFO, @@ -2155,6 +2169,20 @@ public enum class PropertyFilter( false, searchTerms = "rs3,transmitvar_verifyid", ), + GAMELOGEVENT( + CLIENT_TO_SERVER, + OTHER, + "Game Log Event", + false, + searchTerms = "rs3,gamelogevent", + ), + PLUGIN_REPORTS( + CLIENT_TO_SERVER, + OTHER, + "Plugin Reports", + false, + searchTerms = "rs3,plugin,unnamed_batch_80,unnamed_event_92", + ), PING_STATISTICS( CLIENT_TO_SERVER, OTHER, diff --git a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/Rs3TranscriberPlugin.kt b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/Rs3TranscriberPlugin.kt index 022312ec..3a143281 100644 --- a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/Rs3TranscriberPlugin.kt +++ b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/Rs3TranscriberPlugin.kt @@ -163,6 +163,12 @@ public class Rs3TranscriberPlugin( pass(message, Rs3Transcriber::transmitVarVerifyId) name == "PING_STATISTICS" -> pass(message, Rs3Transcriber::pingStatistics) + name == "GAMELOGEVENT" -> + pass(message, Rs3Transcriber::gameLogEvent) + name == "UNNAMED_BATCH_80" -> + pass(message, Rs3Transcriber::unnamedBatch80) + name == "UNNAMED_EVENT_92" -> + pass(message, Rs3Transcriber::unnamedEvent92) name == "SEND_EMAIL_VALIDATION_CODE" -> pass(message, Rs3Transcriber::sendEmailValidationCode) name == "FRIENDLIST_DEL" -> @@ -466,10 +472,10 @@ public class Rs3TranscriberPlugin( "LOC_ANIM" -> pass(message, Rs3Transcriber::locAnim) "LOC_ADD_CHANGE" -> pass(message, Rs3Transcriber::locAddChange) "LOC_DEL" -> pass(message, Rs3Transcriber::locDel) - "OBJ_ADD", "OBJ_ADD_V2" -> pass(message, Rs3Transcriber::objAdd) + "OBJ_ADD", "OBJ_ADD_V2", "OBJ_ADD_V3" -> pass(message, Rs3Transcriber::objAdd) "OBJ_DEL", "OBJ_DEL_V2" -> pass(message, Rs3Transcriber::objDel) - "OBJ_COUNT", "OBJ_COUNT_V2" -> pass(message, Rs3Transcriber::objCount) - "OBJ_REVEAL", "OBJ_REVEAL_V2" -> pass(message, Rs3Transcriber::objReveal) + "OBJ_COUNT", "OBJ_COUNT_V2", "OBJ_COUNT_V3" -> pass(message, Rs3Transcriber::objCount) + "OBJ_REVEAL", "OBJ_REVEAL_V2", "OBJ_REVEAL_V3" -> pass(message, Rs3Transcriber::objReveal) "MAP_ANIM" -> pass(message, Rs3Transcriber::mapAnim) "MAP_ANIM_V1" -> pass(message, Rs3Transcriber::mapAnimV1) "MAP_ANIM_V2" -> pass(message, Rs3Transcriber::mapAnimV2) diff --git a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/interfaces/Rs3ClientPacketTranscriber.kt b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/interfaces/Rs3ClientPacketTranscriber.kt index bb58a2c5..6ad90598 100644 --- a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/interfaces/Rs3ClientPacketTranscriber.kt +++ b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/interfaces/Rs3ClientPacketTranscriber.kt @@ -37,10 +37,13 @@ import net.rsprox.protocol.rs3.game.incoming.model.events.EventMouseClick import net.rsprox.protocol.rs3.game.incoming.model.events.EventMouseMove import net.rsprox.protocol.rs3.game.incoming.model.events.EventNativeMouseClick import net.rsprox.protocol.rs3.game.incoming.model.events.EventNativeMouseMove +import net.rsprox.protocol.rs3.game.incoming.model.events.GameLogEvent import net.rsprox.protocol.rs3.game.incoming.model.events.MidiSongStop import net.rsprox.protocol.rs3.game.incoming.model.events.PingStatistics import net.rsprox.protocol.rs3.game.incoming.model.events.SendPingReply import net.rsprox.protocol.rs3.game.incoming.model.events.TransmitVarVerifyId +import net.rsprox.protocol.rs3.game.incoming.model.events.UnnamedBatch80 +import net.rsprox.protocol.rs3.game.incoming.model.events.UnnamedEvent92 import net.rsprox.protocol.rs3.game.incoming.model.events.WindowStatus import net.rsprox.protocol.rs3.game.incoming.model.locs.OpLoc import net.rsprox.protocol.rs3.game.incoming.model.locs.OpLocT @@ -175,6 +178,12 @@ public interface Rs3ClientPacketTranscriber { public fun pingStatistics(message: PingStatistics) + public fun gameLogEvent(message: GameLogEvent) + + public fun unnamedBatch80(message: UnnamedBatch80) + + public fun unnamedEvent92(message: UnnamedEvent92) + public fun sendEmailValidationCode(message: SendEmailValidationCode) public fun friendListDel(message: FriendListDel) diff --git a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3ClientPacketTranscriber.kt b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3ClientPacketTranscriber.kt index d59c08fd..13c26723 100644 --- a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3ClientPacketTranscriber.kt +++ b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3ClientPacketTranscriber.kt @@ -39,11 +39,14 @@ import net.rsprox.protocol.rs3.game.incoming.model.events.EventMouseClick import net.rsprox.protocol.rs3.game.incoming.model.events.EventMouseMove import net.rsprox.protocol.rs3.game.incoming.model.events.EventNativeMouseClick import net.rsprox.protocol.rs3.game.incoming.model.events.EventNativeMouseMove +import net.rsprox.protocol.rs3.game.incoming.model.events.GameLogEvent import net.rsprox.protocol.rs3.game.incoming.model.events.MidiSongStop import net.rsprox.protocol.rs3.game.incoming.model.events.MouseMovement import net.rsprox.protocol.rs3.game.incoming.model.events.PingStatistics import net.rsprox.protocol.rs3.game.incoming.model.events.SendPingReply import net.rsprox.protocol.rs3.game.incoming.model.events.TransmitVarVerifyId +import net.rsprox.protocol.rs3.game.incoming.model.events.UnnamedBatch80 +import net.rsprox.protocol.rs3.game.incoming.model.events.UnnamedEvent92 import net.rsprox.protocol.rs3.game.incoming.model.events.WindowStatus import net.rsprox.protocol.rs3.game.incoming.model.locs.OpLoc import net.rsprox.protocol.rs3.game.incoming.model.locs.OpLocT @@ -101,6 +104,7 @@ import net.rsprox.shared.property.int import net.rsprox.shared.property.long import net.rsprox.shared.property.regular.AnyProperty import net.rsprox.shared.property.regular.ScriptVarTypeProperty +import net.rsprox.shared.property.script import net.rsprox.shared.property.scriptVarType import net.rsprox.shared.property.shortNpc import net.rsprox.shared.property.shortPlayer @@ -487,6 +491,45 @@ public class TextRs3ClientPacketTranscriber( root.int("fps", message.fps) } + override fun gameLogEvent(message: GameLogEvent) { + if (!filters[PropertyFilter.GAMELOGEVENT]) return omit() + root.int("id", message.id) + root.script("script", message.script) + root.int("value16", message.value16) + root.group("arguments") { + for (argument in message.arguments) { + group { + int("scripttype", argument.scriptType) + appendVariableValue(argument.value) + } + } + } + } + + override fun unnamedBatch80(message: UnnamedBatch80) { + if (!filters[PropertyFilter.PLUGIN_REPORTS]) return omit() + root.boolean("complete", message.complete) + root.group("entries") { + for (entry in message.entries) { + group { + int("field0", entry.field0) + int("field1", entry.field1) + int("field2", entry.field2) + int("field3", entry.field3) + } + } + } + } + + override fun unnamedEvent92(message: UnnamedEvent92) { + if (!filters[PropertyFilter.PLUGIN_REPORTS]) return omit() + root.int("field0", message.field0) + root.int("field1", message.field1) + root.int("field2", message.field2) + root.int("field3", message.field3) + root.int("field4", message.field4) + } + override fun sendEmailValidationCode(message: SendEmailValidationCode) { if (!filters[PropertyFilter.SEND_EMAIL_VALIDATION_CODE]) return omit() root.string("code", message.code) diff --git a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3NpcInfoTranscriber.kt b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3NpcInfoTranscriber.kt index ca4787d6..a9bb58b4 100644 --- a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3NpcInfoTranscriber.kt +++ b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3NpcInfoTranscriber.kt @@ -7,6 +7,7 @@ import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.extendedinfo.Ani import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.extendedinfo.NpcExtendedInfo import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.extendedinfo.NpcMask import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.extendedinfo.OpaqueExtendedInfo +import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.extendedinfo.UnusedExtendedInfo import net.rsprox.protocol.rs3.game.outgoing.model.info.npcinfo.util.Rs3NpcUpdateMaskKey import net.rsprox.shared.ScriptVarType import net.rsprox.shared.filters.PropertyFilter @@ -18,6 +19,7 @@ import net.rsprox.shared.property.RootProperty import net.rsprox.shared.property.any import net.rsprox.shared.property.filteredBoolean import net.rsprox.shared.property.group +import net.rsprox.shared.property.int import net.rsprox.shared.property.namedEnum import net.rsprox.shared.property.regular.AnyProperty import net.rsprox.shared.property.regular.ScriptVarTypeProperty @@ -66,6 +68,7 @@ public class TextRs3NpcInfoTranscriber( when (info) { is AnimationExtendedInfo -> PropertyFilter.NPC_SEQUENCE is OpaqueExtendedInfo -> PropertyFilter.NPC_UNKNOWN_EXT_INFO + is UnusedExtendedInfo -> PropertyFilter.NPC_UNUSED_FIELDS is NpcMask -> when (info.key) { Rs3NpcUpdateMaskKey.SAY -> PropertyFilter.NPC_SAY @@ -109,6 +112,10 @@ public class TextRs3NpcInfoTranscriber( baseCoord: CoordGrid, ) { when (info) { + is UnusedExtendedInfo -> + group("UNUSED_MASK_${info.bit}") { + for ((index, value) in info.fields.withIndex()) int("field$index", value) + } is NpcMask -> appendNpcMask( info, diff --git a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3PlayerInfoTranscriber.kt b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3PlayerInfoTranscriber.kt index 76ec866f..cd05d1be 100644 --- a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3PlayerInfoTranscriber.kt +++ b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3PlayerInfoTranscriber.kt @@ -82,6 +82,7 @@ public class TextRs3PlayerInfoTranscriber( is PlayerExtendedInfo.PlayerStatus -> filters[PropertyFilter.PLAYER_STATUS] is PlayerExtendedInfo.HeadIcons -> filters[PropertyFilter.PLAYER_HEAD_ICONS] is PlayerExtendedInfo.UnusedMask16 -> filters[PropertyFilter.PLAYER_UNUSED_MASK_16] + is PlayerExtendedInfo.UnusedFields -> filters[PropertyFilter.PLAYER_UNUSED_FIELDS] is PlayerExtendedInfo.Unused -> filters[ when (it.kind) { @@ -265,6 +266,10 @@ public class TextRs3PlayerInfoTranscriber( boolean("enabled", info.enabled) } is PlayerExtendedInfo.FaceEntity -> group("FACE_ENTITY") { entities.entity(this, info.target) } + is PlayerExtendedInfo.UnusedFields -> + group("UNUSED_MASK_${info.bit}") { + for ((index, value) in info.fields.withIndex()) int("field$index", value) + } is PlayerExtendedInfo.Unused -> group(info.kind.name) { int("field0", info.field0) diff --git a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3ServerPacketTranscriber.kt b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3ServerPacketTranscriber.kt index 7b566cbb..91c1989f 100644 --- a/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3ServerPacketTranscriber.kt +++ b/transcriber/src/main/kotlin/net/rsprox/transcriber/rs3/text/TextRs3ServerPacketTranscriber.kt @@ -532,6 +532,9 @@ public class TextRs3ServerPacketTranscriber( root.scriptVarType("id", ScriptVarType.INTERFACE, message.childId) root.ifType(message.layer) root.xteas(message.legacyWord0, message.legacyWord1, message.legacyWord2, message.legacyWord3) + if (message.reserved.isNotEmpty()) { + root.filteredAny("reserved", message.reserved, List(message.reserved.size) { 0 }) + } } override fun ifOpenSubActiveNpc(message: IfOpenSubActiveNpc) { @@ -541,6 +544,9 @@ public class TextRs3ServerPacketTranscriber( root.scriptVarType("id", ScriptVarType.INTERFACE, message.childId) root.ifType(message.layer) root.xteas(message.legacyWord0, message.legacyWord1, message.legacyWord2, message.legacyWord3) + if (message.reserved.isNotEmpty()) { + root.filteredAny("reserved", message.reserved, List(message.reserved.size) { 0 }) + } } override fun ifOpenTop(message: IfOpenTop) { @@ -550,6 +556,9 @@ public class TextRs3ServerPacketTranscriber( root.scriptVarType("id", ScriptVarType.INTERFACE, message.interfaceId) message.unused?.let { root.filteredInt("unused", it, 128) } root.xteas(message.legacyWord0, message.legacyWord1, message.legacyWord2, message.legacyWord3) + if (message.reserved.isNotEmpty()) { + root.filteredAny("reserved", message.reserved, List(message.reserved.size) { 0 }) + } } override fun ifOpenSub(message: IfOpenSub) { @@ -558,6 +567,9 @@ public class TextRs3ServerPacketTranscriber( root.scriptVarType("id", ScriptVarType.INTERFACE, message.childId) root.ifType(message.layer) root.xteas(message.legacyWord0, message.legacyWord1, message.legacyWord2, message.legacyWord3) + if (message.reserved.isNotEmpty()) { + root.filteredAny("reserved", message.reserved, List(message.reserved.size) { 0 }) + } } override fun ifCloseSub(message: IfCloseSub) { @@ -969,6 +981,7 @@ public class TextRs3ServerPacketTranscriber( scriptVarType("id", ScriptVarType.OBJ, event.objId) formattedInt("count", event.count) zoneCoord(event.xInZone, event.zInZone) + event.coordinateFlags?.let { filteredInt("coordflags", it, 0) } } override fun objAdd(message: ObjAdd) { @@ -979,6 +992,7 @@ public class TextRs3ServerPacketTranscriber( private fun Property.buildObjDel(event: ObjDel) { scriptVarType("id", ScriptVarType.OBJ, event.objId) zoneCoord(event.xInZone, event.zInZone) + event.coordinateFlags?.let { filteredInt("coordflags", it, 0) } } override fun objDel(message: ObjDel) { @@ -991,6 +1005,7 @@ public class TextRs3ServerPacketTranscriber( formattedInt("oldcount", event.oldQuantity) formattedInt("newcount", event.newQuantity) zoneCoord(event.xInZone, event.zInZone) + event.coordinateFlags?.let { filteredInt("coordflags", it, 0) } } override fun objCount(message: ObjCount) { @@ -1312,7 +1327,7 @@ public class TextRs3ServerPacketTranscriber( } is ObjAdd -> { if (!filters[PropertyFilter.OBJ_ADD]) continue - root.group(if (event.big) "OBJ_ADD_V2" else "OBJ_ADD") { buildObjAdd(event) } + root.group(if (event.version > 1) "OBJ_ADD_V${event.version}" else "OBJ_ADD") { buildObjAdd(event) } } is ObjDel -> { if (!filters[PropertyFilter.OBJ_DEL]) continue @@ -1320,11 +1335,27 @@ public class TextRs3ServerPacketTranscriber( } is ObjCount -> { if (!filters[PropertyFilter.OBJ_COUNT]) continue - root.group(if (event.big) "OBJ_COUNT_V2" else "OBJ_COUNT") { buildObjCount(event) } + root.group( + if (event.version > + 1 + ) { + "OBJ_COUNT_V${event.version}" + } else { + "OBJ_COUNT" + }, + ) { buildObjCount(event) } } is ObjReveal -> { if (!filters[PropertyFilter.OBJ_ADD]) continue - root.group(if (event.big) "OBJ_REVEAL_V2" else "OBJ_REVEAL") { buildObjReveal(event) } + root.group( + if (event.version > + 1 + ) { + "OBJ_REVEAL_V${event.version}" + } else { + "OBJ_REVEAL" + }, + ) { buildObjReveal(event) } } is MapAnim -> { if (!filters[PropertyFilter.MAP_ANIM]) continue @@ -1396,7 +1427,9 @@ public class TextRs3ServerPacketTranscriber( } is ObjAdd -> { if (!filters[PropertyFilter.OBJ_ADD]) continue - sessionState.createFakeServerRoot(if (event.big) "OBJ_ADD_V2" else "OBJ_ADD").buildObjAdd(event) + sessionState + .createFakeServerRoot(if (event.version > 1) "OBJ_ADD_V${event.version}" else "OBJ_ADD") + .buildObjAdd(event) } is ObjDel -> { if (!filters[PropertyFilter.OBJ_DEL]) continue @@ -1406,13 +1439,13 @@ public class TextRs3ServerPacketTranscriber( if (!filters[PropertyFilter.OBJ_COUNT]) continue sessionState .createFakeServerRoot( - if (event.big) "OBJ_COUNT_V2" else "OBJ_COUNT", + if (event.version > 1) "OBJ_COUNT_V${event.version}" else "OBJ_COUNT", ).buildObjCount(event) } is ObjReveal -> { if (!filters[PropertyFilter.OBJ_ADD]) continue sessionState - .createFakeServerRoot(if (event.big) "OBJ_REVEAL_V2" else "OBJ_REVEAL") + .createFakeServerRoot(if (event.version > 1) "OBJ_REVEAL_V${event.version}" else "OBJ_REVEAL") .buildObjReveal(event) } is MapAnim -> { @@ -1498,6 +1531,9 @@ public class TextRs3ServerPacketTranscriber( root.ifType(message.layer) root.int("coordinate", message.coord) root.xteas(message.extra1, message.extra2, message.extra3, message.extra4) + if (message.reserved.isNotEmpty()) { + root.filteredAny("reserved", message.reserved, List(message.reserved.size) { 0 }) + } } override fun ifOpenSubActiveLoc(message: IfOpenSubActiveLoc) { @@ -1510,6 +1546,9 @@ public class TextRs3ServerPacketTranscriber( root.ifType(message.layer) root.int("coordinate", message.coord) root.xteas(message.extra1, message.extra2, message.extra3, message.extra4) + if (message.reserved.isNotEmpty()) { + root.filteredAny("reserved", message.reserved, List(message.reserved.size) { 0 }) + } } override fun ifSetModel(message: IfSetModel) { @@ -2429,7 +2468,8 @@ public class TextRs3ServerPacketTranscriber( if (!filters[PropertyFilter.UNNAMED_SERVER_RECORDS]) return omit() root.int("count", message.count) root.children += AnyProperty("records", message.records, List::class.java) - root.int("discardedfooter", message.discardedFooter) + message.discardedFooter?.let { root.int("discardedfooter", it) } + if (message.reservedFooter.isNotEmpty()) root.any("reservedfooter", message.reservedFooter) } override fun updateFriendlist(message: UpdateFriendlist) {