added some stuff

This commit is contained in:
JogmansonReal
2026-10-16 23:43:29 -07:00
parent 55175acdf6
commit 5c047bd19c
8 changed files with 470 additions and 1 deletions
+1
View File
@@ -74,6 +74,7 @@ Tests/**/TestResults/
/2023Patch /2023Patch
!/2023Patch/ !/2023Patch/
/2023Patch/* /2023Patch/*
!/2023Patch/README.md
!/2023Patch/RadicadeAugustClient/ !/2023Patch/RadicadeAugustClient/
/2023Patch/RadicadeAugustClient/bin/ /2023Patch/RadicadeAugustClient/bin/
/2023Patch/RadicadeAugustClient/obj/ /2023Patch/RadicadeAugustClient/obj/
+78
View File
@@ -0,0 +1,78 @@
# 2023Patch — client-side plugins
BepInEx 6 (IL2CPP) plugins that make an installed 2023 Rec Room build talk to a
Radicade server instead of Rec Room's own services. All projects target `net6.0`, use
Harmony, and `AllowUnsafeBlocks` for the metadata/image-key work.
## Projects
| Folder | Plugin | Notes |
| --- | --- | --- |
| `RadicadePatch/` | `com.radicade.patch` "RadicadePatch" 3.0.0 | Current plugin, aimed at the September 2023 build (`20230831`). The server address is compiled in (`Plugin.ServerAddress`, `https://ns.radicade.app/`). |
| `RadicadeAugustClient/` | `com.radicade.eacbypass` "Radicade August Client" 2.0.0 | Earlier plugin for the August 2023 build (`20230825`). Requires the metadata/interop repair in `Tools/AugustInterop` first. See its own README. |
| `RadicadeEacBypass/` | — | Shared `.cs` sources, not a project. Linked into both plugins (and into `ServerTests`). The root `.gitignore` ignores the folder and then re-allows each shared file individually, so add an entry there when you add a file. `VoiceChatRestrictionPatches.cs` is neither tracked nor present. |
## Building a plugin
Both plugin csproj files reference BepInEx assemblies through a `BepInExRoot`
property that defaults to a machine-local path. Point it at the game's `BepInEx`
folder:
```bash
dotnet build 2023Patch/RadicadePatch/RadicadePatch.csproj -c Release \
-p:BepInExRoot='/c/Program Files/RecRoom/BepInEx'
```
Then copy the produced `RadicadePatch.dll` into `BepInEx/plugins`. The two plugins
share a configuration identity, so **install only one at a time** — disable or back up
the other DLL.
> `RadicadePatch` currently fails to compile because it links
> `RadicadeEacBypass/VoiceChatRestrictionPatches.cs`, which is not in this
> repository. Supply that file (or drop the `<Compile Include>` and the calls to it
> from `Plugin.cs`/`VoiceChatBanFlagPatches.cs`) before building it.
> `RadicadeAugustClient` does not reference that file.
## What the patches do
- **Nameserver redirect** (`NameserverRedirect.cs`) — maps the service hosts the
client learns from any nameserver onto the equivalent paths on the Radicade server
(`auth.…` → `/auth`, `rooms.…` → `/rooms`, and ~40 more), including WebSocket paths.
- **Connection gate / nameserver patches** — pin the client to the configured server
and reject other hosts.
- **Embedded TLS** (`EmbeddedTlsPatches.cs`) — replaces the trust decision for the
configured host only, so no certificate is installed system-wide and no other host
becomes trusted.
- **Hub socket auth** (`HubSocketAuth.cs`) — carries the session token onto the notify
WebSocket.
- **Response repair / HTTP tolerance** (`ResponseRepair.cs`, `HttpTolerancePatches.cs`)
— normalises responses the client is strict about and tolerates the shapes the
reimplementation produces.
- **Image signature key** (`ImageSignatureRequest.cs`) — detects the key id from the
game's metadata so signed image requests can be verified.
- **Client text rewrites**, UI prefab repair, collider-cast guard, keepsake tool,
invite-online-friends and voice-chat flag patches — the smaller gameplay/UI fixes
in `RadicadePatch/`.
## Configuration
The August plugin writes `BepInEx/config/com.radicade.eacbypass.cfg`:
```ini
[Connection]
ServerUrl = https://localhost:3030
[TLS]
AllowedHosts = localhost
```
TLS exceptions are limited to `AllowedHosts`. The current `RadicadePatch` compiles
its server address in and warns at startup if the install's
`RecRoom_Data/radicade-patch.json` marker points at a different server.
## Release build
The release pipeline obfuscates the plugin with **Obfuscar** (`RadicadePatch/obfuscar.xml`,
tool pinned in the root `dotnet-tools.json`). Because obfuscation renames members that
the plugin looks up by name (Harmony patches, reflection, interop), run
`Tools/check-obfuscation-safety.py` first — it fails when a renamed member is still
reached by string.
+167
View File
@@ -0,0 +1,167 @@
# 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 `LICENSE` file** in this repository yet — add one before publishing.
## Repository layout
| Path | What it is |
| --- | --- |
| [`Server/`](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`](Server/README.md). |
| [`ServerTests/`](ServerTests) | xUnit test suite (~1,600 tests) run against EF Core InMemory/SQLite providers. See [`ServerTests/README.md`](ServerTests/README.md). |
| [`2023Patch/`](2023Patch) | BepInEx client plugins and the shared patch sources they compile. See [`2023Patch/README.md`](2023Patch/README.md). |
| [`Tools/`](Tools) | Python, PowerShell and C#/Node developer tooling: metadata patching, install triage, interop repair, packaging. See [`Tools/README.md`](Tools/README.md). |
| [`RoomImports/`](RoomImports) | Captured room saves and asset bundles used by the room-import tests. Third-party game content. |
| [`VPS/`](VPS) | Deployment and maintenance scripts for the hosted server. See [`VPS/README.md`](VPS/README.md). |
| [`docs/`](docs) | Dated engineering notes (working logs, not polished docs). |
| [`Caddyfile`](Caddyfile) | Reverse-proxy config used in front of the server in production. |
| [`RadNet.sln`](RadNet.sln) | Solution: `Server`, `Server.Tests`, `RadicadePatch`. |
| [`dotnet-tools.json`](dotnet-tools.json) | Pins the `obfuscar.globaltool` used to obfuscate the client plugin. |
## How a patched client reaches the server
1. 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's
`global-metadata.dat`, so the client resolves *your* host instead of `rec.net`.
2. At runtime the plugin serves `GET /ns` on your server — a nameserver document that
advertises where every service lives. `NameserverRedirect` maps any service host the
client learned elsewhere onto the equivalent path on your server.
3. The plugin's embedded TLS stack accepts a certificate for the configured host only
(`TLS:AllowedHosts`), so no system-wide trust change is needed.
4. 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
```bash
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](#current-status).
## Run the server
```bash
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:
```bash
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
```bash
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:
- `Server` and `ServerTests` compile 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) references
`RadicadeEacBypass/VoiceChatRestrictionPatches.cs`, which is not part of this
repository, so `dotnet build RadNet.sln` fails on that project until the file is
supplied. `Server`, `ServerTests` and `RadicadeAugustClient` are unaffected.
- Client-side progress is tracked in [`docs/`](docs): login, Photon multiplayer, watch
UI and full room loading are the areas still being ported.
## Documentation
| Doc | Contents |
| --- | --- |
| [`docs/2023-AUGUST-BUILD.md`](docs/2023-AUGUST-BUILD.md) | August 2023 (build 20230825) client migration log. |
| [`docs/2023-0831-CLIENT-SWITCH.md`](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-20230831-TEST.md), [`docs/QUEST-20230907-TEST.md`](docs/QUEST-20230907-TEST.md) | Quest client TLS/instrumentation experiments. |
| [`docs/2023-ONBOARDING-FORCE-NOTES.md`](docs/2023-ONBOARDING-FORCE-NOTES.md), [`docs/GIFT-CONTEXT-DUMP.md`](docs/GIFT-CONTEXT-DUMP.md), [`docs/KEEPSAKES-STATUS.md`](docs/KEEPSAKES-STATUS.md), [`docs/WEEKLY-CHALLENGES.md`](docs/WEEKLY-CHALLENGES.md) | Feature-specific notes and enum dumps. |
+1 -1
View File
@@ -5,7 +5,7 @@ VisualStudioVersion = 17.14.36705.20
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{9DDA5EBF-9DCD-45C3-83ED-2AC383109529}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{9DDA5EBF-9DCD-45C3-83ED-2AC383109529}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.Tests", "Server.Tests\Server.Tests.csproj", "{C108E570-E61B-49CF-8590-CF8B983ED6B0}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.Tests", "ServerTests\Server.Tests.csproj", "{C108E570-E61B-49CF-8590-CF8B983ED6B0}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2023Patch", "2023Patch", "{05A810AF-0524-D221-1DA2-A901B183F7A6}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2023Patch", "2023Patch", "{05A810AF-0524-D221-1DA2-A901B183F7A6}"
EndProject EndProject
+86
View File
@@ -0,0 +1,86 @@
# Server
ASP.NET Core 9 (`net9.0`) implementation of the RecNet API surface that archived
2023 Rec Room clients call. Root namespace `RadicadeServer`; one process serves both
the game API and the public web/share endpoints.
## Running
```bash
dotnet run --project Server
```
Development listens on `https://localhost:3030` and `http://127.0.0.1:3031` (see
`appsettings.Development.json`); Production defaults to `http://0.0.0.0:3030` for a
TLS-terminating proxy in front (see the repo-level `Caddyfile`).
`Program.cs` builds the host, loads configuration into `DBConfig`, then:
- fails fast in Production if `AdminApiKey`, `JwtKey` or `SteamApiKey` are blank;
- registers the EF Core `RecDBContext` (SQL Server, retry-on-failure, pending-model
warnings ignored);
- wires JWT bearer auth (signing key from `Radicade:JwtKey`; the `access_token` query
parameter is accepted on notify-hub paths for WebSocket clients) plus a token
version check that revokes sessions;
- configures ImageSharp (with a `cropSquare` command used by avatar images);
- applies migrations and idempotent schema fix-ups at startup;
- maps controllers and the `NotifyHub` SignalR hubs.
## Layout
| Folder | Contents |
| --- | --- |
| `Program.cs` | Host, DI, auth, middleware pipeline and startup schema work. |
| `DB/` | `DBConfig` (all runtime configuration + paths), `RecDBContext`, `Defaults`, factory and bootstrap helpers. |
| `Migrations/` | EF Core migrations. |
| `NameServer/` | `GET /`, `/ns`, `/nameserver` — the document that tells a client where every service lives. |
| `Auth/`, `AccountCreation/` | Login, token issuance, onboarding flows, platform identity proofing. |
| `Players/`, `PlayersBanned/`, `Relationships/`, `Messages/`, `Chat/`, `Notifications/` | Player records, presence, friends, direct messages, chat and notifications. |
| `Rooms/`, `Clubs/`, `Board/`, `PlayerEvents/`, `Inventions/`, `Keepsakes/`, `Studio/`, `Royale/` | User-generated and social content surfaces. |
| `Avatars/`, `CustomAvatarItems/`, `Images/`, `CDN/`, `Storage/`, `LoadingScreens/`, `Launcher/` | Cosmetics, image/video CDN routes, stored blobs, launcher manifest. |
| `Commerce/`, `Storefront/`, `Gift/`, `Promotions/`, `PlayerCheer/`, `ProgressionEvents/` | Economy: storefronts, purchases, gifts, promotions, progression rewards. |
| `Matchmaking/`, `Activities/`, `Leaderboards/`, `Compatibility/`, `Health/` | Session/matchmaking, activity feed, leaderboards, version compatibility checks, health endpoints. |
| `Moderation/`, `PlayerReporting/`, `PlayerWarnings/`, `PlayerReputation/`, `BanAppeal/` | Moderation and safety tooling. |
| `Config/` | Client configuration/split-test endpoints and player settings. |
| `Analytics/`, `BugReporting/` | Game log ingestion and bug reports. |
| `Admin/` | Admin panel API. Endpoints authenticate with `AdminApiKey`/`SupportApiKey` (see `AdminUtils`). |
| `Web/` | Public web/share API (`/web/...`). |
| `Discord/` | Discord webhook config (`webhooks.json` git-ignored, `webhooks.example.json` tracked). |
| `RecNet/`, `Radicade/` | Shared response/enum models and RecNet-shaped DTOs. |
| `RadicadeServer-Config/` | Catalogs served to clients (storefronts, avatars, equipment, keepsakes, level-up rewards, Steam whitelist). |
| `Middleware/`, `Extensions/`, `Utils/` | Cross-cutting plumbing and helpers. |
| `Tooling/` | Debug and test-case management endpoints. |
## Routing and multi-version support
Routes are declared with controller attributes and many endpoints deliberately expose
several paths for the same handler, because different 2023 builds call slightly
different URLs (for example `~/clubs/club/home/me`, `~/club/home/me` and
`~/api/clubs/v1/home/me`). Supported client versions are listed in
`DBConfig.SupportedGameVersions`, with **`20230831`** (September 2023) as the primary
target and `20230301`–`20231207` plus a couple of 2025 builds also accepted.
CORS is wide open (`AllowAllOrigins`), which is appropriate for a self-hosted server
serving the game client and local tooling.
## Data
`DBConfig.PublicData` defaults to `./RadicadeServer-Data/` and is split into:
- `CDN/Images`, `CDN/Videos`, `CDN/Storage`, `CDN/Custom` — served content and uploads;
- `Persistent/Logs` — rotating logs and generated `debugkey.txt`;
- `Persistent/DataProtection-Keys` — Data Protection key ring;
- `Persistent/localhost-rsa-aes-devcert.pfx` — the Development HTTPS certificate.
## Configuration
See the configuration table in the [root README](../README.md#configuration). The
checked-in `appsettings.*.json` files contain `USEYOURS` placeholders; override real
values with user secrets or environment variables (`Radicade__JwtKey`,
`ConnectionStrings__DefaultConnection`, …). Production startup validates the three
required secrets.
## Tests
Covered by [`ServerTests/`](../ServerTests) — see that README for how to run them and
which helpers they use.
+56
View File
@@ -0,0 +1,56 @@
# ServerTests
xUnit suite for the server and for the parts of the client patch that must agree with
it. The folder is `ServerTests/` but the project file (and assembly) is
`Server.Tests.csproj` / `Server.Tests.dll`, root namespace `RadicadeServer.Tests`.
## Running
```bash
# whole suite
dotnet test ServerTests/Server.Tests.csproj
# a single feature area
dotnet test ServerTests/Server.Tests.csproj --filter FullyQualifiedName~GiftTests
# one test
dotnet test ServerTests/Server.Tests.csproj --filter DisplayName~WeeklyChallenge
```
Around 1,600 tests run in well under a minute. On the current checkout roughly
1,605 pass, 1 is skipped and a handful fail (storefront capture count, some
catalog/locker and weekly-challenge rollover tests) — treat the run output as the
source of truth rather than the README.
## How the tests are wired
- **Database providers.** Tests never touch SQL Server. They build a context through
`TestDbContextFactory`, which uses `Microsoft.EntityFrameworkCore.InMemory` where a
fast stand-in is enough and `Microsoft.EntityFrameworkCore.Sqlite` where real
relational behaviour matters.
- **Static configuration.** A lot of server behaviour is configured through static
fields on `DBConfig` (for example `DBConfig.SteamApiKey`, `DBConfig.AdminApiKey`,
`DBConfig.JwtKey`). Tests assign throwaway values such as `"unit-test-steam-api-key"`
and restore the previous value in a `finally` block.
- **Fixtures.** `Fixtures/*.json` are linked from `Server/RadicadeServer-Config/`
(`avatar.json`, `merged-avatar.json`, `equipment*.json`, `consumables.json`,
`avatar-item-lookup.json`, `2022-avatar.json`) and copied to the output directory;
`Fixtures/split-tests-20230301.json` lives in the repository itself.
- **Shared client sources.** `NameserverRedirect.cs` and `ImageSignatureRequest.cs`
from `2023Patch/RadicadeEacBypass/` are compiled into this test assembly, so the
host-redirect map and image-signature contract are asserted server-side.
- **Test doubles.** Helpers such as `TestDbContextFactory`, `SetBody`, `CreateEventAsync`
and the various request builders keep test bodies focused on the assertion.
## Adding tests
Follow the existing shape: one class per feature area, `[Fact]`/`[Theory]` per case,
names that read as a sentence about the behaviour (`AvatarUnlockCatalog_Preserves…`).
Prefer asserting the exact JSON shape the 2023 client expects over asserting internal
state, since response-shape conformance is what most of this suite protects.
## Known warnings
The build emits `xUnit1031` warnings in `RecNetShapeConformanceTests.cs` where tests
block on tasks (`.Result`/`.GetAwaiter().GetResult()`). They are pre-existing; the
inline fix is to make the test `async` and `await`.
+51
View File
@@ -0,0 +1,51 @@
# Tools
Developer and diagnostic scripts. Most are read-only: the triage and inspection tools
never modify a game install, and the patchers write a separate output or require an
explicit `--apply`.
## C# / Node projects
| Tool | What it does |
| --- | --- |
| `AugustInterop/` (C#, net9.0 + `normalize.cjs`) | Repairs il2cpp metadata/interop generation for the August 2023 build (`20230825`): normalises the shuffled 256-byte `global-metadata.dat` header and patches the BepInEx loader to point at the normalised copy. See its [README](AugustInterop/README.md). |
| `ColliderGuard.Tests/` (C#, net6.0, exe) | Regression harness for `ColliderCastGuardPatch` / `ToolCollisionLayerRestore`, compiled straight from `2023Patch/RadicadePatch/` against the game's Harmony/MonoMod assemblies. |
| `CommentStripper/` (C#, net9.0, exe) | Strips comments from C# sources using the real Roslyn parser (not a text scan), re-parsing its own output to prove only trivia moved. `CommentStripper [--dry-run] <path>...`. |
| `InteropInspect/` (C#, net9.0, exe) | Reads a managed assembly's metadata and searches it: `InteropInspect <assembly.dll> <keyword>...` or `--type <FullName>` for a full listing of one type. |
| `recroom-mirror/` (Node.js ESM) | Local mirror/adapter for RecNet web content: `download.mjs` caches pages from `recroom.network`, `public-cache.mjs` serves the cached public endpoints, `radicade-adapter.mjs` proxies to a Radicade server (`RADICADE_WEB_SERVER`), and `serve.mjs` puts both behind one local HTTP server. |
## Client metadata patching (Python)
| Tool | What it does |
| --- | --- |
| `patch-0831-client-metadata.py` | Points a Rec Room `20230831` install at a Radicade server by rewriting the `rec.net` bootstrap URLs in the IL2CPP string table. |
| `patch-quest-client-metadata.py` | Same, for the unpacked Quest `20230907` client (accepts the Apktool-decoded APK tree). |
| `patch-quest-standalone-login.py` | Experimental Quest standalone login flow; needs the matching server platform guard. |
| `sep-literals.py` | Reads/inspects the il2cpp string-literal table of a `20230831` client (the metadata header is not the standard magic). |
| `sep-scan.py` | Locates metadata-usage tokens/pointers inside an il2cpp binary. |
| `sept-map.py` | Maps obfuscated Il2CppInterop names between two game builds. |
| `package-quest-obb.py` | Rebuilds an Android expansion OBB from an Apktool-decoded tree. |
| `diagnose-quest-tls.py` | Builds an unsigned, logging-only diagnostic APK that preserves certificate decisions. |
| `quest-disassemble.py` | Read-only ARM64 inspection with optional on-device method-map annotations. |
## Triage and analysis (PowerShell / Python)
| Tool | What it does |
| --- | --- |
| `august-client-triage.ps1` | Read-only triage of a patched August 2023 install; writes a report naming the missing piece of the stack. |
| `september-client-triage.ps1` | Read-only triage of a patched September 2023 install (same idea, `20230831`). |
| `client-exit-triage.ps1` | Separates a crash from an orderly exit using the Windows Application event log and the last Unity log. |
| `player-log-window.py` | Slices `Player.log` by wall-clock window and summarises it. |
| `make-august-client-pack.ps1` | Builds a shareable client bundle from a known-good August install, verifying every required file against a reference. |
| `check-obfuscation-safety.py` | Fails when Obfuscar renaming would break a by-name (Harmony/reflection/interop) lookup in the client plugin. |
## Environment repair
| Tool | What it does |
| --- | --- |
| `patch-rrs-nameserver.ps1` | Points the Rec Room Studio Unity editor at a Radicade server instead of Rec Room's nameserver. |
| `repair-unity-script-compiler.ps1` | Restores the Roslyn script compiler that Windows Defender quarantines out of the Unity package cache. |
| `reorganize-server-features.sh` | Moves server sources into feature folders without touching namespaces; `--plan` prints, `--apply` moves. |
Tooling that needs a game install takes the path as an argument or a documented
default; change the default rather than editing the script in place.
+30
View File
@@ -0,0 +1,30 @@
# VPS
Scripts for the host running the public server (a Windows VPS behind Caddy; see the
repo-level [`Caddyfile`](../Caddyfile), which terminates TLS for `ns.radicade.app` and
proxies to `127.0.0.1:3030`).
## `fix-dorm-blob.sh`
Repairs the "joining room" / dorm-load crash caused by a room save that references a
DataBlob missing from CDN storage. It has two modes:
```bash
# MODE 1 — data fix: upload a valid empty room blob through the admin API.
# Requires the server's BotSecret (the Radicade:AdminApiKey / bot secret).
BOT_SECRET='<secret>' bash VPS/fix-dorm-blob.sh
BOT_SECRET='<secret>' HOST=https://ns.radicade.app bash VPS/fix-dorm-blob.sh
# MODE 2 — durable code fix: deploy the RoomUtils self-heal on the host.
bash VPS/fix-dorm-blob.sh --deploy
```
Mode 1 POSTs the blob to `/admin/rooms/upload/datablob` and then verifies it via
`GET /room/<blob>`; HTTP 401 means a wrong secret, `000`/timeout means the backend is
down. Mode 2 pulls the branch, publishes the server, restarts the service and checks
`GET /ns`.
Notes: the secret is taken from `$BOT_SECRET` or `$1` and is never written to disk by
the script, so never commit it — pass it through the environment. The service restart
assumes a systemd-style unit; if the host restarts the server another way, change
`mode2` accordingly.