Compare commits

...

10 Commits

Author SHA1 Message Date
Alexa ba9c40f30a Merge pull request #20 from DorkSquadRR/fix/steamless-download-404
launcher: fix Steamless download 404
2026-06-20 00:00:01 +03:00
Alexa 9b31ffd76b launcher: fix Steamless download 404 (correct asset filename)
The 'Unlock Rec Room from Steam' step built the release URL as
Steamless.v3.1.0.5.zip, but the actual GitHub asset is named
Steamless.v3.1.0.5.-.by.atom0s.zip. Same tag, wrong filename, so
the download 404'd. Correct the asset name in ZipUrl.
2026-06-19 23:58:05 +03:00
Alexa a233ac94bc docs(photon): remove broken Photon dashboard image links (#15)
The four images/photon-*.png screenshots referenced in photon-setup.md never existed in the repo, so they rendered as broken images. Remove the references; the text walkthrough stands on its own.
2026-06-16 11:54:10 +03:00
Alexa 914852a107 fix(release): use -p: not /p: so Windows publish works (#14)
Git bash on the Windows runner mangles args starting with / (MSYS path conversion), turning /p:Version=... into p:Version=... so MSBuild saw multiple projects (MSB1008). Use -p: which is shell-safe on every runner.
2026-06-16 01:16:21 +03:00
Alexa d3ca1f9297 fix(cli): exit 0 on --help so CI smoke test passes (#13)
* fix(cli): exit 0 on --help, handle parse errors cleanly

--help printed usage but returned exit code 1, failing the CI smoke test. Treat --help / -h / no-args as a successful usage print (exit 0), and catch parser ArgumentExceptions so a missing value or bad --mode exits 1 with a message instead of an unhandled crash.

* fix(cli): declare RuntimeIdentifiers so no-restore publish works

CI restores without a RID then publishes per-RID with no-restore, which failed NETSDK1047 because the assets file had no RID targets. Declaring RuntimeIdentifiers makes the RID-less restore cover all of them.
2026-06-16 01:04:45 +03:00
Alexa 75d187acf8 Merge pull request #12 from DorkSquadRR/docs-vr-mobile-support
Docs refresh: README intro, VR/mobile support, antivirus FAQ
2026-06-16 00:37:02 +03:00
Alexa e1fc786ac1 docs: add .backups to .gitignore 2026-06-16 00:35:46 +03:00
Alexa 8f7fc09266 docs(faq): explain why no antivirus exceptions are needed
Add an FAQ entry contrasting DorkNet with closed-source private-server
tools that ask users to disable antivirus: DorkNet is fully open source
and nothing is obfuscated, so there's nothing hidden for a scanner to flag
and no reason to weaken protection to run it.
2026-06-16 00:31:00 +03:00
Alexa e3fb9477b1 docs: add intro, mark VR/mobile supported, drop Junior mention
Add a short plain-language intro at the top of the README explaining what
DorkNet is. Mark VR and Mobile as supported in the feature table, and
remove the Junior accounts row.
2026-06-16 00:27:24 +03:00
Alexa d1b75aba57 Merge pull request #7 from DorkSquadRR/docs-main-refresh
Refresh main docs
2026-06-16 00:03:10 +03:00
8 changed files with 83 additions and 51 deletions
+4 -4
View File
@@ -126,10 +126,10 @@ jobs:
-c Release \
-r "${{ matrix.rid }}" \
--self-contained true \
/p:Version="$v" \
/p:AssemblyVersion="${v}.0" \
/p:FileVersion="${v}.0" \
/p:InformationalVersion="$v"
-p:Version="$v" \
-p:AssemblyVersion="${v}.0" \
-p:FileVersion="${v}.0" \
-p:InformationalVersion="$v"
- name: Package
shell: bash
+1 -2
View File
@@ -23,7 +23,7 @@ appsettings.Development.json
.env
.env.local
.env.*.local
.backups
# Runtime data
data/*.db
data/*.db-shm
@@ -68,4 +68,3 @@ Thumbs.db
# Test outputs
TestResults/
*.coverage
+8 -2
View File
@@ -1,5 +1,11 @@
# DorkNet
DorkNet lets you run your own private server for old versions of Rec Room.
It brings back the 2020-era game — logging in, hanging out in your dorm,
matchmaking, chatting with friends, building rooms — all on a server you
host yourself. You supply your own legally-owned copy of Rec Room, and
DorkNet handles the rest: the server, the client patcher, and the setup
tools to get you playing again.
> ⚠️ **Not affiliated with Rec Room Inc. or Against Gravity.**
> See [DISCLAIMER.md](DISCLAIMER.md). DorkNet ships no Rec Room game assets
@@ -102,8 +108,8 @@ branch's `BRANCHES.md` row for the exact deltas.
| Store catalog + gifting | ✅ |
| Game invites | ✅ |
| Image upload (polaroids, room thumbnails) | ✅ |
| VR (Quest/Index/etc.) | ⚠️ Photon-dependent; works in dev, untested at scale |
| Mobile / Junior accounts | ⚠️ Partial — Junior chat-restrictions disabled by default in Easy mode |
| VR (Quest/Index/etc.) | ✅ |
| Mobile | ✅ |
| Voice chat | ❌ Routes through Photon Voice; needs separate Photon Voice AppId |
| Cross-server federation | ❌ Out of scope |
@@ -6,6 +6,10 @@
alongside Windows. The shared Backend classes are written to
OperatingSystem.IsWindows()-gate any Windows-only paths. -->
<TargetFramework>net9.0</TargetFramework>
<!-- Declared so a RID-less restore produces assets for every target the
CI matrix / release pipeline later publishes with no-restore. Without
this, RID-specific publish fails with NETSDK1047. -->
<RuntimeIdentifiers>win-x64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>DorkNet.ServerCli</RootNamespace>
+43 -34
View File
@@ -14,8 +14,15 @@ public static class Program
{
public static async Task<int> Main(string[] args)
{
// --help / -h (and a bare invocation) print usage and exit cleanly.
if (args.Length == 0 || args.Contains("--help") || args.Contains("-h"))
{
PrintHelp();
return 0;
}
var parsed = ParseArgs(args);
if (parsed is null) return 1; // ParseArgs already wrote --help or an error.
if (parsed is null) return 1; // ParseArgs already wrote the error.
// Validate required values up front so the user sees the
// failure before any download / process spin-up.
@@ -216,50 +223,52 @@ public static class Program
private static ParsedArgs? ParseArgs(string[] args)
{
if (args.Length == 0 || args.Contains("--help") || args.Contains("-h"))
{
PrintHelp();
return null;
}
string photon = "", voice = "", region = "us";
string mode = "localtunnel", apex = "", name = "DorkNet Server";
string versionKey = "march_2020_03_10";
string? serverDir = null;
for (int i = 0; i < args.Length; i++)
try
{
string Next()
for (int i = 0; i < args.Length; i++)
{
if (i + 1 >= args.Length)
throw new ArgumentException($"missing value for {args[i]}");
return args[++i];
string Next()
{
if (i + 1 >= args.Length)
throw new ArgumentException($"missing value for {args[i]}");
return args[++i];
}
switch (args[i])
{
case "--photon-id": photon = Next(); break;
case "--voice-id": voice = Next(); break;
case "--region": region = Next(); break;
case "--mode": mode = Next(); break;
case "--apex": apex = Next(); break;
case "--name": name = Next(); break;
case "--version": versionKey = Next(); break;
case "--server-dir": serverDir = Next(); break;
default:
Console.Error.WriteLine($"error: unknown arg '{args[i]}' (try --help)");
return null;
}
}
switch (args[i])
HostingMode parsedMode = mode.ToLowerInvariant() switch
{
case "--photon-id": photon = Next(); break;
case "--voice-id": voice = Next(); break;
case "--region": region = Next(); break;
case "--mode": mode = Next(); break;
case "--apex": apex = Next(); break;
case "--name": name = Next(); break;
case "--version": versionKey = Next(); break;
case "--server-dir": serverDir = Next(); break;
default:
Console.Error.WriteLine($"error: unknown arg '{args[i]}' (try --help)");
return null;
}
"localtunnel" or "lt" or "internet" or "tunnel" => HostingMode.SingleOriginTunnel,
"wildcard" or "remote" or "tunnelto" => HostingMode.RemoteWildcard,
"lan" or "local" or "wifi" => HostingMode.LocalNetwork,
_ => throw new ArgumentException($"unknown --mode '{mode}' (try localtunnel, wildcard, lan)"),
};
return new ParsedArgs(photon, voice, region, parsedMode, apex, name, versionKey, serverDir);
}
HostingMode parsedMode = mode.ToLowerInvariant() switch
catch (ArgumentException ex)
{
"localtunnel" or "lt" or "internet" or "tunnel" => HostingMode.SingleOriginTunnel,
"wildcard" or "remote" or "tunnelto" => HostingMode.RemoteWildcard,
"lan" or "local" or "wifi" => HostingMode.LocalNetwork,
_ => throw new ArgumentException($"unknown --mode '{mode}' (try localtunnel, wildcard, lan)"),
};
return new ParsedArgs(photon, voice, region, parsedMode, apex, name, versionKey, serverDir);
Console.Error.WriteLine($"error: {ex.Message} (try --help)");
return null;
}
}
private static void PrintHelp()
+19
View File
@@ -10,6 +10,25 @@ modified game files anywhere.
DorkNet's authors don't ship Rec Room IP and don't help users obtain it.
See [DISCLAIMER.md](../DISCLAIMER.md) for the full position.
### Do I need to disable my antivirus?
No, and you shouldn't have to. A lot of closed-source private-server tools
ask you to turn your antivirus off or add exclusions before running them.
That's usually because they ship obfuscated or packed binaries — code
that's been deliberately scrambled so you can't see what it does, which
also happens to trip antivirus heuristics. You're being asked to lower
your guard for something you can't inspect.
DorkNet is the opposite. Everything is open source and nothing is
obfuscated — the server, the launcher, and the patcher are all right here
in the repo for anyone to read, and you can build them yourself instead of
trusting our prebuilt releases. There's nothing hidden for a scanner to
choke on, so there's no reason to weaken your protection to run it.
If a release binary ever does get flagged, that's a false positive on an
unsigned indie executable, not malware — and you always have the option to
build from source and verify it yourself.
### Will Rec Room Inc. shut this down?
Possibly. Fan-server projects exist in a grey zone. AGPL doesn't shield
-8
View File
@@ -29,8 +29,6 @@ Go to **[dashboard.photonengine.com](https://dashboard.photonengine.com/)**
and click "Sign up". Email + password; the free tier doesn't ask for a
card.
![photon dashboard signup screen](images/photon-1-signup.png)
> If you already have an account from another project, log in instead.
> Multiple DorkNet servers can share the same Photon account, but each
> server needs its own AppId pair so concurrent player counts don't
@@ -49,15 +47,11 @@ for:
Click **CREATE**.
![photon "Create a new app" form, Photon SDK selected](images/photon-2-create-realtime.png)
## Step 3 — Copy the Realtime AppId
You land back on the dashboard with your new app at the top. The AppId
is the long string under the app name — click it to copy.
![photon app card with AppId highlighted](images/photon-3-realtime-appid.png)
That's your **Realtime AppId**. Paste it into:
- the launcher's first-run wizard step 4, **REALTIME APPID** field, OR
@@ -69,8 +63,6 @@ That's your **Realtime AppId**. Paste it into:
If you want in-game voice chat, repeat Step 2 with **Photon Voice**
selected instead of Realtime. Same flow.
![photon "Create a new app" form, Voice selected](images/photon-4-create-voice.png)
Copy the Voice AppId from the dashboard the same way as Step 3 and
paste it into:
+4 -1
View File
@@ -22,9 +22,12 @@ namespace DorkNet.Launcher.Backend;
public static class SteamlessInstaller
{
private const string PinnedVersion = "v3.1.0.5";
// Upstream names the asset "Steamless.{ver}.-.by.atom0s.zip" — NOT
// "Steamless.{ver}.zip". Getting this wrong is a 404 at the
// "Unlock Rec Room from Steam" step.
private const string ZipUrl =
"https://github.com/atom0s/Steamless/releases/download/" +
PinnedVersion + "/Steamless." + PinnedVersion + ".zip";
PinnedVersion + "/Steamless." + PinnedVersion + ".-.by.atom0s.zip";
private static readonly HttpClient Http = new()
{