Skip to content

Repository files navigation

β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—   β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•—   β–ˆβ–ˆβ•—
β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β•β•β•β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•‘β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β•šβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—   β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘     β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘    β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• 
β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β•šβ•β•β•β•β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘     β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘     β•šβ–ˆβ–ˆβ•”β•  
β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘   β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘      β–ˆβ–ˆβ•‘   
β•šβ•β•  β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β•β•   β•šβ•β•    β•šβ•β•β•β•β•β•β•šβ•β•   β•šβ•β•      β•šβ•β•   

rs-majula

The first fully feature-complete, multi-revision, RuneScape private server engine written in Rust -- and the first private server to build its game cache from source assets to CRCs that perfectly match the original Jagex game cache.

Important

rs-majula is the project, Cargo workspace, and canonical engine name: a from-scratch Rust reimplementation of a RuneScape 2 game server, with byte-identical protocol and content emulation, a single-threaded deterministic game loop, and an async tokio host. The stock client connects and plays against unmodified cache content.


Overview

The workspace is 19 crates organized by responsibility:

  • rs-engine/ -- See rs-engine/README.md for the full technical whitepaper.
  • rs-pack/ -- the content/cache compiler (also invoked in-process at boot).
  • rs-protocol/ (+ macros/) -- the logic-free wire codec.
  • rs-server/ -- the async tokio binary: bootstrap, sockets, the HTTP service that serves the web client, and the terminal dashboard (TUI).
  • rs-ether/ -- an Elixir sidecar for cross-world social features (git submodule). Login is gated on it -- see requirements.
  • content/, .keys/, public/ -- runtime assets (cache sources packed at boot, the RSA key pair, and the web client), already included in the repo.

Prerequisites

