using System; using Microsoft.Win32; namespace MSCO { /// /// "msco://connect/<host>:<port>"-Links (JOIN-Button auf der Website). /// Die Mod registriert den Link-Typ in Windows so, dass ein Klick Steam direkt mit /// "-applaunch 516750 +msco_connect <link>" startet - ohne cmd/Skript dazwischen, damit /// präparierte Links keine Befehle ausführen können. Die Mod liest die Adresse beim Start /// aus der Kommandozeile und verbindet im Hauptmenü sofort (Server-Mods fragen weiterhin nach). /// (Läuft das Spiel schon, gibt Steam den Link nicht weiter - dann den Server-Browser nutzen.) /// public static class JoinLinks { const string Scheme = "msco"; const string Argument = "+msco_connect"; const int MySummerCarAppId = 516750; /// Link-Typ msco:// für den aktuellen Windows-Benutzer eintragen (kein Admin nötig). public static void Register() { try { string steamExe = SteamExePath(); if (steamExe == null) { MscoLog.Warning("[MSCO] Steam not found - JOIN links from the website are not available."); return; } string command = "\"" + steamExe + "\" -applaunch " + MySummerCarAppId + " " + Argument + " \"%1\""; // Ist der MSCO Launcher installiert, gehören die Links ihm: er startet das Spiel mit MSCO (ohne MSCLoader) using (RegistryKey existing = Registry.CurrentUser.OpenSubKey(@"Software\Classes\" + Scheme + @"\shell\open\command")) { string current = existing != null ? existing.GetValue("") as string : null; if (current != null && current.IndexOf("MSCO-Launcher", StringComparison.OrdinalIgnoreCase) >= 0) return; } using (RegistryKey key = Registry.CurrentUser.CreateSubKey(@"Software\Classes\" + Scheme)) { key.SetValue("", "URL:MSCO Join Link"); key.SetValue("URL Protocol", ""); using (RegistryKey cmd = key.CreateSubKey(@"shell\open\command")) cmd.SetValue("", command); } } catch (Exception e) { MscoLog.Warning("[MSCO] Could not register msco:// links: " + e.Message); } } static string SteamExePath() { using (RegistryKey steam = Registry.CurrentUser.OpenSubKey(@"Software\Valve\Steam")) { string exe = steam != null ? steam.GetValue("SteamExe") as string : null; return string.IsNullOrEmpty(exe) ? null : exe.Replace('/', '\\'); } } static float nextPoll; /// /// JOIN-Link, während das Spiel schon läuft: der MSCO Launcher legt ihn als <Spiel>\MSCO\join.txt ab (Steam /// gibt Links an ein laufendes Spiel nicht weiter). Einmal pro Sekunde nachsehen. /// public static bool TryTakeRequest(out string host, out int port) { host = null; port = 0; if (UnityEngine.Time.realtimeSinceStartup < nextPoll) return false; nextPoll = UnityEngine.Time.realtimeSinceStartup + 1f; try { string file = System.IO.Path.Combine(Bootstrap.Folder ?? "", "join.txt"); if (Bootstrap.Folder == null || !System.IO.File.Exists(file)) return false; string text = System.IO.File.ReadAllText(file); System.IO.File.Delete(file); return TryParse(text, out host, out port); } catch { return false; } } /// Wurde das Spiel über einen JOIN-Link gestartet? public static bool TryGetFromCommandLine(out string host, out int port) { host = null; port = 0; string[] args = Environment.GetCommandLineArgs(); for (int i = 0; i < args.Length - 1; i++) if (args[i] == Argument) return TryParse(args[i + 1], out host, out port); return false; } /// "msco://connect/1.2.3.4:7777/" -> Host und Port (nur Buchstaben, Ziffern, . - :). static bool TryParse(string text, out string host, out int port) { host = null; port = 0; text = text.Trim().Trim('"').Trim(); const string prefix = "msco://connect/"; if (!text.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) return false; string address = text.Substring(prefix.Length).TrimEnd('/'); foreach (char c in address) if (!char.IsLetterOrDigit(c) && c != '.' && c != '-' && c != ':') return false; return ServerBrowser.TryParseAddress(address, out host, out port); } } }