4.7 KiB
Release artifact contract
The launcher on main reads
/versions.json to find every supported per-version
branch, then fetches release files from each branch's GitHub
Releases.
Per-version branches need releases that follow this contract. If the assets are missing or named differently, users will see "no release found" or "manifest missing" when they host or join.
Tag naming
A release's tag must start with the release_tag_prefix declared for
the branch in versions.json. Recommended scheme:
v1-{month}-{YYYY.MM.DD}
Examples (matching the current release_tag_prefix values):
| Branch | release_tag_prefix |
Example full tag |
|---|---|---|
december-2020-12-18 |
v1-december |
v1-december-2026.06.15 |
march-2020-03-10 |
v1-march |
v1-march-2026.06.15 |
The launcher picks the most-recent release (by published_at) whose
tag starts with the prefix, then looks for the two asset names below.
Required assets
1. dorknet-server-{version_key}-win-x64.zip
A self-contained .NET 9 publish of DorkNet.Server for win-x64.
The launcher unpacks this and spawns the executable directly.
Build with:
cd DorkNet.Server
dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true
cd bin/Release/net9.0/win-x64/publish
Compress-Archive -Path * -DestinationPath ../../../../../dorknet-server-{version_key}-win-x64.zip
The zip's root must contain DorkNet.Server.exe (or any .exe; the
launcher scans for it).
2. dorknet-clientpatch-{version_key}.zip
The MelonLoader-based client patcher, packed into a single zip with a manifest.json at the zip root telling the launcher what to do. The launcher performs every step in C# — no PowerShell scripts run.
Required layout inside the zip:
manifest.json (described below)
MelonLoader.zip (optional — the MelonLoader install tree)
DorkNet.ClientMod.dll (required — the DorkNet MelonLoader plugin)
dorknet-clientmod.json.template (optional — UserData config template)
manifest.json schema (v1):
{
"$schema_version": 1,
"loader_archive": "MelonLoader.zip",
"plugin_dll": "DorkNet.ClientMod.dll",
"plugin_dest": "MelonLoader/Mods",
"config_template": "dorknet-clientmod.json.template",
"config_dest": "MelonLoader/UserData/dorknet-clientmod.json",
"old_plugin_paths": [
"BepInEx/plugins/DorkNet.ClientPatch.dll"
]
}
All fields except $schema_version and plugin_dll are optional.
Defaults:
| Field | Default |
|---|---|
plugin_dest |
MelonLoader/Mods |
config_dest |
MelonLoader/UserData/dorknet-clientmod.json |
loader_archive |
(none — assumes user has MelonLoader installed) |
config_template |
(none — no config written) |
config_template placeholders rendered before write:
| Placeholder | Source |
|---|---|
{HOST} |
Host's tunnel hostname (or join code's host field) |
{PHOTON_APPID} |
Host's Photon Realtime AppId |
{PHOTON_VOICE_APPID} |
Host's Photon Voice AppId (falls back to Realtime if empty) |
{PHOTON_REGION} |
Photon Cloud region (us/eu/asia/jp/sa/kr/in/au); defaults to us |
Example template:
{
"ServerHost": "{HOST}",
"PhotonAppId": "{PHOTON_APPID}",
"PhotonVoiceAppId": "{PHOTON_VOICE_APPID}"
}
What the launcher does on Apply
Given the manifest above, the launcher does (in this order):
- Extracts
loader_archiveover the user's Rec Room install root (the parent ofRecroom_Release_Data). MelonLoader'sversion.dllandMelonLoader/tree land in the right places. - Deletes any
old_plugin_paths(cleans up an old BepInEx-era DLL, a previous plugin filename, etc.). - Copies
plugin_dllto<recroom-root>/<plugin_dest>/. - Renders
config_template(placeholder substitution) and writes to<recroom-root>/<config_dest>.
No PowerShell, no separate Steamless invocation, no byte-level metadata patching in v1 — keep the patcher zip declarative. Future schema versions can add fields for those without breaking older launchers (they ignore unknown fields).
Verifying a release before publishing
$tag = "v1-december-2026.06.15"
gh release view $tag --repo DorkSquadRR/DorkNet
gh release download $tag --repo DorkSquadRR/DorkNet `
--pattern "dorknet-server-december_2020_12_18-win-x64.zip" `
--pattern "dorknet-clientpatch-december_2020_12_18.zip"
Then unzip + inspect: the patcher zip should have manifest.json at
root, the named DLL should exist, the config_template (if listed)
should exist, etc.
Future: GitHub Actions workflow
Each per-version branch should land a .github/workflows/release.yml
that builds + packages the artifacts on tag push. Not yet implemented;
releases are manual for now.