From 3a4afd2ba6589676846031a089d56fda6f7a3d0a Mon Sep 17 00:00:00 2001 From: Tomm0017 Date: Tue, 11 Nov 2025 15:19:40 -0500 Subject: [PATCH] Add stateful view support for `ProcessedBinarySession` messages --- .../result/ProcessedBinarySession.kt | 5 + .../processor/state/BinarySessionState.kt | 117 ++++++++++++++++++ .../state/BinarySessionStateIterator.kt | 39 ++++++ 3 files changed, 161 insertions(+) create mode 100644 processor/src/main/kotlin/net/rsprox/processor/state/BinarySessionState.kt create mode 100644 processor/src/main/kotlin/net/rsprox/processor/state/BinarySessionStateIterator.kt diff --git a/processor/src/main/kotlin/net/rsprox/processor/result/ProcessedBinarySession.kt b/processor/src/main/kotlin/net/rsprox/processor/result/ProcessedBinarySession.kt index 14965fce..c6f51dc2 100644 --- a/processor/src/main/kotlin/net/rsprox/processor/result/ProcessedBinarySession.kt +++ b/processor/src/main/kotlin/net/rsprox/processor/result/ProcessedBinarySession.kt @@ -1,6 +1,7 @@ package net.rsprox.processor.result import net.rsprot.protocol.message.IncomingMessage +import net.rsprox.processor.state.BinarySessionStateIterator import net.rsprox.proxy.binary.BinaryHeader import java.nio.file.Path @@ -12,4 +13,8 @@ public class ProcessedBinarySession( public fun toTickTimestamped(): TimestampedBinarySession { return TimestampedBinarySession.from(this) } + + public fun statefulIterator(): BinarySessionStateIterator { + return BinarySessionStateIterator(messages) + } } diff --git a/processor/src/main/kotlin/net/rsprox/processor/state/BinarySessionState.kt b/processor/src/main/kotlin/net/rsprox/processor/state/BinarySessionState.kt new file mode 100644 index 00000000..9ddca951 --- /dev/null +++ b/processor/src/main/kotlin/net/rsprox/processor/state/BinarySessionState.kt @@ -0,0 +1,117 @@ +package net.rsprox.processor.state + +import net.rsprot.protocol.message.IncomingMessage +import net.rsprox.protocol.common.CoordGrid +import net.rsprox.protocol.game.outgoing.model.map.RebuildLogin +import net.rsprox.protocol.game.outgoing.model.map.RebuildNormal +import net.rsprox.protocol.game.outgoing.model.map.RebuildRegion +import net.rsprox.protocol.game.outgoing.model.map.util.BuildArea +import net.rsprox.protocol.game.outgoing.model.misc.client.ServerTickEnd +import net.rsprox.protocol.game.outgoing.model.zone.header.UpdateZoneFullFollows +import net.rsprox.protocol.game.outgoing.model.zone.header.UpdateZonePartialEnclosed +import net.rsprox.protocol.game.outgoing.model.zone.header.UpdateZonePartialFollows + +public data class BinarySessionState( + public val currentTick: Int, + public val localPlayerIndex: Int, + public val buildArea: CoordGrid, + public val updateZone: CoordGrid, + public val regionZones: BuildArea?, +) { + public fun absCoord(xInZone: Int, zInZone: Int): CoordGrid { + val zoneBase = CoordGrid(updateZone.level, buildArea.x + updateZone.x, buildArea.z + updateZone.z) + val coord = CoordGrid(zoneBase.level, zoneBase.x + xInZone, zoneBase.z + zInZone) + return absCoord(buildArea, regionZones, coord) + } + + internal fun nextState(message: IncomingMessage): BinarySessionState { + when (message) { + is ServerTickEnd -> { + return copy(currentTick = currentTick + 1) + } + is RebuildNormal -> { + val buildAreaX = (message.zoneX - 6) shl 3 + val buildAreaZ = (message.zoneZ - 6) shl 3 + val buildArea = CoordGrid(0, buildAreaX, buildAreaZ) + return copy(buildArea = buildArea, regionZones = null) + } + is RebuildRegion -> { + val buildAreaX = (message.zoneX - 6) shl 3 + val buildAreaZ = (message.zoneZ - 6) shl 3 + val buildArea = CoordGrid(0, buildAreaX, buildAreaZ) + return copy(buildArea = buildArea, regionZones = message.buildArea) + } + is RebuildLogin -> { + val localIndex = message.playerInfoInitBlock.localPlayerIndex + val buildAreaX = (message.zoneX - 6) shl 3 + val buildAreaZ = (message.zoneZ - 6) shl 3 + val buildArea = CoordGrid(0, buildAreaX, buildAreaZ) + return copy(localPlayerIndex = localIndex, buildArea = buildArea, regionZones = null) + } + is UpdateZoneFullFollows -> { + val updateZone = CoordGrid(message.level, message.zoneX, message.zoneZ) + return copy(updateZone = updateZone) + } + is UpdateZonePartialEnclosed -> { + val updateZone = CoordGrid(message.level, message.zoneX, message.zoneZ) + return copy(updateZone = updateZone) + } + is UpdateZonePartialFollows -> { + val updateZone = CoordGrid(message.level, message.zoneX, message.zoneZ) + return copy(updateZone = updateZone) + } + } + return this + } + + public companion object { + public val DEFAULT: BinarySessionState = + BinarySessionState( + currentTick = 0, + localPlayerIndex = -1, + buildArea = CoordGrid.INVALID, + updateZone = CoordGrid.INVALID, + regionZones = null, + ) + + private fun absCoord(buildArea: CoordGrid, regionZones: BuildArea?, coord: CoordGrid): CoordGrid { + if (regionZones == null || coord.x < 6400) { + return coord + } + val localX = coord.x - buildArea.x + val localZ = coord.z - buildArea.z + if (localX < 0 || localX >= 104 || localZ < 0 || localZ >= 104) { + return CoordGrid.INVALID + } + val localZoneX = localX ushr 3 + val localZoneZ = localZ ushr 3 + val template = regionZones[coord.level, localZoneX, localZoneZ] + if (template.invalid) { + return CoordGrid.INVALID + } + val copiedRotation = template.rotation + val copiedZoneX = template.zoneX + val copiedZoneZ = template.zoneZ + val copiedLevel = template.level + val unrotatedX = (copiedZoneX shl 3) or (localX and 0x7) + val unrotatedZ = (copiedZoneZ shl 3) or (localZ and 0x7) + return rotate(CoordGrid(copiedLevel, unrotatedX, unrotatedZ), copiedRotation) + } + + private fun rotate( + coordGrid: CoordGrid, + rotation: Int, + ): CoordGrid { + val zoneAbsX = coordGrid.x and 0x7.inv() + val zoneAbsZ = coordGrid.z and 0x7.inv() + val xInZone = coordGrid.x and 0x7 + val zInZone = coordGrid.z and 0x7 + return when (rotation) { + 1 -> CoordGrid(coordGrid.level, zoneAbsX + zInZone, zoneAbsZ + (7 - xInZone)) + 2 -> CoordGrid(coordGrid.level, zoneAbsX + (7 - xInZone), zoneAbsZ + (7 - zInZone)) + 3 -> CoordGrid(coordGrid.level, zoneAbsX + (7 - zInZone), zoneAbsZ + xInZone) + else -> coordGrid + } + } + } +} diff --git a/processor/src/main/kotlin/net/rsprox/processor/state/BinarySessionStateIterator.kt b/processor/src/main/kotlin/net/rsprox/processor/state/BinarySessionStateIterator.kt new file mode 100644 index 00000000..d0d54291 --- /dev/null +++ b/processor/src/main/kotlin/net/rsprox/processor/state/BinarySessionStateIterator.kt @@ -0,0 +1,39 @@ +package net.rsprox.processor.state + +import net.rsprot.protocol.message.IncomingMessage + +public class BinarySessionStateIterator( + private val messages: List, +) : Iterable { + override fun iterator(): Iterator { + return EntryIterator(messages) + } + + public class EntryIterator(private val messages: List) : Iterator { + private var state = BinarySessionState.DEFAULT + private var cursor = 0 + + override fun hasNext(): Boolean { + return cursor < messages.size + } + + override fun next(): Entry { + val message = messages[cursor++] + state = state.nextState(message) + return Entry(state, message) + } + } + + public class Entry( + private val state: BinarySessionState, + private val message: IncomingMessage, + ) { + public operator fun component1(): BinarySessionState { + return state + } + + public operator fun component2(): IncomingMessage { + return message + } + } +}