From f707e67e5c67a74b7c32817aae3376b2dab9d6d9 Mon Sep 17 00:00:00 2001 From: MrMaho Date: Fri, 2 Oct 2026 17:44:03 +0200 Subject: [PATCH] Doors on all vehicles: no more part-logic FSMs in DoorSync, single sender for hinges - DoorSync matched every FSM with door/hood/lid/trunk in its name, including the door parts' removal/assembly/bolt/paint FSMs and trigger_ objects, and forced their states at the other players: doors hung crooked, snapped back or came off. Those are excluded now (assembly runs via FsmSync). - HingeSync: on a parked vehicle everyone nearby sent the angle, so doors ping-ponged. Now only the player who clicked near the door (4 s) sends; on a driven vehicle the driver sends; received angles are held 3 s. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 6 ++++++ DoorSync.cs | 16 ++++++++++++++++ HingeSync.cs | 36 ++++++++++++++++++++++++++++++++---- MultiplayerManager.cs | 3 +++ 4 files changed, 57 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46d4e48..9be6431 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,12 @@ - Konsole (F7): `model classic` zeigt wieder die MSCO-Figur, `model game` die MSC-Menschen; `rig` zeigt, wer welches Modell hat. Findet MSCO den Körper nicht, bleibt automatisch die MSCO-Figur +**Türen an allen Fahrzeugen** +- Türen hingen schief, sprangen zurück oder lösten sich: der Tür-Sync erfasste auch die FSMs zum An-/Abbauen, + Festschrauben und Lackieren der Tür-Teile und erzwang deren Zustände beim Mitspieler. Jetzt nur noch Öffnen/Schließen +- Türen schaukelten hin und her: an einem stehenden Auto schickte jeder in der Nähe den Türwinkel zurück. Jetzt schickt + nur, wer an der Tür geklickt hat (bzw. beim fahrenden Auto der Fahrer); empfangene Winkel werden länger gehalten + **Mitfahren** - **Wer im Fahrzeug ist, fährt mit - genau an seiner Stelle**: Kopf in der Kabine, in der offenen Tür oder auf der Ladefläche -> die Position im Fahrzeug wird festgehalten, kein Umsetzen auf einen berechneten Sitz. Geht auch, wenn diff --git a/DoorSync.cs b/DoorSync.cs index b3c5d0a..45e7be4 100644 --- a/DoorSync.cs +++ b/DoorSync.cs @@ -16,6 +16,13 @@ namespace MSCO public class DoorSync { static readonly string[] Keywords = { "door", "gate", "hood", "bonnet", "trunk", "lid", "hatch" }; + // Nicht die FSMs zum An-/Abbauen, Festschrauben, Lackieren, Speichern ... der Tür-TEILE: deren Zustände wurden + // beim Mitspieler erzwungen - Türen hingen schief, lösten sich oder sprangen zurück. Montage läuft über FsmSync. + static readonly string[] ExcludedFsms = + { + "removal", "assembly", "assemble", "boltcheck", "bolt", "screw", "paint", "data", "save", "load", "wiring", + "setup", "damage", "tightness", "detach", "attach", "install" + }; const float Cooldown = 1.5f; // Folge-Zustände der Animation nicht nochmal senden const float RescanInterval = 10f; // neue Objekte (z.B. angebaute Autotüren) aufnehmen @@ -102,6 +109,7 @@ namespace MSCO string root = fsm.transform.root.name; if (root == "PLAYER" || root.StartsWith("MSCO_")) continue; if (!Matches(fsm.gameObject.name) && !Matches(fsm.FsmName) && !Matches(fsm.transform.parent != null ? fsm.transform.parent.name : "")) continue; + if (IsPartLogic(fsm)) continue; string key = FsmSync.PathOf(fsm.transform) + "|" + fsm.FsmName; Tracked t; @@ -110,6 +118,14 @@ namespace MSCO } } + static bool IsPartLogic(PlayMakerFSM fsm) + { + string f = fsm.FsmName.ToLower(), o = fsm.gameObject.name.ToLower(); + if (o.StartsWith("trigger_") || o.StartsWith("bolt")) return true; + foreach (string x in ExcludedFsms) if (f.Contains(x)) return true; + return false; + } + static bool Matches(string name) { if (string.IsNullOrEmpty(name)) return false; diff --git a/HingeSync.cs b/HingeSync.cs index 284756b..f89c4d6 100644 --- a/HingeSync.cs +++ b/HingeSync.cs @@ -19,7 +19,12 @@ namespace MSCO const float SendInterval = 0.1f; const float MinAngle = 2f; // Grad - kleiner ist Zittern const float NearRange = 4f; // so nah muss man an einer Tür stehen, um sie zu bewegen - const float ApplyHold = 1.5f; // so lange nach einer Nachricht die Feder halten und selbst nicht senden + const float ApplyHold = 3f; // so lange nach einer Nachricht die Feder halten und selbst nicht senden + // Steht das Fahrzeug, schickt nur, wer die Tür gerade selbst bewegt hat (Klick in der Nähe). Vorher schickte + // jeder in der Nähe: setzte sich die Tür beim anderen nach dem Übernehmen etwas anders, schickte er zurück - + // die Türen schaukelten hin und her. + const float InteractRange = 2.5f; + const float InteractAuthority = 4f; // so lange nach dem Klick (Tür schwingt aus) const float SpringForce = 120f; const float SpringDamper = 12f; @@ -34,6 +39,7 @@ namespace MSCO public float TargetAngle; public float TargetTime = -100f; public bool Driving; // Feder gerade von uns gesetzt + public float LocalAuthorityUntil = -100f; public bool OrigUseSpring; public JointSpring OrigSpring; } @@ -69,10 +75,13 @@ namespace MSCO foreach (Hinge h in hinges.Values) { if (h.Joint == null || h.Rb == null || !h.Rb.gameObject.activeInHierarchy) continue; - if (Time.time - h.TargetTime < ApplyHold) continue; // gerade von anderen gesetzt + bool mine = Time.time < h.LocalAuthorityUntil; + if (!mine && Time.time - h.TargetTime < ApplyHold) continue; // gerade von anderen gesetzt int owner = objects.VehicleOwner(h.Root); - if (owner != SyncedBody.NoOwner && owner != localId) continue; // der Fahrer schickt - if (owner == SyncedBody.NoOwner && (h.Rb.position - playerPos).sqrMagnitude > NearRange * NearRange) continue; + // Fährt jemand: der Fahrer schickt (Türen schwingen während der Fahrt). Hat man selbst gerade an der Tür + // geklickt, schickt man auch - sonst würde die Feder sie beim Fahrer gleich wieder zudrücken. + if (!mine && owner != SyncedBody.NoOwner && owner != localId) continue; + if (!mine && owner == SyncedBody.NoOwner) { h.SentAngle = SafeAngle(h, h.SentAngle); continue; } // stehendes Auto: nur wer klickt float angle = h.Joint.angle; if (float.IsNaN(angle) || float.IsInfinity(angle)) continue; @@ -90,6 +99,24 @@ namespace MSCO })); } + /// Jedes Frame: Klick (linke Maustaste / Benutzen) in der Nähe einer Tür = wir bewegen sie gerade. + public void NoteInteraction(Vector3 playerPos) + { + if (!Input.GetMouseButtonDown(0) && !Input.GetKeyDown(KeyCode.F)) return; + foreach (Hinge h in hinges.Values) + { + if (h.Rb == null || (h.Rb.worldCenterOfMass - playerPos).sqrMagnitude > InteractRange * InteractRange) continue; + h.LocalAuthorityUntil = Time.time + InteractAuthority; + h.TargetTime = -100f; // eigene Bewegung: keine Feder mehr auf den alten Winkel + } + } + + static float SafeAngle(Hinge h, float fallback) + { + float a = h.Joint.angle; + return float.IsNaN(a) || float.IsInfinity(a) ? fallback : a; + } + public void Handle(BinaryReader r) { int count = r.ReadInt32(); @@ -100,6 +127,7 @@ namespace MSCO Hinge h; if (!hinges.TryGetValue(key, out h)) { nextScan = 0f; continue; } if (float.IsNaN(angle) || float.IsInfinity(angle) || Mathf.Abs(angle) > 180f) continue; + if (Time.time < h.LocalAuthorityUntil) continue; // wir bewegen sie gerade selbst h.TargetAngle = angle; h.TargetTime = Time.time; h.SentAngle = angle; // nicht als eigene Bewegung zurückschicken diff --git a/MultiplayerManager.cs b/MultiplayerManager.cs index c1305b1..8cb47c5 100644 --- a/MultiplayerManager.cs +++ b/MultiplayerManager.cs @@ -1883,6 +1883,9 @@ namespace MSCO } else if (IsPeerReady && MenuHelper.InGame && localPlayer != null && !overlays.AnyOpen) passengerResult = passenger.AutoUpdate(localPlayer, playerCamera, objects, players); // in die Beifahrertür treten + // Klick an einer Fahrzeugtür: wir bewegen sie (nur dann wird ihr Winkel geschickt, siehe HingeSync) + if (MenuHelper.InGame && localPlayer != null && !overlays.AnyOpen) + hinges.NoteInteraction(playerCamera != null ? playerCamera.transform.position : localPlayer.position); if (passengerResult != null) { SetStatus(passengerResult);