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 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 17:44:03 +02:00
co-authored by Claude Opus 5.5
parent dd31587d61
commit f707e67e5c
4 changed files with 57 additions and 4 deletions
+32 -4
View File
@@ -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
}));
}
/// <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;
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