diff --git a/MODDING.md b/MODDING.md index 7fe0d86..61dffaf 100644 --- a/MODDING.md +++ b/MODDING.md @@ -28,6 +28,22 @@ steht, welche Mods sie nutzen, und es gibt Filter *VANILLA* / *MODDED*. > Mods sind Programme und laufen mit vollen Rechten auf dem PC der Spieler. Serverbetreiber: nur Mods anbieten, denen ihr > vertraut. Spieler: nur auf Servern zustimmen, denen ihr vertraut. +## Mod veröffentlichen (Modliste auf msco.mbm.wtf/mods) + +Im MSCO Launcher unter **Mods → Hochladen**: DLL wählen (Name, Version und Beschreibung werden aus den +Assembly-Attributen `AssemblyProduct`, `AssemblyInformationalVersion` und `AssemblyDescription` vorgeschlagen), eine +**Mod-ID** vergeben (3–40 Zeichen, `a-z 0-9 _ . -`, z.B. `showboltsize`) und hochladen. Hochladen geht mit dem +Launcher-Konto; eine Mod-ID gehört danach dir. + +Jede Version wird von einem MSCO-Admin geprüft (Admin-Bereich → *Mods von Spielern*) und ist erst danach öffentlich: +auf und im Launcher unter **Mods → Durchsuchen** (ein Klick installiert, SHA-256 wird +geprüft, Updates werden angezeigt). Eine neue Version braucht dieselbe Mod-ID und eine höhere Versionsnummer; bis sie +freigegeben ist, bleibt die alte öffentlich. Den Status (wartet, öffentlich, abgelehnt mit Grund) siehst du unter +**Meine Uploads**. Höchstens 10 MB pro Datei. + +Beispiel mit Quellcode: [`examples/ShowBoltSize`](examples/ShowBoltSize) zeigt unter dem Fadenkreuz die Größe der +Schraube, auf die man schaut. + ## Eine Mod bauen Vorlage: [`examples/HelloMod`](examples/HelloMod) – Projekt (.NET Framework 3.5) mit Verweisen auf `UnityEngine.dll` diff --git a/examples/ShowBoltSize/ShowBoltSize.cs b/examples/ShowBoltSize/ShowBoltSize.cs new file mode 100644 index 0000000..9504df0 --- /dev/null +++ b/examples/ShowBoltSize/ShowBoltSize.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; +using System.Reflection; +using HutongGames.PlayMaker; +using MSCO; +using UnityEngine; + +[assembly: AssemblyTitle("Show Bolt Size")] +[assembly: AssemblyProduct("Show Bolt Size")] +[assembly: AssemblyDescription("Shows the size of the bolt you look at, so you pick the right wrench.")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyInformationalVersion("1.0.0")] + +namespace ShowBoltSize +{ + /// + /// Zeigt unter dem Fadenkreuz die Größe der Schraube, auf die man schaut ("10 mm"). Jede Schraube hat die FSM "Screw" + /// mit der Variable "BoltSize". Deren Kollider sind nur mit Werkzeug in der Hand aktiv - deshalb kein Raycast, sondern: + /// die Schraube, die am nächsten an der Blickrichtung liegt (bis 1,3 m). Nur Anzeige, ändert nichts am Spiel. + /// + public class ShowBoltSize : MscoMod + { + public override string ID { get { return "showboltsize"; } } + public override string Name { get { return "Show Bolt Size"; } } + public override string Version { get { return "1.0.0"; } } + public override string Author { get { return "MBM"; } } + + const float MaxDistance = 1.3f; + const float BoltRadius = 0.025f; // so groß wirkt eine Schraube beim Zielen + const float ScanInterval = 2f; + + sealed class Bolt + { + public Transform Transform; + public FsmFloat SizeF; + public FsmInt SizeI; + } + + readonly List bolts = new List(); + bool inGame; + float nextScan; + string label; + GUIStyle style; + + public override void OnMenuLoad() { inGame = false; bolts.Clear(); label = null; } + public override void OnGameLoad() { inGame = true; nextScan = 0f; } + + public override void Update() + { + label = null; + if (!inGame) return; + Camera cam = Camera.main; + if (cam == null) return; + if (Time.realtimeSinceStartup >= nextScan) Scan(); + + Transform eye = cam.transform; + Bolt best = null; + float bestAngle = float.MaxValue; + foreach (Bolt b in bolts) + { + if (b.Transform == null || !b.Transform.gameObject.activeInHierarchy) continue; + Vector3 to = b.Transform.position - eye.position; + float distance = to.magnitude; + if (distance > MaxDistance || distance < 0.05f) continue; + float angle = Vector3.Angle(eye.forward, to); + float limit = Mathf.Atan2(BoltRadius, distance) * Mathf.Rad2Deg + 0.5f; + if (angle < limit && angle < bestAngle) + { + bestAngle = angle; + best = b; + } + } + if (best != null) label = Describe(best); + } + + void Scan() + { + nextScan = Time.realtimeSinceStartup + ScanInterval; + bolts.Clear(); + foreach (PlayMakerFSM fsm in Object.FindObjectsOfType()) + { + if (fsm == null || fsm.FsmName != "Screw") continue; + FsmFloat f = fsm.FsmVariables.FindFsmFloat("BoltSize"); + FsmInt i = fsm.FsmVariables.FindFsmInt("BoltSize"); + if (f == null && i == null) continue; + bolts.Add(new Bolt { Transform = fsm.transform, SizeF = f, SizeI = i }); + } + } + + /// Größe in mm. Das Spiel speichert sie je nach Schraube als 10 oder als 1.0 (= 10 mm). + static string Describe(Bolt b) + { + float value = b.SizeF != null ? b.SizeF.Value : b.SizeI.Value; + if (value <= 0f) return null; + float mm = value < 2.5f ? value * 10f : value; + return Mathf.RoundToInt(mm) + " mm"; + } + + public override void OnGUI() + { + if (label == null) return; + if (style == null) + { + style = new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleCenter, fontSize = 16, fontStyle = FontStyle.Bold }; + style.normal.textColor = Color.white; + } + var r = new Rect(Screen.width / 2f - 50f, Screen.height / 2f + 22f, 100f, 26f); + Color old = GUI.color; + GUI.color = new Color(0f, 0f, 0f, 0.6f); + GUI.DrawTexture(r, Texture2D.whiteTexture); + GUI.color = old; + GUI.Label(r, label, style); + } + } +} diff --git a/examples/ShowBoltSize/ShowBoltSize.csproj b/examples/ShowBoltSize/ShowBoltSize.csproj new file mode 100644 index 0000000..3621f48 --- /dev/null +++ b/examples/ShowBoltSize/ShowBoltSize.csproj @@ -0,0 +1,42 @@ + + + + + + Release + AnyCPU + Library + ShowBoltSize + ShowBoltSize + v3.5 + Unity Full v3.5 + 13 + bin\$(Configuration)\ + none + true + F:\SteamLibrary\steamapps\common\My Summer Car + + + + + $(GamePath)\mysummercar_Data\Managed\UnityEngine.dll + False + + + $(GamePath)\mysummercar_Data\Managed\PlayMaker.dll + False + + + $(GamePath)\MSCO\MSCO.dll + False + + + + + + +