Tool Version Why
Rust (via rustup) stable, β‰₯ 1.95 (MSRV), edition 2024 Pinned by rust-toolchain.toml, so rustup installs the right toolchain automatically. Builds use -C target-cpu=native (the binary is tuned to the building machine's CPU).
C linker -- Required by any Rust build: MSVC Build Tools on Windows, cc/clang on Linux/macOS.
Docker + Compose -- Required to log in. Runs Postgres 17 (docker-compose.yml); the server authenticates/persists accounts against it. Until Postgres is connected, logins are rejected with login server offline.
Elixir + mix ~> 1.15 Required to log in. Runs the rs-ether sidecar, which the login flow depends on (cross-world login checks). The server boots and serves the web client without it, but every login attempt returns login server offline. Auto-spawned via cmd /c (Windows); on Linux/macOS start it from rs-ether/ yourself.
Git -- rs-ether is a submodule -- clone with --recursive.

Note

To actually log in you need both Postgres (Docker) up and the ether sidecar connected. If Postgres is down or the sidecar fails to start (e.g. Elixir isn't installed), the server still serves the web client, but the client will report "login server offline" on every login.


Get the source

git clone --recursive https://github.com/RustCityRS/rs-majula.git
cd rs-majula
# already cloned without submodules?
git submodule update --init --recursive

Quick start (single world)

Needs Rust + Docker + Elixir. The RSA keys and cache content ship in the repo, so there is nothing else to generate.

# 1. Start Postgres (background; data persists in a named volume)
docker compose up -d

# 2. Build & run the server (node 10 = world 1).
#    On first boot the ether sidecar runs `mix deps.get` + `ecto.create` +
#    `ecto.migrate` against Postgres, so Docker must be up first.
cargo run -p rs-server

# 3. Open the web client and log in
#    http://localhost:8080/rs2.cgi

Tip

First build compiles the whole workspace and takes a while. For running a populated world locally, prefer the dev-opt profile (near-release speed, still has debuginfo): cargo run --profile dev-opt -p rs-server.

Tip

For maximum performance (production or benchmarking), run in release mode -- cargo run --release -p rs-server -- for full optimizations and fat LTO, at the cost of the longest compile.

Stop Postgres when you're done with docker compose down (add -v to also wipe the database volume).


Running a second world (cluster)

The cargo world1 / cargo world2 aliases bring up a two-node cluster (each auto-spawns its own ether sidecar; they mesh via the shared --cluster list):

docker compose up -d
cargo world1   # --node-id 10, cluster world10+world11
cargo world2   # --node-id 11, in a second terminal -- the cluster meshes

See rs-ether/README.md for sidecar details.


Command-line arguments

All configuration is via CLI flags (clap). This is the complete set -- run cargo run -p rs-server -- --help for the canonical output.

Argument Default Description
--host <HOST> 0.0.0.0 Bind address for the TCP game + HTTP listeners.
--http-port <HTTP_PORT> 8070 + node_id (8080) HTTP port -- web client + cache archives.
--tcp-port <TCP_PORT> 43584 + node_id (43594) TCP game-protocol port.
--private-key <PRIVATE_KEY> .keys/private.pem RSA private key (PEM) for the login handshake.
--members true Members world (vs free-to-play) content rules.
--client-pathfinder true Trust client-computed movement paths.
--no-tui false Disable the TUI dashboard; use stdout logging (auto-falls back when stdout isn't a TTY).
--verify true Verify packed-cache byte-identity at boot (pack_all).
--node-id <NODE_ID> 10 World node ID (10 = world 1, 11 = world 2, …); drives the derived port scheme.
--ether-port <ETHER_PORT> 5000 + node_id (5010) Ether sidecar TCP port.
--db-host <DB_HOST> localhost Postgres hostname.
--db-port <DB_PORT> 5432 Postgres port.
--db-name <DB_NAME> postgres Postgres database name.
--db-user <DB_USER> postgres Postgres username.
--db-pass <DB_PASS> password Postgres password.
--cluster <CLUSTER> "" Comma-separated cluster node list (e.g. world10@127.0.0.1,world11@127.0.0.1), forwarded to the sidecar mesh.
--pepper <PEPPER> localhost Server-side pepper for password hashing.

Note

--members, --client-pathfinder, --no-tui, and --verify are boolean flags (defaults shown). The --db-* defaults match docker-compose.yml, so the server connects with no extra flags.


Build profiles

Defined in .cargo/config.toml:

  • dev (default) -- unoptimized, full debuginfo; fast compiles, enables the debug-only hot-reload.
  • dev-opt -- inherits = dev with opt-level = 2; the practical profile for running a real world locally. cargo run --profile dev-opt -p rs-server.
  • release -- maximum performance: opt-level=3, fat LTO, panic = "unwind" (load-bearing for the engine's catch_unwind recovery). Slowest to compile; use it for production and benchmarking. cargo run --release -p rs-server.

How to Play

There are two ways to play the server.

1. The original shipped Java client

Depending on your targeted revision, navigate to the respective /public/{REV}/client.jar file. Run the following command:

java -cp client.jar client 10 0 highmem members 10

Note

Usage: node-id, port-offset, [lowmem/highmem], [free/members], storeid

2. The ported JavaScript browser client

Navigate to the following address on any modern web browser:

http://localhost:8080/

Note

Any browser should be supported as long as it supports WebAssembly. This includes any mobile browser as well.


Multi-Revision

The engine supports multiple revision targets. The ones listed below can be targeted to your choice. Simply change the REV located in /.cargo/config.toml and rebuild.

[env]
REV = "289"

225 (2004-05-18)

244 (2004-06-28)

245.2 (2004-07-13)

254 (2004-09-07)

274 (2004-11-24)

289 (2005-01-17)


Contributing

All are welcome to help contribute to the project. I especially am always looking for performance opportunities that could be had, whether CPU or RAM optimizations.

  • Please provide benchmarks of a before & after if you open a PR for any performance improvements.
  • Please provide sources of any additional engine or content changes you open a PR for.
  • I am using a Windows machine and am unable to validate the project under Linux or MacOS myself, relying on Github actions.

Tip

When you open or push to a PR, a Github action will run jobs to validate that all revisions build, compile content and test. You do not have to manually validate every supported revision yourself.


Bearer of the curse, seek misery.

About

A Multi-Revision RuneScape 2 Game Server & Engine in Rust

Topics

Resources

Stars

11 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages