Compare commits

...

3 Commits

Author SHA1 Message Date
Alexa f2b3f66aec docs(photon): remove broken Photon dashboard image links
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:00 +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
4 changed files with 51 additions and 46 deletions
+4 -4
View File
@@ -126,10 +126,10 @@ jobs:
-c Release \ -c Release \
-r "${{ matrix.rid }}" \ -r "${{ matrix.rid }}" \
--self-contained true \ --self-contained true \
/p:Version="$v" \ -p:Version="$v" \
/p:AssemblyVersion="${v}.0" \ -p:AssemblyVersion="${v}.0" \
/p:FileVersion="${v}.0" \ -p:FileVersion="${v}.0" \
/p:InformationalVersion="$v" -p:InformationalVersion="$v"
- name: Package - name: Package
shell: bash shell: bash
@@ -6,6 +6,10 @@
alongside Windows. The shared Backend classes are written to alongside Windows. The shared Backend classes are written to
OperatingSystem.IsWindows()-gate any Windows-only paths. --> OperatingSystem.IsWindows()-gate any Windows-only paths. -->
<TargetFramework>net9.0</TargetFramework> <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> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>DorkNet.ServerCli</RootNamespace> <RootNamespace>DorkNet.ServerCli</RootNamespace>
+43 -34
View File
@@ -14,8 +14,15 @@ public static class Program
{ {
public static async Task<int> Main(string[] args) 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); 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 // Validate required values up front so the user sees the
// failure before any download / process spin-up. // failure before any download / process spin-up.
@@ -216,50 +223,52 @@ public static class Program
private static ParsedArgs? ParseArgs(string[] args) 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 photon = "", voice = "", region = "us";
string mode = "localtunnel", apex = "", name = "DorkNet Server"; string mode = "localtunnel", apex = "", name = "DorkNet Server";
string versionKey = "march_2020_03_10"; string versionKey = "march_2020_03_10";
string? serverDir = null; 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) string Next()
throw new ArgumentException($"missing value for {args[i]}"); {
return args[++i]; 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; "localtunnel" or "lt" or "internet" or "tunnel" => HostingMode.SingleOriginTunnel,
case "--voice-id": voice = Next(); break; "wildcard" or "remote" or "tunnelto" => HostingMode.RemoteWildcard,
case "--region": region = Next(); break; "lan" or "local" or "wifi" => HostingMode.LocalNetwork,
case "--mode": mode = Next(); break; _ => throw new ArgumentException($"unknown --mode '{mode}' (try localtunnel, wildcard, lan)"),
case "--apex": apex = Next(); break; };
case "--name": name = Next(); break;
case "--version": versionKey = Next(); break; return new ParsedArgs(photon, voice, region, parsedMode, apex, name, versionKey, serverDir);
case "--server-dir": serverDir = Next(); break;
default:
Console.Error.WriteLine($"error: unknown arg '{args[i]}' (try --help)");
return null;
}
} }
catch (ArgumentException ex)
HostingMode parsedMode = mode.ToLowerInvariant() switch
{ {
"localtunnel" or "lt" or "internet" or "tunnel" => HostingMode.SingleOriginTunnel, Console.Error.WriteLine($"error: {ex.Message} (try --help)");
"wildcard" or "remote" or "tunnelto" => HostingMode.RemoteWildcard, return null;
"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);
} }
private static void PrintHelp() private static void PrintHelp()
-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 and click "Sign up". Email + password; the free tier doesn't ask for a
card. card.
![photon dashboard signup screen](images/photon-1-signup.png)
> If you already have an account from another project, log in instead. > If you already have an account from another project, log in instead.
> Multiple DorkNet servers can share the same Photon account, but each > Multiple DorkNet servers can share the same Photon account, but each
> server needs its own AppId pair so concurrent player counts don't > server needs its own AppId pair so concurrent player counts don't
@@ -49,15 +47,11 @@ for:
Click **CREATE**. Click **CREATE**.
![photon "Create a new app" form, Photon SDK selected](images/photon-2-create-realtime.png)
## Step 3 — Copy the Realtime AppId ## Step 3 — Copy the Realtime AppId
You land back on the dashboard with your new app at the top. The 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. 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: That's your **Realtime AppId**. Paste it into:
- the launcher's first-run wizard step 4, **REALTIME APPID** field, OR - 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** If you want in-game voice chat, repeat Step 2 with **Photon Voice**
selected instead of Realtime. Same flow. 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 Copy the Voice AppId from the dashboard the same way as Step 3 and
paste it into: paste it into: