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.