0.2.0: Server-Browser und Spiel-Ticket

- Seite Server: Liste der Website, Ping/Spieler direkt abgefragt, BEITRETEN und Direkt verbinden
- Holt beim Spielen ein Spiel-Ticket und schreibt es in BSO.json

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-28 18:10:55 +01:00
co-authored by Claude Opus 5.5
parent 077e39fa8a
commit fb8d6d6844
8 changed files with 174 additions and 7 deletions
+43 -3
View File
@@ -19,9 +19,9 @@ public sealed class MainForm : Form
readonly Settings settings = Settings.Load();
/// <summary>Befehle, die nur einmal gleichzeitig laufen duerfen (Downloads/Installationen/Start).</summary>
static readonly HashSet<string> Exclusive = new() { "installMod", "launch", "installLauncherUpdate", "uninstall" };
static readonly HashSet<string> Exclusive = new() { "installMod", "launch", "join", "installLauncherUpdate", "uninstall" };
readonly HashSet<string> running = new();
static readonly HashSet<string> QuietCommands = new() { "window", "status", "me", "init", "releases" };
static readonly HashSet<string> QuietCommands = new() { "window", "status", "me", "init", "releases", "servers" };
bool updateInstalled;
static readonly JsonSerializerOptions Json = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
@@ -288,6 +288,18 @@ public sealed class MainForm : Form
return await InstallMod();
case "launch":
return await Launch();
case "servers":
return await ServerList();
case "join":
{
// Beitreten: Server merken, beim Start automatisch verbinden, Spiel starten
string address = Arg(args, "address").Trim();
if (address.Length == 0 || address.Length > 260) throw new Exception("Ungueltige Serveradresse");
settings.Server = address;
settings.AutoConnect = true;
settings.Save();
return await Launch();
}
case "releases":
{
var r = await Api.Releases();
@@ -363,6 +375,21 @@ public sealed class MainForm : Form
};
}
/// <summary>Serverliste der Website, jeder Server direkt angefragt (Ping, aktuelle Spielerzahl). Nicht erreichbar = ohne Ping.</summary>
static async Task<object> ServerList()
{
var servers = await Api.Servers();
var pings = await Task.WhenAll(servers.Select(s => ServerPing.Query(s.host, s.port)));
return servers.Select((s, i) => new
{
s.name, s.description, s.address, s.version,
players = pings[i]?.Players ?? s.players,
maxPlayers = pings[i]?.MaxPlayers ?? s.maxPlayers,
ping = pings[i]?.Ping,
compatible = s.protocol == 0 || s.protocol == 2 // Protokoll der Mod, die der Launcher installiert
}).OrderBy(s => s.ping == null).ThenByDescending(s => s.players).ToList();
}
async Task<object> InstallMod()
{
string folder = Game.FindFolder(settings) ?? throw new Exception("Bus-Simulator 2012 nicht gefunden - in den Einstellungen den Spielordner waehlen");
@@ -388,7 +415,20 @@ public sealed class MainForm : Form
else if (installed == null) throw new Exception("BSO ist nicht installiert und der BSO-Server ist nicht erreichbar");
}
Game.WriteModConfig(folder, settings.Username, settings.Server, settings.AutoConnect);
// Spiel-Ticket: ohne gueltiges Konto kein Multiplayer (Mod und Server pruefen es)
string token = settings.Token ?? throw new Exception("Bitte anmelden");
var t = await Api.Ticket(token);
if (t.Status == 401)
{
settings.Token = null;
settings.Save();
Emit(new { @event = "loggedOut" });
throw new Exception("Anmeldung abgelaufen - bitte neu anmelden");
}
if (!t.Ok) throw new Exception("Konto konnte nicht geprueft werden: " + t.Error);
string ticket = t.Json.GetProperty("ticket").GetString()!;
Game.WriteModConfig(folder, settings.Username, settings.Server, settings.AutoConnect, ticket);
Game.Launch();
LauncherLog.Info($"Spiel gestartet (Server {settings.Server}, automatisch verbinden {settings.AutoConnect})");
if (!settings.KeepOpen)