diff --git a/Bootstrap.cs b/Bootstrap.cs new file mode 100644 index 0000000..a95a22c --- /dev/null +++ b/Bootstrap.cs @@ -0,0 +1,143 @@ +using System; +using System.IO; +using System.Reflection; +using Harmony; +using UnityEngine; + +namespace Doorstop +{ + /// + /// Einstieg ohne MSCLoader: Unity Doorstop (winhttp.dll im Spielordner) ruft beim Spielstart diese Methode auf - der + /// MSCO Launcher startet das Spiel mit "--doorstop-target-assembly ...\MSCO\MSCO.dll", MSCLoader wird dann gar nicht + /// geladen. Hier läuft noch nichts von Unity: nur vorbereiten, gestartet wird im Hauptmenü (siehe MSCO.Bootstrap). + /// + public static class Entrypoint + { + public static void Start() + { + MSCO.Bootstrap.Start(); + } + } +} + +namespace MSCO +{ + /// + /// Startet MSCO eigenständig: Abhängigkeiten (Harmony, Newtonsoft.Json) aus dem MSCO-Ordner laden, warten bis das + /// Spiel seinen Code geladen hat, dann beim ersten PlayMakerArrayListProxy.Awake (Hauptmenü, Hauptthread) den + /// MultiplayerManager anlegen. Protokoll: <Spiel>\MSCO\MSCO_Loader.txt. + /// + public static class Bootstrap + { + static string folder; + static bool patched, started; + static StreamWriter log; + + public static void Start() + { + try + { + folder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + log = new StreamWriter(Path.Combine(folder, "MSCO_Loader.txt"), false) { AutoFlush = true }; + Log("MSCO " + MSCO.ModVersion + " loader started (standalone, without MSCLoader)"); + Log("Command line: " + string.Join(" ", Environment.GetCommandLineArgs())); + AppDomain.CurrentDomain.AssemblyResolve += Resolve; + AppDomain.CurrentDomain.AssemblyLoad += (_, e) => OnAssemblyLoaded(e.LoadedAssembly); + foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) OnAssemblyLoaded(a); + } + catch (Exception e) + { + Log("Loader failed: " + e); + } + } + + public static void Log(string line) + { + try { if (log != null) log.WriteLine(DateTime.Now.ToString("HH:mm:ss") + " " + line); } catch { } + } + + /// Unsere Abhängigkeiten liegen neben MSCO.dll (das Spiel sucht nur in Managed). + static Assembly Resolve(object sender, ResolveEventArgs args) + { + try + { + string name = new AssemblyName(args.Name).Name; + string file = Path.Combine(folder, name + ".dll"); + if (File.Exists(file)) return Assembly.LoadFrom(file); + } + catch (Exception e) { Log("Resolve " + args.Name + " failed: " + e.Message); } + return null; + } + + static void OnAssemblyLoaded(Assembly assembly) + { + if (patched) return; + string name; + try { name = assembly.GetName().Name; } catch { return; } + if (name != "Assembly-CSharp") return; + patched = true; + try { Patch(assembly); } + catch (Exception e) { Log("Could not hook into the game: " + e); } + } + + /// Haken in PlayMakerArrayListProxy.Awake (läuft im Hauptmenü früh auf dem Hauptthread). + static void Patch(Assembly game) + { + Type proxy = game.GetType("PlayMakerArrayListProxy"); + MethodInfo awake = proxy != null ? proxy.GetMethod("Awake", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : null; + if (awake == null) + { + Log("PlayMakerArrayListProxy.Awake not found - MSCO cannot start"); + return; + } + HarmonyInstance.Create("mbm.msco.bootstrap").Patch(awake, + new HarmonyMethod(typeof(Bootstrap).GetMethod("BeforeAwake", BindingFlags.Static | BindingFlags.NonPublic)), null); + Log("Hooked into the game, waiting for the main menu"); + } + + static void BeforeAwake() + { + if (started) return; + started = true; + try + { + var go = new GameObject("MSCO_Host"); + UnityEngine.Object.DontDestroyOnLoad(go); + go.AddComponent(); + Log("MSCO started"); + } + catch (Exception e) { Log("Start failed: " + e); } + } + } + + /// Lebt über alle Szenen: legt im Hauptmenü den MultiplayerManager an (früher MSCLoaders OnMenuLoad). + public class MscoHost : MonoBehaviour + { + void Start() + { + MscoLog.Info("Welcome to MSCO by mbm.wtf"); + // Den Nachrichten-Bildschirm des Spiels ("Latest news ... press any key") überspringen - direkt ins Hauptmenü + string scene = Application.loadedLevelName; + Bootstrap.Log("First scene: " + scene); + if (scene != "MainMenu" && scene != "GAME") + { + Bootstrap.Log("Skipping the intro/news screen"); + Application.LoadLevel("MainMenu"); + return; + } + MultiplayerManager.Ensure(); + } + + void OnLevelWasLoaded(int level) + { + Bootstrap.Log("Level loaded: " + Application.loadedLevelName); + MultiplayerManager.Ensure(); + } + + void OnApplicationQuit() + { + // Wer beendet das Spiel? (Diagnose) + Bootstrap.Log("Game is quitting (scene " + Application.loadedLevelName + "): " + System.Environment.StackTrace); + } + } +} diff --git a/Branding.cs b/Branding.cs index 544ec62..536e2aa 100644 --- a/Branding.cs +++ b/Branding.cs @@ -6,7 +6,7 @@ namespace MSCO { /// /// MSCO-Logo (branding/logo-128.png, als Ressource in die DLL eingebettet): - /// Symbol in der MSCLoader-Modliste und im Launcher. + /// Symbol im MSCO-Launcher (Hauptmenü) und in Overlays. /// public static class Branding { diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ac7da0..e4608ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 2.9.0 + +**Eigenständig – ohne MSCLoader** +- MSCO braucht MSCLoader nicht mehr: es startet selbst über Unity Doorstop (`winhttp.dll`) aus `\MSCO`. + Der MSCO Launcher richtet alles ein und stellt `doorstop_config.ini` auf MSCO um – auch der Start über Steam lädt dann + MSCO. MSCLoader ist dabei blockiert (seine Konfiguration wird als `doorstop_config.mscloader.ini` gesichert) +- Der Nachrichten-Bildschirm beim Spielstart („Press any key“) wird übersprungen, MSCO öffnet direkt im Hauptmenü +- Tasten ändern jetzt mit `bind` in der F7-Konsole (`bind passenger O`), gespeichert in den Spiel-Einstellungen +- Harmony und Newtonsoft.Json liegen neben `MSCO.dll`; Lade-Protokoll in `MSCO\MSCO_Loader.txt` +- `msco://`-Links werden vom Launcher übernommen, wenn er installiert ist +- Netzwerk-Version bleibt 2.8: spielt mit 2.8.x-Servern und -Mitspielern + ## 2.8.1 **Mehr Events synchron** diff --git a/Commands.cs b/Commands.cs index 06fd638..ea4d835 100644 --- a/Commands.cs +++ b/Commands.cs @@ -1,10 +1,11 @@ +using UnityEngine; using System; namespace MSCO { /// /// Alle MSCO-Befehle an einer Stelle - genutzt von der eigenen F7-Konsole (ohne "mp" davor) - /// und von der MSCLoader-Konsole ("mp ..."). + /// (früher auch aus der MSCLoader-Konsole - MSCO läuft jetzt ohne MSCLoader). /// public static class Commands { @@ -17,6 +18,7 @@ namespace MSCO "disconnect - leave the server / game\n" + "host [port] / join [port] - direct LAN game (no Steam)\n" + "save - save the game (host / singleplayer)\n" + + "bind [action key] - show / change keys (passenger, console, chat)\n" + "ping [on|off] - show your ping to the server (toggle)\n" + "fps [on|off] - show the frames per second (toggle)\n" + "/admin - admin menu (kick / ban / teleport / cheats)\n" + @@ -115,6 +117,22 @@ namespace MSCO else mp.ShowPing = !mp.ShowPing; print("Ping: " + mp.PingText + " (display " + (mp.ShowPing ? "on" : "off") + ")"); break; + case "bind": + { + // Tasten ändern: "bind" zeigt alle, "bind passenger O" setzt eine (früher MSCLoader-Einstellungen) + if (args.Length < 3) + { + foreach (KeyBinding k in MSCO.Keys) print(" " + k.Id.PadRight(10) + " " + k.Key + " (" + k.Description + ", default " + k.Default + ")"); + print("Change: bind <" + string.Join("|", System.Array.ConvertAll(MSCO.Keys, k => k.Id)) + "> e.g. bind passenger O"); + break; + } + KeyBinding target = System.Array.Find(MSCO.Keys, k => k.Id.Equals(args[1], System.StringComparison.OrdinalIgnoreCase)); + KeyCode key; + if (target == null) print("Unknown action " + args[1] + " - see 'bind'"); + else if (!KeyBinding.TryParse(args[2], out key)) print("Unknown key " + args[2] + " (Unity key names, e.g. O, F6, Keypad5, Mouse3)"); + else { target.Key = key; print(target.Description + ": " + key); } + break; + } case "fps": // "fps" schaltet die Anzeige um, "fps on/off" setzt sie if (args.Length > 1) mp.ShowFps = args[1].ToLower() == "on" || args[1] == "1"; diff --git a/DiscordPresence.cs b/DiscordPresence.cs index 220a10f..66d20ef 100644 --- a/DiscordPresence.cs +++ b/DiscordPresence.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.Threading; -using MSCLoader; using UnityEngine; namespace MSCO diff --git a/DoorSync.cs b/DoorSync.cs index 45e7be4..3da3b1f 100644 --- a/DoorSync.cs +++ b/DoorSync.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.IO; using HutongGames.PlayMaker; -using MSCLoader; using UnityEngine; namespace MSCO diff --git a/FsmSync.cs b/FsmSync.cs index 0f40cc0..01c4697 100644 --- a/FsmSync.cs +++ b/FsmSync.cs @@ -4,7 +4,6 @@ using System.IO; using System.Reflection; using Harmony; using HutongGames.PlayMaker; -using MSCLoader; using UnityEngine; namespace MSCO diff --git a/InputLock.cs b/InputLock.cs index d7f39d4..aeed2f6 100644 --- a/InputLock.cs +++ b/InputLock.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Reflection; using Harmony; -using MSCLoader; using UnityEngine; namespace MSCO diff --git a/JoinLinks.cs b/JoinLinks.cs index c8078b6..613e58a 100644 --- a/JoinLinks.cs +++ b/JoinLinks.cs @@ -1,6 +1,5 @@ using System; using Microsoft.Win32; -using MSCLoader; namespace MSCO { @@ -31,6 +30,13 @@ namespace MSCO } 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"); diff --git a/MSCO.cs b/MSCO.cs index 36daaf2..b7af382 100644 --- a/MSCO.cs +++ b/MSCO.cs @@ -1,22 +1,24 @@ -using MSCLoader; using UnityEngine; namespace MSCO { - public class MSCO : Mod + /// + /// MSCO - My Summer Car Online. Läuft eigenständig (ohne MSCLoader): gestartet über Unity Doorstop, siehe Bootstrap. + /// + public static class MSCO { /// - /// Version der Mod (MSCLoader / MSC Launcher). Kleine Updates: nur die dritte Stelle erhöhen (2.8.1, 2.8.2 ...) - - /// sie bleiben mit 2.8-Servern und -Mitspielern kompatibel. + /// Version der Mod. Kleine Updates: nur die dritte Stelle erhöhen (2.9.1, 2.9.2 ...) - sie bleiben mit + /// Servern und Mitspielern derselben ersten zwei Stellen kompatibel. /// - public const string ModVersion = "2.8.1"; + public const string ModVersion = "2.9.0"; /// /// Netzwerk-Version (die ersten beiden Stellen). Nur erhöhen, wenn sich das Protokoll inkompatibel ändert - dann - /// auch GameServer.ModVersion im Server und eine neue Mod-Version 2.9.0 o.ä. + /// auch GameServer.ModVersion im Server. /// public const string ProtocolVersion = "2.8"; - /// Passt eine andere Version (Server, Host, Mitspieler) zu uns? Verglichen werden nur die ersten zwei Stellen. + /// Passt eine andere Version (Server, Host, Mitspieler) zu uns? Verglichen wird die Netzwerk-Version. public static bool Compatible(string other) { return Protocol(other) == ProtocolVersion; @@ -30,78 +32,67 @@ namespace MSCO return parts.Length >= 2 ? parts[0] + "." + parts[1] : version.Trim(); } - public override string ID => "MSCO"; // Your (unique) mod ID - public override string Name => "MSCO"; // Your mod name - public override string Author => "MBM"; // Name of the Author (your name) - public override string Version => ModVersion; // Version - public override string Description => "Online mod by mbm.wtf"; // Short description of your mod - public override Game SupportedGames => Game.MySummerCar; - // Logo in der MSCLoader-Modliste (branding/logo-128.png, in die DLL eingebettet) - public override byte[] Icon { get { return Branding.LogoPng; } set { } } + /// Beifahrer ein-/aussteigen (Standard P), Konsole (F7), Chat (T) - änderbar mit "bind" in der Konsole. + internal static readonly KeyBinding PassengerKey = new KeyBinding("passenger", "Ride along / get out", KeyCode.P); + internal static readonly KeyBinding ConsoleKey = new KeyBinding("console", "Open the MSCO console", KeyCode.F7); + internal static readonly KeyBinding ChatKey = new KeyBinding("chat", "Open the chat", KeyCode.T); + internal static readonly KeyBinding[] Keys = { PassengerKey, ConsoleKey, ChatKey }; + } - bool commandAdded; + /// Tastenbelegung, gespeichert in den PlayerPrefs (früher in den MSCLoader-Einstellungen). + public class KeyBinding + { + public readonly string Id, Description; + public readonly KeyCode Default; + bool loaded; + KeyCode key; - public override void ModSetup() + public KeyBinding(string id, string description, KeyCode defaultKey) { - SetupFunction(Setup.OnMenuLoad, Mod_OnMenuLoad); - SetupFunction(Setup.OnLoad, Mod_OnLoad); - SetupFunction(Setup.PostLoad, Mod_PostLoad); - SetupFunction(Setup.OnSave, Mod_OnSave); - SetupFunction(Setup.OnGUI, Mod_OnGUI); - SetupFunction(Setup.Update, Mod_Update); - SetupFunction(Setup.FixedUpdate, Mod_FixedUpdate); - SetupFunction(Setup.ModSettings, Mod_Settings); + Id = id; + Description = description; + Default = defaultKey; } - /// Taste zum Ein-/Aussteigen als Beifahrer (in den MSCLoader-Einstellungen änderbar). - internal static SettingsKeybind PassengerKey; - /// MSCO-Konsole (Standard F7) und Chat (Standard T), ebenfalls änderbar. - internal static SettingsKeybind ConsoleKey, ChatKey; + string Pref { get { return "MSCO_Key_" + Id; } } - private void Mod_Settings() + public KeyCode Key { - // All settings should be created here. - // DO NOT put anything that isn't settings or keybinds in here! - PassengerKey = Keybind.Add("passenger", "Ride as passenger (toggle)", KeyCode.P); - ChatKey = Keybind.Add("chat", "Open chat", KeyCode.T); - // Nicht F8: im Pausenmenü öffnet F8 ein Test-Menü des Spiels. Neue ID, damit alte F8-Belegungen nicht übernommen werden - ConsoleKey = Keybind.Add("console_f7", "Open MSCO console", KeyCode.F7); - } - - private void Mod_OnMenuLoad() - { - MscoLog.Info("Welcome to MSCO by mbm.wtf"); - // Netzwerk + Lobby leben in einem eigenen Objekt, das Szenenwechsel überlebt - MultiplayerManager.Ensure(); - if (!commandAdded) + get { - ConsoleCommand.Add(new MpCommand()); - commandAdded = true; + if (!loaded) + { + // Erst im Spiel lesen (PlayerPrefs gehen nicht in statischen Initialisierern) + KeyCode parsed; + key = TryParse(PlayerPrefs.GetString(Pref, ""), out parsed) ? parsed : Default; + loaded = true; + } + return key; + } + set + { + key = value; + loaded = true; + PlayerPrefs.SetString(Pref, value.ToString()); + PlayerPrefs.Save(); } } - private void Mod_OnLoad() + + public bool GetKeybindDown() { - // Called once, when mod is loading after game is fully loaded + return Key != KeyCode.None && Input.GetKeyDown(Key); } - private void Mod_PostLoad() + + public static bool TryParse(string text, out KeyCode key) { - // Called once, after all mods finished OnLoad - } - private void Mod_OnSave() - { - // Called once, when save and quit - } - private void Mod_OnGUI() - { - // Lobby/Status zeichnet der MultiplayerManager - } - private void Mod_Update() - { - // Netzwerk läuft im MultiplayerManager - } - private void Mod_FixedUpdate() - { - // FixedUpdate is called once per fixed frame + key = KeyCode.None; + if (string.IsNullOrEmpty(text)) return false; + try + { + key = (KeyCode)System.Enum.Parse(typeof(KeyCode), text.Trim(), true); + return true; + } + catch { return false; } } } } diff --git a/MSCO.csproj b/MSCO.csproj index eded03f..70d701a 100644 --- a/MSCO.csproj +++ b/MSCO.csproj @@ -42,12 +42,8 @@ F:\SteamLibrary\steamapps\common\My Summer Car\mysummercar_Data\Managed\UnityEngine.dll False - - F:\SteamLibrary\steamapps\common\My Summer Car\mysummercar_Data\Managed\MSCLoader.dll - False - - F:\SteamLibrary\steamapps\common\My Summer Car\mysummercar_Data\Managed\Newtonsoft.Json.dll + lib\Newtonsoft.Json.dll False @@ -67,7 +63,7 @@ False - F:\SteamLibrary\steamapps\common\My Summer Car\mysummercar_Data\Managed\0Harmony.dll + lib\0Harmony.dll False @@ -82,7 +78,7 @@ - + @@ -120,35 +116,11 @@ - - C:\Users\nico\Documents\MySummerCar\Mods - NONE - NONE - - echo . - echo "== Running post build actions for configuration $(ConfigurationName)! ===" - IF "$(ConfigurationName)" == "Release" ( - IF NOT "$(MSCMODSFOLDER)" == "NONE" ( - copy "$(TargetPath)" "$(MSCMODSFOLDER)" /y - echo "Copied dll into MSC mods folder!" - ) - IF NOT "$(MWCMODSFOLDER)" == "NONE" ( - copy "$(TargetPath)" "$(MWCMODSFOLDER)" /y - echo "Copied dll into MWC mods folder!" - ) - ) - -if "$(ConfigurationName)" == "Debug" ( -copy "$(TargetPath)" "C:\Users\nico\Documents\MySummerCar\Mods" /y -copy "$(TargetDir)$(TargetName).pdb" "C:\Users\nico\Documents\MySummerCar\Mods" /y -cd "C:\Users\nico\Documents\MySummerCar\Mods" -call "C:\Users\nico\Documents\MySummerCar\Mods\debug.bat" -) ELSE ( -copy "$(TargetPath)" "C:\Users\nico\Documents\MySummerCar\Mods\Mods" /y -) - - + + + + diff --git a/MenuHelper.cs b/MenuHelper.cs index 9220a03..ac2fbe4 100644 --- a/MenuHelper.cs +++ b/MenuHelper.cs @@ -1,7 +1,6 @@ using System.Reflection; using HutongGames.PlayMaker; using HutongGames.PlayMaker.Actions; -using MSCLoader; using UnityEngine; namespace MSCO diff --git a/MpCommand.cs b/MpCommand.cs deleted file mode 100644 index 546065a..0000000 --- a/MpCommand.cs +++ /dev/null @@ -1,16 +0,0 @@ -using MSCLoader; - -namespace MSCO -{ - /// MSCLoader-Konsole: "mp <befehl>" - gleiche Befehle wie in der F7-Konsole. - public class MpCommand : ConsoleCommand - { - public override string Name => "mp"; - public override string Help => "MSCO commands, e.g. mp help | mp connect | mp save (or press F7)"; - - public override void Run(string[] args) - { - Commands.Execute(args, line => ModConsole.Print("[MSCO] " + line)); - } - } -} diff --git a/MscoLog.cs b/MscoLog.cs index db8f330..17a6da7 100644 --- a/MscoLog.cs +++ b/MscoLog.cs @@ -4,7 +4,7 @@ using UnityEngine; namespace MSCO { /// - /// Zentrales Log der Mod: alle Meldungen landen in der MSCO-Konsole (F7), nicht in der MSCLoader-Konsole. + /// Zentrales Log der Mod: alle Meldungen landen in der MSCO-Konsole (F7), nicht in einer Loader-Konsole. /// Zusätzlich gehen sie per Debug.Log in die output_log.txt des Spiels (zur Fehlersuche), ohne dass sich die /// MSCLoader-Konsole öffnet. Thread-sicher: Meldungen aus Hintergrund-Threads werden im Hauptthread übernommen. /// diff --git a/MultiplayerManager.cs b/MultiplayerManager.cs index d9fb4a3..080f17a 100644 --- a/MultiplayerManager.cs +++ b/MultiplayerManager.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.IO; using HutongGames.PlayMaker; -using MSCLoader; using UnityEngine; namespace MSCO @@ -1103,7 +1102,7 @@ namespace MSCO public string DisconnectNotice { get; private set; } // ---------------------------------------------------------------- Über Neuladen hinweg merken - // Beim Wechsel ins Hauptmenü lädt MSCLoader alle Mods neu - dabei ginge der Kick-Grund bzw. "bitte neu + // Beim Wechsel ins Hauptmenü wird die Sitzung neu aufgebaut - dabei ginge der Kick-Grund bzw. "bitte neu // verbinden" verloren, bevor man das Menü überhaupt sieht. Deshalb in den PlayerPrefs sichern. const string PrefNotice = "MSCO_PendingNotice"; const string PrefReconnect = "MSCO_PendingReconnect"; @@ -1339,7 +1338,7 @@ namespace MSCO if (wasClientInGame) { SetStatus("Disconnected from host: " + reason); - PersistPendingState(); // MSCLoader lädt die Mods im Menü neu - vorher sichern + PersistPendingState(); // das Menü baut alles neu auf - vorher sichern Application.LoadLevel(MenuHelper.MenuScene); } } @@ -2422,7 +2421,7 @@ namespace MSCO overlays.Draw(this, session != null); } - /// F7 Konsole, T Chat (Tasten in den MSCLoader-Einstellungen änderbar). + /// F7 Konsole, T Chat (Tasten mit "bind" in der Konsole änderbar). void UpdateOverlayKeys() { if (MSCO.ConsoleKey != null && MSCO.ConsoleKey.GetKeybindDown()) overlays.ToggleConsole(); diff --git a/ObjectSync.cs b/ObjectSync.cs index 5e1a08a..8774a01 100644 --- a/ObjectSync.cs +++ b/ObjectSync.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Text; using HutongGames.PlayMaker; -using MSCLoader; using UnityEngine; namespace MSCO diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index e193108..5d93618 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; // Please disclose yourself when generating code for this project // Put "Generated By: {AI model name}" in AssemblyTrademark("") field [assembly: AssemblyTitle("MSCO")] -[assembly: AssemblyDescription("MSCLoader Mod file")] +[assembly: AssemblyDescription("MSCO - My Summer Car Online (standalone, Unity Doorstop)")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("MBM")] [assembly: AssemblyProduct("MSCO")] diff --git a/README.md b/README.md index cd5cc3c..54959fb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # MSCO – My Summer Car Online -Multiplayer-Mod für **My Summer Car** (MSCLoader). Spiel mit bis zu 3 Spielern zusammen – per Steam-Einladung -(P2P) oder auf einem dedizierten Server aus dem Server-Browser. +Multiplayer-Mod für **My Summer Car**. Spiel mit bis zu 3 Spielern zusammen – per Steam-Einladung (P2P) oder auf +einem dedizierten Server aus dem Server-Browser. MSCO läuft **eigenständig, ohne MSCLoader** (Start über +[Unity Doorstop](https://github.com/NeighTools/UnityDoorstop)); MSCLoader wird beim Spielen mit MSCO blockiert. - Mod: dieses Repository - Dedizierter Server: [MSCO-Dedicated-Server](https://git.mbm.wtf/MrMaho/MSCO-Dedicated-Server) @@ -49,20 +50,32 @@ Multiplayer-Mod für **My Summer Car** (MSCLoader). Spiel mit bis zu 3 Spielern GOTO/BRING (teleportieren), Cheats (+1.000 / +10.000 MK, Bedürfnisse auffüllen, Satsuma zu sich holen), Items spawnen, Welt zurücksetzen/Backups – Cheats werden im Chat angezeigt - **P** / **Leertaste** – aussteigen; **P** neben einem Auto – auf den Beifahrersitz -- Alle Tasten sind in den MSCLoader-Einstellungen der Mod änderbar +- Tasten ändern mit `bind` in der F7-Konsole (z.B. `bind passenger O`) - Rich Presence: zeigt Freunden deinen Status („In the Menus“, Server, Spielerzahl) ## Installation **Mit dem Launcher (empfohlen):** den [MSCO Launcher](https://msco.mbm.wtf/download) installieren – er installiert -und aktualisiert MSCO und startet das Spiel. [MSCLoader](https://github.com/piotrulos/MSCModLoader) muss installiert sein. +und aktualisiert MSCO und startet das Spiel. MSCLoader wird **nicht** gebraucht. -**Von Hand:** +Was der Launcher im Spielordner einrichtet: -1. [MSCLoader](https://github.com/piotrulos/MSCModLoader) installieren. -2. `MSCO.dll` von der [Download-Seite](https://msco.mbm.wtf/download) laden und in den Mods-Ordner kopieren - (Standard: `Documents\MySummerCar\Mods`). -3. Spiel **über Steam** starten – ohne Steam gehen nur Non-Steam-Server. +| Datei | | +|---|---| +| `MSCO\MSCO.dll` (+ `0Harmony.dll`, `Newtonsoft.Json.dll`) | die Mod | +| `winhttp.dll` | Unity Doorstop 4 – nur wenn noch keiner da ist (MSCLoader bringt denselben mit) | +| `doorstop_config.ini` | zeigt auf `MSCO\MSCO.dll` – eine MSCLoader-Konfiguration wird vorher als `doorstop_config.mscloader.ini` gesichert | + +Alte MSCO-Versionen im MSCLoader-Mods-Ordner werden in `MSCO.dll.old` umbenannt. Damit startet My Summer Car auch über +Steam mit MSCO und ohne MSCLoader. **MSCLoader wieder benutzen:** `doorstop_config.mscloader.ini` zurück in +`doorstop_config.ini` umbenennen. + +**Von Hand:** Doorstop 4 (`winhttp.dll`, x64) in den Spielordner, `MSCO.dll` von der +[Download-Seite](https://msco.mbm.wtf/download) mit `0Harmony.dll` und `Newtonsoft.Json.dll` nach +`\MSCO\` und in `doorstop_config.ini` `target_assembly = MSCO\MSCO.dll` eintragen. + +Spiel **mit Steam** starten – ohne Steam gehen nur Non-Steam-Server. Das Lade-Protokoll steht in +`\MSCO\MSCO_Loader.txt`. ### Einen eigenen Server betreiben @@ -77,12 +90,14 @@ unter https://msco.mbm.wtf/keys. | „This server requires Steam“ | Spiel über Steam starten | | Warnung „Version mismatch“ | Die ersten zwei Stellen unterscheiden sich – Mod (Launcher) oder Server aktualisieren | | Mod lässt sich nicht aktualisieren | Spiel schließen – solange es läuft, ist `MSCO.dll` gesperrt | +| Statt MSCO startet MSCLoader | Im Launcher **SPIELEN** drücken – er stellt `doorstop_config.ini` wieder auf MSCO (z.B. nach einem MSCLoader-Update) | +| MSCO startet gar nicht | `\MSCO\MSCO_Loader.txt` ansehen | | Eigener Spielstand weg | Wird nach dem Verlassen automatisch wiederhergestellt; Sicherung liegt in `AppData\LocalLow\Amistech\My Summer Car\MSCO_Backup` | | Absturz / Hänger beim Beitreten | `output_log.txt` im Spielordner an den Server-Betreiber bzw. als Issue schicken | ## Befehle -In der F7-Konsole direkt, in der MSCLoader-Konsole mit `mp` davor (z.B. `mp connect ...`): +In der F7-Konsole: | Befehl | Beschreibung | |---|---| @@ -98,38 +113,40 @@ In der F7-Konsole direkt, in der MSCLoader-Konsole mit `mp` davor (z.B. `mp conn | `admin` bzw. `/admin` im Chat | Admin-Menü | | `vehicles`, `rig` | Diagnose: Fahrzeuge / Spielermodelle | | `debug` | Sync-Debugausgaben an/aus | +| `bind [aktion taste]` | Tasten anzeigen / ändern (`passenger`, `console`, `chat`) | | `clear` | Konsole leeren | ## Selbst bauen - Eine C#-Entwicklungsumgebung, .NET Framework 3.5 (Unity 5.0 / Mono) - Die Verweise in `MSCO.csproj` zeigen auf `F:\SteamLibrary\steamapps\common\My Summer Car\mysummercar_Data\Managed\` - (UnityEngine, PlayMaker, Assembly-CSharp, Assembly-CSharp-firstpass, MSCLoader, 0Harmony, Newtonsoft.Json, cInput) – - bei anderem Installationsort anpassen. -- Nach dem Build wird die DLL automatisch nach `Documents\MySummerCar\Mods` kopiert (`MSCMODSFOLDER` in der csproj). + (UnityEngine, PlayMaker, Assembly-CSharp, Assembly-CSharp-firstpass, cInput) – bei anderem Installationsort anpassen. + Harmony 1.2 und Newtonsoft.Json liegen in `lib/` (MIT, siehe `lib/THIRD-PARTY.txt`). +- Nach dem Build wird die DLL automatisch nach `\MSCO` kopiert (Ziel `CopyToGame` in der csproj). +- Einstieg: `Bootstrap.cs` (`Doorstop.Entrypoint.Start` → Harmony-Haken in `PlayMakerArrayListProxy.Awake` → `MSCO_Host` + im Hauptmenü, überspringt den Nachrichten-Bildschirm). ``` msbuild MSCO.csproj -p:Configuration=Release ``` -### Updates veröffentlichen (MSC Launcher / MSCLoader) +### Updates veröffentlichen - **Kleines Update** (Fehlerbehebungen, neue Funktionen, Netzwerk unverändert): in `MSCO.cs` nur die dritte Stelle von - `ModVersion` erhöhen (`2.8.1` → `2.8.2`), Release bauen und `bin/Release/MSCO.dll` hochladen. Spieler mit 2.8.x - spielen weiter zusammen, Server 2.8 müssen nicht aktualisiert werden. + `ModVersion` erhöhen (`2.9.0` → `2.9.1`), Release bauen und `bin/Release/MSCO.dll` auf den Keymaster laden. Spieler + mit derselben Netzwerk-Version spielen weiter zusammen, Server müssen nicht aktualisiert werden. - **Großes Update** (Protokoll inkompatibel geändert): `ProtocolVersion` in `MSCO.cs` **und** `GameServer.ModVersion` im Server erhöhen (z.B. `2.9`), `ModVersion` auf `2.9.0`. Dann brauchen alle die neue Mod und den neuen Server. - Verglichen werden immer nur die ersten zwei Stellen; übers Netz geht nur die Netzwerk-Version. - **Automatisch hochladen**: Ist lokal `MSCO_RELEASE_TOKEN` gesetzt (= `RELEASE_TOKEN` des Keymasters, oder in - `%AppData%\MSCO -elease-token.txt`), lädt jeder Release-Build eine neue Version selbst auf den Keymaster + `%AppData%\MSCO\release-token.txt`), lädt jeder Release-Build eine neue Version selbst auf den Keymaster (`release.ps1`, Changelog aus dem passenden Abschnitt in `CHANGELOG.md`). Gibt es die Version schon, passiert nichts. ## Aufbau | Datei | Aufgabe | |---|---| -| `MSCO.cs` | Mod-Einstieg, Tastenbelegung | +| `Bootstrap.cs`, `MSCO.cs` | Start ohne MSCLoader (Doorstop), Versionen, Tastenbelegung | | `MultiplayerManager.cs` | Sitzung, Nachrichten, Spielerliste, Spielstart, HUD | | `NetSession.cs` | Netzwerk (TCP und Steam P2P), Protokoll | | `LobbyUI.cs`, `Overlays.cs`, `UiTheme.cs` | Launcher, Konsole/Chat/Admin-Menü, gemeinsamer Stil | diff --git a/SafetyPatches.cs b/SafetyPatches.cs index caeefa6..05ce33d 100644 --- a/SafetyPatches.cs +++ b/SafetyPatches.cs @@ -2,7 +2,6 @@ using System; using System.Reflection; using Harmony; using HutongGames.PlayMaker; -using MSCLoader; using UnityEngine; namespace MSCO diff --git a/SaveSync.cs b/SaveSync.cs index 29192ea..af3c2dc 100644 --- a/SaveSync.cs +++ b/SaveSync.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.IO; -using MSCLoader; using UnityEngine; namespace MSCO diff --git a/SteamLobby.cs b/SteamLobby.cs index 28b47e1..f89512d 100644 --- a/SteamLobby.cs +++ b/SteamLobby.cs @@ -1,5 +1,4 @@ using System; -using MSCLoader; using Steamworks; namespace MSCO diff --git a/VehicleStateSync.cs b/VehicleStateSync.cs index cbbdaef..397b032 100644 --- a/VehicleStateSync.cs +++ b/VehicleStateSync.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Text; using HutongGames.PlayMaker; -using MSCLoader; using UnityEngine; namespace MSCO diff --git a/WorldSync.cs b/WorldSync.cs index a51c9d4..eabb6e9 100644 --- a/WorldSync.cs +++ b/WorldSync.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.IO; using HutongGames.PlayMaker; -using MSCLoader; using UnityEngine; namespace MSCO diff --git a/lib/0Harmony.dll b/lib/0Harmony.dll new file mode 100644 index 0000000..6c0dd94 Binary files /dev/null and b/lib/0Harmony.dll differ diff --git a/lib/Newtonsoft.Json.dll b/lib/Newtonsoft.Json.dll new file mode 100644 index 0000000..3bc80ac Binary files /dev/null and b/lib/Newtonsoft.Json.dll differ diff --git a/lib/THIRD-PARTY.txt b/lib/THIRD-PARTY.txt new file mode 100644 index 0000000..1d97e21 --- /dev/null +++ b/lib/THIRD-PARTY.txt @@ -0,0 +1,20 @@ +Third-party libraries shipped with MSCO +======================================= + +0Harmony.dll - Harmony 1.2.0.1 by Andreas Pardeike + https://github.com/pardeike/Harmony - MIT License + Copyright (c) 2017 Andreas Pardeike + +Newtonsoft.Json.dll - Json.NET 13.0.4 by James Newton-King + https://www.newtonsoft.com/json - MIT License + Copyright (c) 2007 James Newton-King + +MIT License: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including without +limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above +copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.