Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# RSProt

[![GitHub Actions][actions-badge]][actions] [![MIT license][mit-badge]][mit]
[![OldSchool - 221 - 237 (Alpha)](https://img.shields.io/badge/OldSchool-221--237_(Alpha)-9a1abd)](https://github.com/blurite/rsprot/tree/master/protocol/osrs-237/osrs-237-api/src/main/kotlin/net/rsprot/protocol/api)
[![OldSchool - 221 - 238 (Alpha)](https://img.shields.io/badge/OldSchool-221--238_(Alpha)-9a1abd)](https://github.com/blurite/rsprot/tree/master/protocol/osrs-238/osrs-238-api/src/main/kotlin/net/rsprot/protocol/api)

## Status
> [!NOTE]
Expand All @@ -16,7 +16,7 @@ In order to add it to your server, add the below line under dependencies
in your build.gradle.kts.

```kts
implementation("net.rsprot:osrs-237-api:1.0.0-ALPHA-20260409")
implementation("net.rsprot:osrs-238-api:1.0.0-ALPHA-20260506")
```

An in-depth tutorial on how to implement it will be added into this read-me
Expand All @@ -32,12 +32,12 @@ other revisions are welcome, but will not be provided by default.
- Java 11

## Supported Versions
This library currently supports revision 221-237 OldSchool desktop clients.
This library currently supports revision 221-238 OldSchool desktop clients.

## Quick Guide
This section covers a quick guide for how to use the protocol after implementing
the base API. It is not a guide for the base API itself, that will come in the
future. This specific quick guide refers to revision 237. Revisions older
future. This specific quick guide refers to revision 238. Revisions older
than 235 have a significantly different API and will not be explored here.
It is recommented you upgrade to latest, or view an older readme in history.

Expand Down
30 changes: 30 additions & 0 deletions WHATSNEW.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
## What's New?

### Revision 238

> [!IMPORTANT]
> Rebuild WorldEntity V4 now uses absolute zone coordinates in the provider
> interface.

#### Additions
- AMBIENCE_START packet. Loops an ambience sound effect indefinitely.
NOTE: Ambience sound effects are their own cache archive, not to be confused
with regular sound effects.
- AMBIENCE_STOP packet.
- CAM_UNLOCK packet. Uncaps the pitch min and max values of the camera.
- CAM_SKYBOX packet. Sets a skybox model at 0,0 coordinate. Currently only
works on native - java has not fully been wired up.
- CAM_TARGET_V4 packet. No longer takes world entity id with every type,
the client simply infers it based on context. Additionally now supports a
coordinate target.

#### Changes
- Face angle & face pathingentity have been merged into a single
extended info for players and NPCs. It now supports more properties,
and the ability to face a world entity.

#### Removals
- REBUILD_NORMAL_V1
- REBUILD_REGION_V1
- IF_SETMODEL_V1
- ZBUF
- OP{LOC,NPC,OBJ}1..5

### Revision 237

> [!IMPORTANT]
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ plugins {

allprojects {
group = "net.rsprot"
version = "1.0.0-ALPHA-20260409"
version = "1.0.0-ALPHA-20260506"

repositories {
mavenCentral()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import net.rsprot.buffer.JagByteBuf
import net.rsprot.buffer.bitbuffer.toBitBuf
import net.rsprot.crypto.xtea.XteaKey
import net.rsprot.protocol.game.outgoing.map.util.RebuildRegionZone
import net.rsprot.protocol.game.outgoing.map.util.ReferenceZone

/**
* The maximum theoretical number of mapsquares that can be sent in a single
Expand Down Expand Up @@ -77,7 +76,7 @@ internal fun encodeRegionV1(

internal fun encodeRegionV2(
buffer: JagByteBuf,
zones: List<ReferenceZone?>,
zones: List<RebuildRegionZone?>,
) {
// Mapsquare count, temporary value
val marker = buffer.writerIndex()
Expand All @@ -97,7 +96,7 @@ internal fun encodeRegionV2(
continue
}
bitbuf.pBits(1, 1)
bitbuf.pBits(26, zone.packed)
bitbuf.pBits(26, zone.referenceZone.packed)
val mapsquareId = zone.mapsquareId
if (contains(mapsquares, distinctMapsquareCount, mapsquareId)) {
continue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package net.rsprot.protocol.game.outgoing.map

import net.rsprot.protocol.ServerProtCategory
import net.rsprot.protocol.game.outgoing.GameServerProtCategory
import net.rsprot.protocol.game.outgoing.map.util.ReferenceZone
import net.rsprot.protocol.game.outgoing.map.util.RebuildRegionZone
import net.rsprot.protocol.message.OutgoingGameMessage

/**
Expand All @@ -23,7 +23,7 @@ public class RebuildRegionV2 private constructor(
private val _zoneX: UShort,
private val _zoneZ: UShort,
public val reload: Boolean,
public val zones: List<ReferenceZone?>,
public val zones: List<RebuildRegionZone?>,
) : OutgoingGameMessage {
public constructor(
zoneX: Int,
Expand Down Expand Up @@ -111,7 +111,7 @@ public class RebuildRegionV2 private constructor(
zoneX: Int,
zoneZ: Int,
level: Int,
): ReferenceZone?
): RebuildRegionZone?
}

private companion object {
Expand All @@ -128,8 +128,8 @@ public class RebuildRegionV2 private constructor(
centerZoneX: Int,
centerZoneZ: Int,
zoneProvider: RebuildRegionZoneProvider,
): List<ReferenceZone?> {
val zones = ArrayList<ReferenceZone?>(4 * 13 * 13)
): List<RebuildRegionZone?> {
val zones = ArrayList<RebuildRegionZone?>(4 * 13 * 13)
for (level in 0..<4) {
for (zoneX in (centerZoneX - 6)..(centerZoneX + 6)) {
for (zoneZ in (centerZoneZ - 6)..(centerZoneZ + 6)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package net.rsprot.protocol.game.outgoing.map

import net.rsprot.protocol.ServerProtCategory
import net.rsprot.protocol.game.outgoing.GameServerProtCategory
import net.rsprot.protocol.game.outgoing.map.util.ReferenceZone
import net.rsprot.protocol.game.outgoing.map.util.RebuildRegionZone
import net.rsprot.protocol.message.OutgoingGameMessage

/**
Expand All @@ -15,7 +15,7 @@ import net.rsprot.protocol.message.OutgoingGameMessage
public class RebuildWorldEntityV4 private constructor(
private val _baseX: UShort,
private val _baseZ: UShort,
public val zones: List<ReferenceZone?>,
public val zones: List<RebuildRegionZone?>,
) : OutgoingGameMessage {
public constructor(
baseX: Int,
Expand All @@ -26,7 +26,13 @@ public class RebuildWorldEntityV4 private constructor(
) : this(
baseX.toUShort(),
baseZ.toUShort(),
buildRebuildWorldEntityZones(sizeX, sizeZ, zoneProvider),
buildRebuildWorldEntityZones(
baseX ushr 3,
baseZ ushr 3,
sizeX,
sizeZ,
zoneProvider,
),
) {
require(sizeX in 0..<13) {
"Size x must be in range of 0..<13: $sizeX"
Expand Down Expand Up @@ -81,45 +87,46 @@ public class RebuildWorldEntityV4 private constructor(
public fun interface RebuildWorldEntityZoneProvider {
/**
* Provides a zone that the client must copy based on the parameters.
* This 'provide' function will be called with the relative-to-worldentity zone coordinates,
* so starting with 0,0 and ending before sizeX,sizeZ. The server is responsible for
* looking up the actual zone that was copied for that world entity.
*
* @param zoneX the zone x coordinate of the region zone, relative to the south-westernmost zone
* @param zoneZ the zone z coordinate of the region zone, relative to the south-westernmost zone
* @param zoneX the x coordinate of the region zone
* @param zoneZ the z coordinate of the region zone
* @param level the level of the region zone
* @return the zone to be copied, or null if there's no zone to be copied there.
*/
public fun provide(
zoneX: Int,
zoneZ: Int,
level: Int,
): ReferenceZone?
): RebuildRegionZone?
}

private companion object {
/**
* Builds a list of rebuild region zones to be written to the client,
* in order as the client expects them.
* @param baseZoneX the south-western zone x coordinate
* @param baseZoneZ the south-western zone z coordinate
* @param sizeX the width of the worldentity
* @param sizeZ the length of the worldentity
* @param zoneProvider the functional interface providing the necessary information
* to be written to the client
* @return a list of rebuild region zones (or nulls) for each zone in the build area.
*/
private fun buildRebuildWorldEntityZones(
baseZoneX: Int,
baseZoneZ: Int,
sizeX: Int,
sizeZ: Int,
zoneProvider: RebuildWorldEntityZoneProvider,
): List<ReferenceZone?> {
val zones = ArrayList<ReferenceZone?>(4 * sizeX * sizeZ)
): List<RebuildRegionZone?> {
val zones = ArrayList<RebuildRegionZone?>(4 * sizeX * sizeZ)
for (level in 0..<4) {
for (zoneX in 0..<sizeX) {
for (zoneZ in 0..<sizeZ) {
zones +=
zoneProvider.provide(
zoneX,
zoneZ,
baseZoneX + zoneX,
baseZoneZ + zoneZ,
level,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ import net.rsprot.crypto.xtea.XteaKey
*/
public class RebuildRegionZone public constructor(
public val referenceZone: ReferenceZone,
public val key: XteaKey,
public val key: XteaKey = XteaKey.ZERO,
) {
@JvmOverloads
public constructor(
zoneX: Int,
zoneZ: Int,
level: Int,
rotation: Int,
key: XteaKey,
key: XteaKey = XteaKey.ZERO,
) : this(
ReferenceZone(
zoneX,
Expand Down
1 change: 1 addition & 0 deletions protocol/osrs-238/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// No-op
40 changes: 40 additions & 0 deletions protocol/osrs-238/osrs-238-api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
dependencies {
implementation(platform(rootProject.libs.netty.bom))
api(rootProject.libs.netty.buffer)
implementation(rootProject.libs.netty.transport)
implementation(rootProject.libs.netty.handler)
implementation(rootProject.libs.netty.native.epoll)
implementation(rootProject.libs.netty.native.kqueue)
implementation(rootProject.libs.netty.iouring)
implementation(rootProject.libs.netty.native.macos.dns.resolver)
val epollClassifiers = listOf("linux-aarch_64", "linux-x86_64", "linux-riscv64")
val kqueueClassifiers = listOf("osx-x86_64")
val iouringClassifiers = listOf("linux-aarch_64", "linux-x86_64")
for (classifier in epollClassifiers) {
implementation(variantOf(rootProject.libs.netty.native.epoll) { classifier(classifier) })
}
for (classifier in kqueueClassifiers) {
implementation(variantOf(rootProject.libs.netty.native.kqueue) { classifier(classifier) })
}
for (classifier in iouringClassifiers) {
implementation(variantOf(rootProject.libs.netty.iouring) { classifier(classifier) })
}
implementation(rootProject.libs.inline.logger)
api(projects.protocol)
api(projects.compression)
api(projects.crypto)
api(projects.protocol.osrs238.osrs238Common)
api(projects.protocol.osrs238.osrs238Model)
implementation(projects.protocol.osrs238.osrs238Internal)
implementation(projects.protocol.osrs238.osrs238Desktop)
implementation(projects.protocol.osrs238.osrs238Shared)
implementation(projects.buffer)
}

mavenPublishing {
pom {
name = "RsProt OSRS 238 API"
description = "The API module for revision 238 OldSchool RuneScape networking, " +
"offering an all-in-one implementation."
}
}
Loading
Loading