main: branch-aware README + BRANCHES.md + versions.json

Rewrites main as a docs-only landing branch. Adds:
- BRANCHES.md — per-branch chart (client build, status, notes)
- versions.json — machine-readable manifest the Easy launcher reads
- Branch-picking step + Easy-app/Docker URLs updated in README +
  docs/advanced-setup.md

Drops the per-folder README stubs (server/, admin-ui/, client-mod/,
docker/, easy-app/, tools/) — the actual code lives on per-version
branches now, not on main.
This commit is contained in:
Alexa
2026-05-26 01:17:14 +03:00
parent dc1e5436b5
commit d1cc50622b
11 changed files with 178 additions and 332 deletions
+62
View File
@@ -0,0 +1,62 @@
# Branches
DorkNet maintains a long-lived branch per supported Rec Room client
build. Each branch is an independent fork of the server + client patcher
tuned to that build's wire protocol. Pick the one matching your install.
## Active branches
### `december-2020-12-18`
- **Client build:** Rec Room 2020.12.18
- **Status:** active
- **Notes:**
- Single EF Initial migration; SQLite + Postgres both work out of the
box.
- Includes the chat-threads, clubs, playlists, weekly-challenge, and
room-keys subsystems added late-2020.
- Server's `Versions/Late2020VersionPlugin` is the active version
plugin; client header `X-DorkNet-Version: december_2020_12_18`.
### `march-2020-03-10`
- **Client build:** Rec Room 2020.03.10
- **Status:** pending import
- **Notes:**
- Earlier wire shape — no clubs, no playlists, simpler store catalog.
- Diverges from `december-2020-12-18` by ~170 files; cannot be
unified with the plugin abstraction alone.
Setup for either is the same — see [docs/advanced-setup.md](docs/advanced-setup.md)
(starts with a "pick your branch" step).
## How to pick
If you don't know which Rec Room build you have, check:
- **Steam**: right-click *Rec Room* → Properties → Local files →
Browse → look at the `Recroom_Release_Data/StreamingAssets/version.txt`
if present, or note the install timestamp.
- **Manual install** (the typical DorkNet setup path): the build is in
the folder name (`RecRoom-2020.12.18`, `RecRoom-2020.03.10`, etc.).
- **Easy launcher**: auto-detects the build and picks the branch.
## Machine-readable manifest
[`versions.json`](versions.json) carries the same information in a
format the Easy launcher and install scripts can consume directly. Add
new versions there too when a new branch lands.
## Adding a new version branch
1. Land the server code on a new orphan branch named `<month>-<build>`
(e.g. `august-2021-08-04`).
2. Add a row to the active-branches list above.
3. Add the matching entry to `versions.json`.
4. Add a `docs/<month>-setup.md` setup guide.
5. Tag a release on the new branch so the Easy launcher's
release-fetcher picks it up.
Branches are intentionally long-lived — once a build is supported, its
branch keeps getting patches against the same wire protocol. Don't
rebase across branches; cherry-pick when a fix applies to multiple.
+54 -22
View File
@@ -1,38 +1,65 @@
# DorkNet
A self-hostable reimplementation of the 2020 Rec Room backend. Bring your own
client; run a private server for yourself and your friends.
A self-hostable reimplementation of the 2020 Rec Room backend. Bring your
own client; run a private server for yourself and your friends.
> ⚠️ **Not affiliated with Rec Room Inc. or Against Gravity.**
> See [DISCLAIMER.md](DISCLAIMER.md). DorkNet ships no Rec Room game assets or
> modified binaries — you supply your own legally-acquired Rec Room 2020.12.18
> See [DISCLAIMER.md](DISCLAIMER.md). DorkNet ships no Rec Room game assets
> or modified binaries — you supply your own legally-acquired Rec Room
> install.
---
## Pick your client version
DorkNet maintains a separate branch for each Rec Room client build it
supports. The server, client patcher, and seed data on each branch are
tuned to that build's wire protocol.
| Client build | Branch | Status |
|---|---|---|
| **Rec Room 2020.12.18** (December) | [`december-2020-12-18`](../../tree/december-2020-12-18) | Active |
| **Rec Room 2020.03.10** (March) | [`march-2020-03-10`](../../tree/march-2020-03-10) | Pending import |
See [BRANCHES.md](BRANCHES.md) for the full per-branch breakdown
(supported features, schema notes, plugin compatibility). Programs that
need the mapping in machine-readable form (the Easy launcher, install
scripts) read it from [versions.json](versions.json).
This `main` branch is **docs-only** — it carries the project README, the
manifest the launcher reads, the per-version setup guides, and the Easy
app source. All actual server / patcher code lives on the per-version
branches above.
---
## Two ways to run it
### 🎮 Easy mode — desktop app
One download. Double-click. Choose "host" or "join" on first launch.
One download. Pick a client version on first launch. Hosts can switch
between supported builds without re-installing the launcher.
- **Host a server** for you and your friends — runs a local server + tunnel,
patches your Rec Room install, and gives you a shareable join code.
- **Join a server** someone shared with you — paste the code, point at your
Rec Room install, hit play.
- **Host a server** — runs a local server + Cloudflare tunnel for the
client version you choose, patches your Rec Room install, and gives
you a shareable join code.
- **Join a server** — paste the code, point at your Rec Room install,
hit play. The launcher fetches the matching client patcher for the
host's server version.
→ **[Easy setup guide](docs/easy-setup.md)** — screenshots, takes 5 minutes.
→ **[Easy setup guide](docs/easy-setup.md)** — screenshots, ~5 minutes.
[Download the latest Easy app →](https://github.com/YOUR_GH_USERNAME/dorknet/releases/latest)
[Download the latest Easy app →](https://github.com/DorkSquadRR/DorkNet/releases/latest)
### 🛠️ Advanced mode — Docker
### 🛠️ Advanced mode — Docker / source
For people running a community server, doing custom modding, or contributing
back. Postgres + Redis + the ASP.NET Core server behind an nginx reverse proxy.
For community-server hosts, modders, and contributors. Pick the branch
matching your client build, clone, run.
```bash
git clone https://github.com/YOUR_GH_USERNAME/dorknet
cd dorknet/docker
# Example: hosting for December 2020.12.18 clients
git clone --branch december-2020-12-18 https://github.com/DorkSquadRR/DorkNet
cd DorkNet/docker
cp .env.example .env # fill in 2-3 values
docker compose up -d
```
@@ -43,6 +70,9 @@ docker compose up -d
## What works / what doesn't
Feature set varies per branch. The table below is the union — see each
branch's `BRANCHES.md` row for the exact deltas.
| Feature | Status |
| -------------------------------- | ------ |
| Account creation + login | ✅ |
@@ -69,16 +99,18 @@ docker compose up -d
- **Code**: [AGPL-3.0](LICENSE). Hosted forks must publish their source.
- **"Rec Room"** is a trademark of Rec Room Inc. See [DISCLAIMER.md](DISCLAIMER.md).
- DorkNet is a clean-room reimplementation of the 2020 backend protocol for
educational and personal use.
- DorkNet is a clean-room reimplementation of the 2020 backend protocol
for educational and personal use.
---
## Docs
- [Easy setup](docs/easy-setup.md)
- [Advanced setup](docs/advanced-setup.md)
- [Joining a server](docs/joining-a-server.md)
- [Architecture](docs/architecture.md)
- [Branch chart](BRANCHES.md) — which branch matches your client
- [Easy setup](docs/easy-setup.md) — desktop-launcher path
- [Advanced setup](docs/advanced-setup.md) — Docker / VPS path
- [Joining a server](docs/joining-a-server.md) — for players
- [Architecture](docs/architecture.md) — how the code is laid out
- [FAQ](docs/faq.md)
- [Troubleshooting](docs/troubleshooting.md)
- [Contributing](CONTRIBUTING.md)
-36
View File
@@ -1,36 +0,0 @@
# admin-ui/
React + Vite + Tailwind SPA. Talks to `/api/admin/v1/*` on the server.
Embedded into:
1. The standalone server's `wwwroot/admin/` (advanced mode), served at
`https://admin.<your-domain>/`.
2. The Easy desktop app via a Photino WebView (host mode admin tab).
## Dev
```bash
npm install
npm run dev # http://localhost:5173, proxies /api → :5000
```
Start the server first; Vite's proxy doesn't synthesize endpoints.
## Build
```bash
npm run build # dist/ — copied into server/wwwroot/admin by the
# server's CI publish step, and into easy-app/Resources/
# by tools/build-easy-app.ps1
```
## Stack notes
- React 18 + Vite 5 + TypeScript
- Tailwind 3 with a custom dark `ink/brand` palette in `tailwind.config.js`
- React Router 6
- No external component library; primitives in `src/components/`
- No state library beyond per-page `useState` + `useApi`
See [docs/architecture.md](../docs/architecture.md) for how the SPA is
delivered in both modes.
-57
View File
@@ -1,57 +0,0 @@
# client-mod/
MelonLoader 0.6.x mod that retargets the 2020 Rec Room client at a
DorkNet server. Compiles to `DorkNet.ClientMod.dll`, which the patcher
drops into the user's `Recroom_Release/Mods/` folder.
## What it does
Harmony patches applied at boot:
- **`Uri ctor`** — rewrites every `.rec.net` URL to your configured
server host. Catches every hardcoded API endpoint the watch ships with.
- **`PhotonNetwork.ConnectUsingSettings`** — overrides the baked-in
Photon Cloud AppId with yours.
- **`NetworkingPeer.CallAuthenticate`** — injects `userid` + `LoginLock`
into Photon's CustomAuth so your server can identify the player.
- **`BouncyCastle.Tls.*NotifyServerCertificate`** — bypasses TLS chain
validation. The 2020 client only trusts a baked-in cert set; we replace
the verifier so any cert from your server is accepted. (Mitigated by
also force-routing only to your configured host.)
- **`PlayerEmotes.RemoveInvalidCharactersFromMessage`** — skips the
TMP font-validation step that NREs when the font asset isn't loaded
yet (private servers don't always have it cached at chat-send time).
- **`AccountExtensions.CanLocalPlayerChat`** — forces chat-enabled for
Junior / restricted accounts (single-tenant private server, no chat
moderation needed).
See `Mod.cs` for the full patch list with citations to the Cpp2IL
disassembly that justifies each one.
## Config
The mod reads `MelonLoader/UserData/dorknet-clientmod.json`:
```json
{
"ServerHost": "abc-def.trycloudflare.com",
"PhotonAppId": "your-photon-realtime-appid",
"PhotonCloudRegion": "eu",
"InjectAuthValues": true,
"EnableTlsTrustBypass": true
}
```
The patcher (desktop app and CLI) writes this file as part of the patch
flow — users don't normally edit it by hand.
## Building
```bash
dotnet build -c Release
# → bin/Release/DorkNet.ClientMod.dll
```
Requires Il2Cpp interop assemblies from the user's MelonLoader install.
Path defaults to `dist/RecRoom-Clean-2020.03.10/MelonLoader/`; override
with `-p:MelonLoaderDir=<path>`.
-22
View File
@@ -1,22 +0,0 @@
# docker/
The Docker Compose stack for advanced mode. See
[docs/advanced-setup.md](../docs/advanced-setup.md) for the full
walkthrough.
```
docker/
├── docker-compose.yml Postgres + Redis + server + nginx
├── docker-compose.cloudflared.yml Optional: replace nginx with CF Tunnel
├── Dockerfile.server Multi-stage: SDK build → admin-ui build → runtime
├── nginx.conf Subdomain routing for *.your-domain
└── .env.example Required environment variables
```
Quick start:
```bash
cp .env.example .env
$EDITOR .env
docker compose up -d
```
+9 -8
View File
@@ -1,10 +1,11 @@
# DorkNet docs
| Doc | For who |
| -------------------------------------- | ---------------------------------------------------- |
| [easy-setup.md](easy-setup.md) | Hosts who want the desktop-app one-click experience |
| [advanced-setup.md](advanced-setup.md) | Hosts running a community server on a VPS |
| [joining-a-server.md](joining-a-server.md) | Players whose friend gave them a join code |
| [architecture.md](architecture.md) | Anyone hacking on the code |
| [faq.md](faq.md) | Common questions before you ask in issues |
| [troubleshooting.md](troubleshooting.md) | Known failure modes + fixes |
| Doc | For who |
| ---------------------------------------------- | ------------------------------------------------------ |
| [../BRANCHES.md](../BRANCHES.md) | Anyone picking which branch matches their Rec Room build |
| [easy-setup.md](easy-setup.md) | Hosts who want the desktop-app one-click experience |
| [advanced-setup.md](advanced-setup.md) | Hosts running a community server on Docker / a VPS |
| [joining-a-server.md](joining-a-server.md) | Players whose friend gave them a join code |
| [architecture.md](architecture.md) | Contributors hacking on the code |
| [faq.md](faq.md) | Common questions before you ask in issues |
| [troubleshooting.md](troubleshooting.md) | Known failure modes + fixes |
+30 -8
View File
@@ -29,9 +29,22 @@ Tunnel) this should comfortably run 50+ concurrent players on a $20/mo VPS.
## Setup
### 1. Pick the branch matching your client build
DorkNet keeps one branch per supported Rec Room build. See
[`../BRANCHES.md`](../BRANCHES.md) for the full chart. Quick map:
| Your Rec Room install | Branch to clone |
|---|---|
| 2020.12.18 (most common DorkNet target) | `december-2020-12-18` |
| 2020.03.10 (or 2020.03.06) | `march-2020-03-10` |
### 2. Clone + configure
```bash
git clone https://github.com/YOUR_GH_USERNAME/dorknet
cd dorknet/docker
# Replace the branch in --branch with the row that matched above.
git clone --branch december-2020-12-18 https://github.com/DorkSquadRR/DorkNet
cd DorkNet/docker
cp .env.example .env
$EDITOR .env # fill in the values noted below
@@ -93,13 +106,15 @@ server is ready at `https://api.your-server.example.com/healthz`.
Same patcher as Easy mode, but you'll run it from the command line:
```powershell
.\tools\patch-client.ps1 `
-RecRoomDir "C:\path\to\Recroom_Release" `
-ServerHost "your-server.example.com" `
-PhotonAppId "your-photon-realtime-appid" `
-PhotonRegion "eu"
.\tools\install-plugin.ps1 `
-RecRoomPath "C:\path\to\Recroom_Release_Data" `
-PhotonAppId "<your-photon-realtime-app-id>" `
-PhotonVoiceAppId "<your-photon-voice-app-id>"
```
The installer drops the DorkNet BepInEx plugin into the client's
`BepInEx/plugins/` and writes its config under `BepInEx/config/`.
## Admin UI
`https://admin.your-server.example.com` — log in with the first account
@@ -119,7 +134,7 @@ docker compose exec postgres pg_dump -U dorknet dorknet > backup.sql
## Updating
```bash
cd dorknet
cd DorkNet
git pull
docker compose pull
docker compose up -d
@@ -127,3 +142,10 @@ docker compose up -d
The server runs all idempotent migrations on boot, so version upgrades
are zero-downtime as long as the schema changes are additive.
> ⚠️ `git pull` only fetches updates for **your current branch**.
> DorkNet branches are independent — updates on `december-2020-12-18`
> don't flow to `march-2020-03-10` and vice versa. If you've checked
> out the wrong branch for your client, switching is a fresh
> `git clone --branch ...` (the schema and Photon AppId requirements
> differ).
-112
View File
@@ -1,112 +0,0 @@
# DorkNet Easy App
The unified desktop app for hosts and guests. One binary, two modes.
## Project layout
```
easy-app/
├── Shell/ PhotinoNET window host, mode router, settings store,
│ auto-updater, system tray, log viewer.
├── HostMode/ Tunnel manager (cloudflared wrapper), server lifecycle
│ (start/stop the in-process ASP.NET Core), share-code
│ generation.
├── JoinMode/ Join-code parser (dorknet:// URL handler), connection
│ sanity-check, server reachability ping.
├── Shared/ Patcher library (port of tools/patch-client.ps1 to C#),
│ ConfigManager, RecRoomInstallFinder (Steam library scan),
│ ImageSigningKeyManager (auto-generate on first run).
└── Resources/ Icons, admin-ui dist (bundled at build time),
cloudflared.exe, MelonLoader/, mod DLLs.
```
## Build flow
`Resources/admin-ui-dist/` is the production build output from
`../admin-ui/` — copied in by a pre-build task so the Photino webview can
serve it as the host-mode admin tab.
```pwsh
# One-shot dev build
pwsh tools/build-easy-app.ps1
# Release artifact
dotnet publish easy-app -c Release -r win-x64 --self-contained \
-p:PublishSingleFile=true -p:PublishTrimmed=false
# → bin/Release/net9.0/win-x64/publish/dorknet.exe (~80 MB)
```
## Why PhotinoNET
- The admin UI is already a webview-friendly React SPA. Embedding it in a
Photino window is essentially free.
- Single .NET project. No Node toolchain in the desktop build, no Electron.
- Bundled binary ~50 MB before the runtime, ~80 MB with self-contained
.NET. Acceptable for one-time downloads.
## Why not Electron / Tauri / Avalonia
- **Electron**: doubles the binary size, adds Node into the supply chain.
- **Tauri**: Rust dependency we don't otherwise need; mixing it with the
existing .NET server complicates the build matrix.
- **Avalonia**: native, beautiful, but means re-implementing the admin
UI a second time. The point of unified Host mode is *reuse* the admin
SPA verbatim.
## Modes — first-run decision
`Shared/ConfigManager` writes `%APPDATA%\DorkNet\mode.json`:
```json
{ "mode": "host" }
```
`Shell` reads this on startup. Missing or `null` → first-run wizard.
Settings → "Switch mode" sets `mode` to the other value, restarts the
process clean (Photino re-init).
## Host mode lifecycle
1. User clicks Start server.
2. `HostMode.ServerLauncher` boots the ASP.NET Core host in-process,
wired to a SQLite DB at `%APPDATA%\DorkNet\dorknet.db`.
3. `HostMode.TunnelManager` spawns `cloudflared tunnel --url
http://localhost:5000`, reads the public URL off stderr.
4. UI surfaces the URL + a "Copy join code" button. Join code is
base64(`{host, photonAppId, photonRegion, name}`).
## Join mode lifecycle
1. User pastes a join code (or clicks a `dorknet://` URL — the installer
registers the protocol handler).
2. `JoinMode.CodeParser` decodes, ping-checks the host, shows a
"Connecting to X" preview.
3. User points at their Rec Room install (auto-detected via
`RecRoomInstallFinder` if Steam owns it).
4. `Shared.Patcher` patches `global-metadata.dat`, drops MelonLoader,
writes `dorknet-clientmod.json` with the decoded host + Photon AppId.
5. UI offers a "Launch Rec Room" button — runs `Recroom_Release.exe`
directly, no Steam intermediary needed.
## Auto-updates
[Velopack](https://velopack.io) is the path of least resistance for .NET
desktop. Drop-in: declare a GitHub Release feed, ship updates as deltas.
## Testing
QA matrix to maintain:
- Fresh Windows 10 VM, no Rec Room → install Steam → buy / depot-download
the 2020 build → DorkNet host mode → patch + start + tunnel → connect
from a second VM via Join mode. End-to-end smoke test.
- Mac M1 + Linux: deferred. PhotinoNET supports them but we need separate
cloudflared binaries and a packaging step per OS.
## Open questions
- [ ] Code-signing cert. SmartScreen warning is a major adoption friction.
EV cert is ~$200/yr; standard cert is cheaper but takes longer to build
reputation.
- [ ] Crash reporting. Sentry has a generous free tier and a clean .NET SDK.
- [ ] Telemetry — opt-in? Off by default? Right now: no plans, but
document the position so contributors know.
-57
View File
@@ -1,57 +0,0 @@
# server/
The ASP.NET Core backend.
Built two ways:
- **Standalone Postgres-backed** for advanced mode (Docker), via
`dotnet run` or the `dorknet-server` container.
- **In-process SQLite-backed** for the Easy desktop app, hosted as a
library inside `easy-app/`.
## Code layout (TBC)
```
server/
├── Controllers/ HTTP endpoints, sliced by subdomain → service
├── Services/ Business logic (presence, notifications, levels, ...)
├── Hubs/ SignalR NotifyHub
├── Data/ DbContext + EntityFramework entity classes
├── Auth/ JWT issuance, Photon CustomAuth handler
├── Middleware/ SubdomainRouter, request logging, error handling
└── Program.cs Boot: migrations, seeds, canonical overrides, DI
```
## Building
```bash
dotnet build -c Release
dotnet run # localhost:5000
```
## Provider switch
The DbContext is provider-agnostic. `appsettings` picks one:
```jsonc
{
"ConnectionStrings": {
// Postgres for advanced mode
"Default": "Host=localhost;Database=dorknet;Username=dorknet;Password=..."
// OR SQLite for easy mode
// "Default": "Data Source=dorknet.db"
},
"Database": {
"Provider": "Postgres" // or "Sqlite"
}
}
```
Easy app boots with `Provider=Sqlite` baked in; standalone defaults to
`Provider=Postgres`.
## See also
- [docs/architecture.md](../docs/architecture.md) — request flow,
subdomain routing, Photon relationship
- [docs/advanced-setup.md](../docs/advanced-setup.md) — production setup
- [CONTRIBUTING.md](../CONTRIBUTING.md) — style + PR rules
-10
View File
@@ -1,10 +0,0 @@
# tools/
CLI helpers. Most users don't need to touch these — the desktop app
wraps the same logic with a UI.
| Script | Purpose |
| -------------------- | ------------------------------------------------------ |
| `patch-client.ps1` | Patch a Rec Room install to talk to your DorkNet server. The desktop app wraps this in a UI; CLI path is for advanced-mode hosts. |
| `dump-il2cpp.ps1` | Run Cpp2IL against a Rec Room install to produce the decompiled dumps the project uses for reverse-engineering. Output stays on your machine — never committed. |
| `build-easy-app.ps1` | Build the unified desktop app (`dorknet.exe`). Self-contained .NET single-file publish. |
+23
View File
@@ -0,0 +1,23 @@
{
"$schema_version": 1,
"$comment": "Branch-to-client-build manifest. The Easy launcher and install scripts read this to map a detected Rec Room install to the right DorkNet branch + release. When adding a branch, append here AND to BRANCHES.md.",
"branches": [
{
"branch": "december-2020-12-18",
"client_build": "2020.12.18",
"alt_builds": [],
"version_key": "december_2020_12_18",
"release_tag_prefix": "v1-december",
"supported": true
},
{
"branch": "march-2020-03-10",
"client_build": "2020.03.10",
"alt_builds": ["2020.03.06"],
"version_key": "march_2020_03_10",
"release_tag_prefix": "v1-march",
"supported": false,
"supported_note": "branch import pending"
}
]
}