MSCO 2.10.1: car doors and garage door synced, door lock fix, perf tools

- Car doors (FSM with bool "Open" and "Open door"/"Close door") are synced as open/closed:
  the receiver removes the hold joint and frees the hinge, closing runs the game's own logic
- Fix: every synced close of an already closed Satsuma door added another FixedJoint, so the
  door could not be opened anymore; extra joints are removed automatically
- Hinge sync also covers world doors/gates with hinges (garage door), interaction by bounds
- Scene name read once per frame (Application.loadedLevelName allocates a string per call)
- Console "perf" (FPS, ms per MSCO part incl. OnGUI, GC, hook calls), -msco-perf start option
- Console "fsmdump <text>" / -msco-dump: PlayMaker FSMs and hinges to MSCO\fsmdump.txt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 11:01:27 +02:00
co-authored by Claude Opus 5.5
parent 4c1366b5d9
commit adc6eff9e8
14 changed files with 429 additions and 11 deletions
+25 -5
View File
@@ -40,6 +40,7 @@ namespace MSCO
public float TargetTime = -100f;
public bool Driving; // Feder gerade von uns gesetzt
public float LocalAuthorityUntil = -100f;
public Collider Collider; // für den Abstand zum Spieler (große Türen wie das Garagentor)
public bool OrigUseSpring;
public JointSpring OrigSpring;
}
@@ -102,10 +103,13 @@ namespace MSCO
/// <summary>Jedes Frame: Klick (linke Maustaste / Benutzen) in der Nähe einer Tür = wir bewegen sie gerade.</summary>
public void NoteInteraction(Vector3 playerPos)
{
if (!Input.GetMouseButtonDown(0) && !Input.GetKeyDown(KeyCode.F)) return;
// Links öffnet, rechts schließt (Garagentor), F = Benutzen
if (!Input.GetMouseButtonDown(0) && !Input.GetMouseButtonDown(1) && !Input.GetKeyDown(KeyCode.F)) return;
foreach (Hinge h in hinges.Values)
{
if (h.Rb == null || (h.Rb.worldCenterOfMass - playerPos).sqrMagnitude > InteractRange * InteractRange) continue;
if (h.Rb == null) continue;
Vector3 near = h.Collider != null ? h.Collider.ClosestPointOnBounds(playerPos) : h.Rb.worldCenterOfMass;
if ((near - playerPos).sqrMagnitude > InteractRange * InteractRange) continue;
h.LocalAuthorityUntil = Time.time + InteractAuthority;
h.TargetTime = -100f; // eigene Bewegung: keine Feder mehr auf den alten Winkel
}
@@ -183,10 +187,17 @@ namespace MSCO
if (j == null || !seen.Add(j)) continue;
Rigidbody rb = j.GetComponent<Rigidbody>();
Rigidbody body = j.connectedBody;
if (rb == null || body == null || !IsVehicle(body.transform.root.name)) continue;
int key = Hash(FsmSync.PathOf(j.transform) + "|" + FsmSync.PathOf(body.transform));
if (rb == null) continue;
// Fahrzeugtüren/-hauben - und Türen/Tore der Welt mit Scharnier (z.B. das Garagentor)
bool vehicle = body != null && IsVehicle(body.transform.root.name);
if (!vehicle && !IsWorldDoor(j)) continue;
int key = Hash(FsmSync.PathOf(j.transform) + "|" + (body != null ? FsmSync.PathOf(body.transform) : "world"));
if (hinges.ContainsKey(key)) continue;
hinges[key] = new Hinge { Key = key, Root = body.transform.root.name, Joint = j, Rb = rb };
hinges[key] = new Hinge
{
Key = key, Root = (body != null ? body.transform : j.transform).root.name, Joint = j, Rb = rb,
Collider = rb.GetComponentInChildren<Collider>()
};
}
// Abgebaute Teile (Scharnier weg) vergessen
var gone = new List<int>();
@@ -197,6 +208,15 @@ namespace MSCO
if (hinges.Count != before) MscoLog.Info("[MSCO] Vehicle doors/hood/trunk: " + hinges.Count + " synced");
}
/// <summary>Tür/Tor der Welt (nicht Verkehr/NPC-Autos, nicht der Spieler): Name enthält door/gate.</summary>
static bool IsWorldDoor(HingeJoint j)
{
string root = j.transform.root.name;
if (root == "PLAYER" || root == "NPC_CARS" || root == "TRAFFIC" || root.StartsWith("MSCO_")) return false;
string path = FsmSync.PathOf(j.transform).ToLowerInvariant();
return path.Contains("door") || path.Contains("gate");
}
static bool IsVehicle(string root)
{
foreach (string v in ObjectSync.VehicleRoots) if (root.StartsWith(v)) return true;