MSCO 2.9.0: standalone without MSCLoader (Unity Doorstop)
- Bootstrap: Doorstop entry point, loads Harmony/Newtonsoft from the MSCO folder, hooks PlayMakerArrayListProxy.Awake and starts MSCO in the main menu; skips the news screen - No MSCLoader reference anymore; key bindings in PlayerPrefs, bind console command - Harmony 1.2 and Newtonsoft.Json in lib/ (MIT notices); build copies to <game>\MSCO - README/CHANGELOG updated Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+143
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Harmony;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Doorstop
|
||||
{
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
public static class Entrypoint
|
||||
{
|
||||
public static void Start()
|
||||
{
|
||||
MSCO.Bootstrap.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace MSCO
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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 { }
|
||||
}
|
||||
|
||||
/// <summary>Unsere Abhängigkeiten liegen neben MSCO.dll (das Spiel sucht nur in Managed).</summary>
|
||||
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); }
|
||||
}
|
||||
|
||||
/// <summary>Haken in PlayMakerArrayListProxy.Awake (läuft im Hauptmenü früh auf dem Hauptthread).</summary>
|
||||
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<MscoHost>();
|
||||
Log("MSCO started");
|
||||
}
|
||||
catch (Exception e) { Log("Start failed: " + e); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Lebt über alle Szenen: legt im Hauptmenü den MultiplayerManager an (früher MSCLoaders OnMenuLoad).</summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@ namespace MSCO
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public static class Branding
|
||||
{
|
||||
|
||||
@@ -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 `<Spielordner>\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**
|
||||
|
||||
+19
-1
@@ -1,10 +1,11 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
namespace MSCO
|
||||
{
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
public static class Commands
|
||||
{
|
||||
@@ -17,6 +18,7 @@ namespace MSCO
|
||||
"disconnect - leave the server / game\n" +
|
||||
"host [port] / join <ip> [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)) + "> <key> 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";
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using HutongGames.PlayMaker;
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.IO;
|
||||
using System.Reflection;
|
||||
using Harmony;
|
||||
using HutongGames.PlayMaker;
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Harmony;
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
|
||||
+7
-1
@@ -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");
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
{
|
||||
public class MSCO : Mod
|
||||
/// <summary>
|
||||
/// MSCO - My Summer Car Online. Läuft eigenständig (ohne MSCLoader): gestartet über Unity Doorstop, siehe Bootstrap.
|
||||
/// </summary>
|
||||
public static class MSCO
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public const string ModVersion = "2.8.1";
|
||||
public const string ModVersion = "2.9.0";
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public const string ProtocolVersion = "2.8";
|
||||
|
||||
/// <summary>Passt eine andere Version (Server, Host, Mitspieler) zu uns? Verglichen werden nur die ersten zwei Stellen.</summary>
|
||||
/// <summary>Passt eine andere Version (Server, Host, Mitspieler) zu uns? Verglichen wird die Netzwerk-Version.</summary>
|
||||
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 { } }
|
||||
|
||||
bool commandAdded;
|
||||
|
||||
public override void ModSetup()
|
||||
{
|
||||
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);
|
||||
/// <summary>Beifahrer ein-/aussteigen (Standard P), Konsole (F7), Chat (T) - änderbar mit "bind" in der Konsole.</summary>
|
||||
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 };
|
||||
}
|
||||
|
||||
/// <summary>Taste zum Ein-/Aussteigen als Beifahrer (in den MSCLoader-Einstellungen änderbar).</summary>
|
||||
internal static SettingsKeybind PassengerKey;
|
||||
/// <summary>MSCO-Konsole (Standard F7) und Chat (Standard T), ebenfalls änderbar.</summary>
|
||||
internal static SettingsKeybind ConsoleKey, ChatKey;
|
||||
|
||||
private void Mod_Settings()
|
||||
/// <summary>Tastenbelegung, gespeichert in den PlayerPrefs (früher in den MSCLoader-Einstellungen).</summary>
|
||||
public class KeyBinding
|
||||
{
|
||||
// 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);
|
||||
public readonly string Id, Description;
|
||||
public readonly KeyCode Default;
|
||||
bool loaded;
|
||||
KeyCode key;
|
||||
|
||||
public KeyBinding(string id, string description, KeyCode defaultKey)
|
||||
{
|
||||
Id = id;
|
||||
Description = description;
|
||||
Default = defaultKey;
|
||||
}
|
||||
|
||||
private void Mod_OnMenuLoad()
|
||||
string Pref { get { return "MSCO_Key_" + Id; } }
|
||||
|
||||
public KeyCode Key
|
||||
{
|
||||
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
|
||||
key = KeyCode.None;
|
||||
if (string.IsNullOrEmpty(text)) return false;
|
||||
try
|
||||
{
|
||||
key = (KeyCode)System.Enum.Parse(typeof(KeyCode), text.Trim(), true);
|
||||
return true;
|
||||
}
|
||||
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
|
||||
catch { return false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-35
@@ -42,12 +42,8 @@
|
||||
<HintPath>F:\SteamLibrary\steamapps\common\My Summer Car\mysummercar_Data\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="MSCLoader">
|
||||
<HintPath>F:\SteamLibrary\steamapps\common\My Summer Car\mysummercar_Data\Managed\MSCLoader.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>F:\SteamLibrary\steamapps\common\My Summer Car\mysummercar_Data\Managed\Newtonsoft.Json.dll</HintPath>
|
||||
<HintPath>lib\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
@@ -67,7 +63,7 @@
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>F:\SteamLibrary\steamapps\common\My Summer Car\mysummercar_Data\Managed\0Harmony.dll</HintPath>
|
||||
<HintPath>lib\0Harmony.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
@@ -82,7 +78,7 @@
|
||||
<Compile Include="Toasts.cs" />
|
||||
<Compile Include="PlayerNeeds.cs" />
|
||||
<Compile Include="Favorites.cs" />
|
||||
<Compile Include="MpCommand.cs" />
|
||||
<Compile Include="Bootstrap.cs" />
|
||||
<Compile Include="Commands.cs" />
|
||||
<Compile Include="MscoLog.cs" />
|
||||
<Compile Include="ItemSpawner.cs" />
|
||||
@@ -120,35 +116,11 @@
|
||||
<Compile Include="RemotePlayer.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<MSCMODSFOLDER>C:\Users\nico\Documents\MySummerCar\Mods</MSCMODSFOLDER>
|
||||
<MWCMODSFOLDER>NONE</MWCMODSFOLDER>
|
||||
<ABFOLDER>NONE</ABFOLDER>
|
||||
<PostBuildEvent>
|
||||
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
|
||||
)
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- Zum Testen: MSCO.dll direkt in den Spielordner (My Summer Car\MSCO) - läuft das Spiel, ist sie gesperrt -->
|
||||
<Target Name="CopyToGame" AfterTargets="Build">
|
||||
<Copy SourceFiles="$(TargetPath)" DestinationFolder="F:\SteamLibrary\steamapps\common\My Summer Car\MSCO" ContinueOnError="true" Condition="Exists('F:\SteamLibrary\steamapps\common\My Summer Car')" />
|
||||
</Target>
|
||||
<!-- Release-Build: neue Version automatisch auf den Keymaster laden (nur mit Release-Token, siehe release.ps1) -->
|
||||
<Target Name="MscoRelease" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="powershell -NoProfile -ExecutionPolicy Bypass -File "$(MSBuildProjectDirectory)\release.ps1" -Product mod -File "$(TargetPath)"" ContinueOnError="true" />
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Reflection;
|
||||
using HutongGames.PlayMaker;
|
||||
using HutongGames.PlayMaker.Actions;
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
using MSCLoader;
|
||||
|
||||
namespace MSCO
|
||||
{
|
||||
/// <summary>MSCLoader-Konsole: "mp <befehl>" - gleiche Befehle wie in der F7-Konsole.</summary>
|
||||
public class MpCommand : ConsoleCommand
|
||||
{
|
||||
public override string Name => "mp";
|
||||
public override string Help => "MSCO commands, e.g. mp help | mp connect <host[:port]> | mp save (or press F7)";
|
||||
|
||||
public override void Run(string[] args)
|
||||
{
|
||||
Commands.Execute(args, line => ModConsole.Print("[MSCO] " + line));
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -4,7 +4,7 @@ using UnityEngine;
|
||||
namespace MSCO
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <summary>F7 Konsole, T Chat (Tasten in den MSCLoader-Einstellungen änderbar).</summary>
|
||||
/// <summary>F7 Konsole, T Chat (Tasten mit "bind" in der Konsole änderbar).</summary>
|
||||
void UpdateOverlayKeys()
|
||||
{
|
||||
if (MSCO.ConsoleKey != null && MSCO.ConsoleKey.GetKeybindDown()) overlays.ToggleConsole();
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using HutongGames.PlayMaker;
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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
|
||||
`<Spielordner>\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
|
||||
`<Spielordner>\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 | `<Spielordner>\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 `<Spielordner>\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 |
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Reflection;
|
||||
using Harmony;
|
||||
using HutongGames.PlayMaker;
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using MSCLoader;
|
||||
using Steamworks;
|
||||
|
||||
namespace MSCO
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using HutongGames.PlayMaker;
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using HutongGames.PlayMaker;
|
||||
using MSCLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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.
|
||||
Reference in New Issue
Block a user