diff --git a/ObjectSync.cs b/ObjectSync.cs index 5f3c519..69a92da 100644 --- a/ObjectSync.cs +++ b/ObjectSync.cs @@ -22,6 +22,9 @@ namespace MSCO public int OwnerId = NoOwner; public bool OwnerActive; // Besitzer hält/fährt es gerade aktiv public bool WasKinematic; // Zustand bevor ein anderer Spieler es übernommen hat + // Angebaute Teile eines Fahrzeugs (eigene Rigidbodies mit Gelenken), solange ein anderer fährt: kinematisch + public Dictionary FrozenParts; + public float NextPartScan; public float StillTime; public float NoMotionClaimUntil; // kurz nach einer Übergabe nicht wegen Nachfedern/Nachrollen übernehmen @@ -177,7 +180,7 @@ namespace MSCO public void Reset() { foreach (SyncedBody b in byId.Values) - if (IsRemoteOwned(b) && b.Rb != null) b.Rb.isKinematic = b.WasKinematic; + if (IsRemoteOwned(b) && b.Rb != null) RestoreKinematic(b); byId.Clear(); byRb.Clear(); rejected.Clear(); @@ -194,7 +197,7 @@ namespace MSCO foreach (SyncedBody b in byId.Values) { if (b.OwnerId != playerId || b.Rb == null) continue; - b.Rb.isKinematic = b.WasKinematic; + RestoreKinematic(b); b.OwnerId = SyncedBody.NoOwner; b.NoMotionClaimUntil = Time.time + HandoverCooldown; } @@ -290,6 +293,7 @@ namespace MSCO foreach (SyncedBody b in byId.Values) { if (!IsRemoteOwned(b) || b.Rb == null) continue; + if (b.IsVehicle && Time.time >= b.NextPartScan) FreezeParts(b); if (Time.time - b.AvatarHoldTime < 0.2f) continue; // sitzt gerade in der Hand eines Mitspielers if ((b.Rb.position - b.TargetPos).sqrMagnitude > SnapDistance * SnapDistance) { @@ -333,7 +337,7 @@ namespace MSCO void Claim(SyncedBody b, bool active) { - if (IsRemoteOwned(b)) b.Rb.isKinematic = b.WasKinematic; + if (IsRemoteOwned(b)) RestoreKinematic(b); b.OwnerId = LocalId; b.OwnerActive = active; b.StillTime = 0f; @@ -362,8 +366,7 @@ namespace MSCO if (b.OwnerId == ownerId) return; if (!IsRemoteOwned(b)) { - b.WasKinematic = b.Rb.isKinematic; - b.Rb.isKinematic = true; + FreezeForRemote(b); b.TargetPos = b.Rb.position; b.TargetRot = b.Rb.rotation; } @@ -372,11 +375,53 @@ namespace MSCO void SetFree(SyncedBody b) { - if (IsRemoteOwned(b)) b.Rb.isKinematic = b.WasKinematic; + if (IsRemoteOwned(b)) RestoreKinematic(b); b.OwnerId = SyncedBody.NoOwner; b.NoMotionClaimUntil = Time.time + HandoverCooldown; } + /// + /// Ein anderer Spieler bewegt das Objekt: bei uns nur noch folgen (kinematisch). Bei Fahrzeugen auch alle + /// angebauten Teile - die hängen in MSC mit Gelenken (mit Bruchkraft) am Auto. Würde nur das Auto ruckartig + /// versetzt, rissen die Gelenke und das Auto fiele auseinander. + /// + void FreezeForRemote(SyncedBody b) + { + b.WasKinematic = b.Rb.isKinematic; + b.Rb.isKinematic = true; + if (b.IsVehicle) FreezeParts(b); + } + + void FreezeParts(SyncedBody b) + { + b.NextPartScan = Time.time + 1f; + if (b.FrozenParts == null) b.FrozenParts = new Dictionary(); + foreach (Rigidbody part in b.Rb.GetComponentsInChildren()) + { + if (part == b.Rb || b.FrozenParts.ContainsKey(part)) continue; + b.FrozenParts[part] = part.isKinematic; + part.isKinematic = true; + } + } + + /// Wieder selbst simulieren: Auto und angebaute Teile zurück auf ihren vorherigen Zustand. + void RestoreKinematic(SyncedBody b) + { + if (b.Rb != null) b.Rb.isKinematic = b.WasKinematic; + if (b.FrozenParts == null) return; + foreach (KeyValuePair kv in b.FrozenParts) + { + if (kv.Key == null) continue; + kv.Key.isKinematic = kv.Value; + if (!kv.Value) + { + kv.Key.velocity = Vector3.zero; // keinen Schwung aus dem Folgen mitnehmen + kv.Key.angularVelocity = Vector3.zero; + } + } + b.FrozenParts = null; + } + void SendOwnedStates() { sendList.Clear(); @@ -450,7 +495,7 @@ namespace MSCO if (!IsValidPose(pos, rot)) { SetFree(b); return; } b.Rb.transform.position = pos; b.Rb.transform.rotation = rot; - b.Rb.isKinematic = b.WasKinematic; + RestoreKinematic(b); if (!b.Rb.isKinematic) { b.Rb.velocity = vel; diff --git a/VehicleStateSync.cs b/VehicleStateSync.cs index 5874d62..0e978af 100644 --- a/VehicleStateSync.cs +++ b/VehicleStateSync.cs @@ -21,13 +21,14 @@ namespace MSCO static readonly string[] Keywords = { "fuel", "oil", "coolant", "water", "fluid", "brake", "clutchfluid", "battery", "charge", - "bolt", "tight", "damage", "wear", "condition", "odo", "km", "dirt", "paint", "color", "colour", + "damage", "wear", "condition", "odo", "km", "dirt", "paint", "color", "colour", "tune", "tuning", "ratio", "broken", "fixed", "flat", "pressure", "level", "mixture", "timing", "idle", "air", "jet", "spark", "gap", "rust", "health", "burn", "cool", "temp" }; // Montiert-Flags nicht direkt setzen: das echte Anbauen läuft über FsmSync (Events) - static readonly string[] Excluded = { "install", "rpm", "speed", "steer", "throttle", "gear", "raycast", "distance" }; + // Schrauben/Festigkeit laufen über FsmSync (Events) - ein falscher Wert hier würde Teile lockern und abfallen lassen + static readonly string[] Excluded = { "install", "bolt", "tight", "detach", "attach", "rpm", "speed", "steer", "throttle", "gear", "raycast", "distance" }; const float ScanInterval = 10f; const float CheckInterval = 0.5f;