Radicade
Radicade is an unofficial, community-built private-server toolchain for archived Rec Room 2023 clients. It is two halves that meet in the middle:
- A server (
Server/) — an ASP.NET Core reimplementation of the RecNet API that the 2023 client expects: nameserver discovery, auth/account creation, players, rooms, matchmaking, clubs, gifts, storefront/commerce, moderation, a CDN + object storage, an admin panel API and a SignalR notification hub. - Client patches (
2023Patch/) — BepInEx 6 (IL2CPP) plugins that point a locally installed 2023 build at your own server: they rewrite the addresses the client hardcodes into its IL2CPP string table, redirect the service hosts the nameserver advertises, and replace the embedded TLS trust decision for one configured host only.
Not affiliated with Rec Room Inc. or Against Gravity. This project is for preservation and private testing with game clients you already own. Do not point it at, or use it against, official Rec Room services.
There is no
LICENSEfile in this repository yet — add one before publishing.
Repository layout
| Path | What it is |
|---|---|
Server/ |
ASP.NET Core 9 (.NET 9) server, ~545 C# files. Entity Framework Core + SQL Server, JWT bearer auth, ImageSharp for image transforms, SignalR notify hub. See Server/README.md. |
ServerTests/ |
xUnit test suite (~1,600 tests) run against EF Core InMemory/SQLite providers. See ServerTests/README.md. |
2023Patch/ |
BepInEx client plugins and the shared patch sources they compile. See 2023Patch/README.md. |
Tools/ |
Python, PowerShell and C#/Node developer tooling: metadata patching, install triage, interop repair, packaging. See Tools/README.md. |
RoomImports/ |
Captured room saves and asset bundles used by the room-import tests. Third-party game content. |
VPS/ |
Deployment and maintenance scripts for the hosted server. See VPS/README.md. |
docs/ |
Dated engineering notes (working logs, not polished docs). |
Caddyfile |
Reverse-proxy config used in front of the server in production. |
RadNet.sln |
Solution: Server, Server.Tests, RadicadePatch. |
dotnet-tools.json |
Pins the obfuscar.globaltool used to obfuscate the client plugin. |
How a patched client reaches the server
- The 2023 client hardcodes its bootstrap and service URLs.
Tools/patch-0831-client-metadata.py(and the Quest equivalent) rewrites the matching records in the game'sglobal-metadata.dat, so the client resolves your host instead ofrec.net. - At runtime the plugin serves
GET /nson your server — a nameserver document that advertises where every service lives.NameserverRedirectmaps any service host the client learned elsewhere onto the equivalent path on your server. - The plugin's embedded TLS stack accepts a certificate for the configured host only
(
TLS:AllowedHosts), so no system-wide trust change is needed. - The server answers those calls out of SQL Server plus its local CDN/data folders, and
pushes realtime traffic over the notify hub (
/notify/hub/v1).
Requirements
- .NET SDK 9 for the server, tests and client plugin. (Built here with SDK 10.0.401.)
- SQL Server for actually running the server (the dev connection string targets
.\SQLEXPRESS). The test suite does not need it. - Node.js for
Tools/AugustInterop/normalize.cjs. - BepInEx 6.x (IL2CPP) installed in a 2023 game folder, to build the client plugins.
- Python 3 and PowerShell for the scripts in
Tools/.
Build
dotnet build Server/Server.csproj
dotnet build ServerTests/Server.Tests.csproj
The solution RadNet.sln includes the client plugin too, which needs the BepInEx
assemblies and one source file that is not in this repository — see
Current status.
Run the server
dotnet run --project Server
In Development it listens on https://localhost:3030 and http://127.0.0.1:3031
and generates a self-signed dev certificate under RadicadeServer-Data/Persistent/.
In Production it listens on http://0.0.0.0:3030 and expects TLS to be terminated
in front of it — that is what the bundled Caddyfile (ns.radicade.app →
127.0.0.1:3030) does.
Database migrations are applied automatically at startup (Database.Migrate() plus a
set of idempotent Ensure…Column/Ensure…Table helpers for tables added after the
last migration).
Local data lives under RadicadeServer-Data/ by default: CDN/{Images,Videos,Storage,Custom}
and Persistent/Logs, Persistent/DataProtection-Keys. Both the public and private
data roots are overridable with Radicade:PublicDataPath / Radicade:PrivateDataPath.
Configuration
Settings are read from appsettings.json, appsettings.{Environment}.json, environment
variables and user secrets, in ASP.NET Core's usual order. The checked-in files carry
placeholders (USEYOURS); supply real values locally.
| Key | Purpose |
|---|---|
ConnectionStrings:DefaultConnection |
SQL Server connection string. Required. |
Radicade:ServerUrl |
Public base URL the server advertises. |
Radicade:ListenUrls |
Semicolon-separated Kestrel URLs; falls back to the environment defaults above. |
Radicade:JwtKey |
Signing key for session/access tokens. Required in Production. |
Radicade:AdminApiKey |
Shared secret for the /admin API and maintenance scripts. Required in Production. |
Radicade:SupportApiKey |
Second shared secret accepted by admin endpoints. |
Radicade:SteamApiKey |
Steam Web API key for identity proof. Required in Production unless TrustUnverifiedSteamIdentity. |
Radicade:TrustUnverifiedSteamIdentity |
Dev switch: accept unproved platform identity (defaulted on in Development when no key is set). |
Radicade:Photon:{RealtimeAppId,VoiceAppId,ChatAppId,Region} |
Photon app IDs handed to clients for realtime, voice and chat. |
Radicade:MailApiKey, MailApiUrl, MailFrom, MailFromName |
Outbound mail (Resend-compatible HTTP API). |
Radicade:AdminPanelUrl |
Admin panel origin the API points at. |
Radicade:Admins[] |
{ "Username", "Password" } panel login accounts. |
Radicade:TestInfluencerAccountIds, TestCoOwnerAccountIds |
Seeded test accounts. |
Radicade:PublicDataPath, Radicade:PrivateDataPath |
Override the data roots. |
AllowedHosts |
Host filtering. |
Discord:Webhooks:* |
Discord webhook URLs. Copy Server/Discord/Webhooks/webhooks.example.json to webhooks.json (git-ignored). |
Server/Program.cs refuses to start in Production while AdminApiKey, JwtKey or
SteamApiKey are blank, so set them as environment variables rather than committing
them:
export ConnectionStrings__DefaultConnection='Server=...;Database=RadicadeServer;...'
export Radicade__JwtKey='<random 32+ byte base64>'
export Radicade__AdminApiKey='<random>'
export Radicade__SteamApiKey='<steam web api key>'
Tests
dotnet test ServerTests/Server.Tests.csproj
The suite runs on Microsoft.EntityFrameworkCore.InMemory and SQLite, seeds its own
fixtures, and also compiles two shared client sources
(NameserverRedirect.cs, ImageSignatureRequest.cs) so the client/server routing
contract is tested in one place.
Configuration data
Server/RadicadeServer-Config/ holds the catalogs the server serves: storefront
captures (storefronts/sf*.json, embedded as resources so a wiped database or a
build without the folder still works), avatar/equipment/consumables catalogs,
levelup-rewards.json, keepsake-rooms.json and steamwhitelist.json. Dropping a
new sf{id}.json in overrides the embedded copy without a rebuild.
Current status
This is a working-in-progress preservation project, not a finished product:
ServerandServerTestscompile cleanly; the full test suite currently reports ~1,605 passing, 1 skipped and a handful failing on this checkout (storefront capture count, a few catalog/locker and weekly-challenge rollover tests). Re-run locally to see the current list.2023Patch/RadicadePatch(the current September client plugin) referencesRadicadeEacBypass/VoiceChatRestrictionPatches.cs, which is not part of this repository, sodotnet build RadNet.slnfails on that project until the file is supplied.Server,ServerTestsandRadicadeAugustClientare unaffected.- Client-side progress is tracked in
docs/: login, Photon multiplayer, watch UI and full room loading are the areas still being ported.
Documentation
| Doc | Contents |
|---|---|
docs/2023-AUGUST-BUILD.md |
August 2023 (build 20230825) client migration log. |
docs/2023-0831-CLIENT-SWITCH.md |
Switching the client to September 2023 (build 20230831) and the per-service host split. |
docs/QUEST-20230831-TEST.md, docs/QUEST-20230907-TEST.md |
Quest client TLS/instrumentation experiments. |
docs/2023-ONBOARDING-FORCE-NOTES.md, docs/GIFT-CONTEXT-DUMP.md, docs/KEEPSAKES-STATUS.md, docs/WEEKLY-CHALLENGES.md |
Feature-specific notes and enum dumps. |