diff --git a/MultiplayerManager.cs b/MultiplayerManager.cs index 6770427..0f1e611 100644 --- a/MultiplayerManager.cs +++ b/MultiplayerManager.cs @@ -28,7 +28,7 @@ namespace MSCO const float PingInterval = 2f; const float LateJoinSaveDelay = 1.5f; // Host: Zeit zum Speichern, bevor der Spielstand verschickt wird const float TeleportSideOffset = 1.5f; // später Beigetretene erscheinen so weit neben dem Host - const float SendInterval = 0.05f; // 20 Updates pro Sekunde + const float SendInterval = 1f / 30f; // 30 Spieler-Updates pro Sekunde const string PrefName = "MSCO_Name"; const float NameTagHideDistance = 15f; // ab hier kein Namensschild mehr const float NameTagFadeRange = 5f; // die letzten Meter davor wird es ausgeblendet diff --git a/ObjectSync.cs b/ObjectSync.cs index 8805798..817bc29 100644 --- a/ObjectSync.cs +++ b/ObjectSync.cs @@ -37,6 +37,8 @@ namespace MSCO public Vector3 TargetPos; public Quaternion TargetRot; + public Vector3 TargetVel; // Geschwindigkeit beim Besitzer: damit wird die Position vorausberechnet + public float TargetTime; // wann TargetPos ankam public float LastRecvTime; public float AvatarHoldTime = -100f; // zuletzt von der Hand eines Mitspielers platziert @@ -63,7 +65,8 @@ namespace MSCO static readonly string[] IgnoredRoots = { "PLAYER", "TRAFFIC", "NPC_CARS" }; const float MaxSmallItemMass = 60f; // schwerere Dinge ohne ITEM/PART-Tag sind Teil der Welt - const float SendInterval = 1f / 15f; + const float SendInterval = 1f / 30f; // unbewegte Objekte werden ohnehin nicht gesendet + const float MaxExtrapolation = 0.25f; // höchstens so weit (Sekunden) in die Zukunft vorausrechnen const float KeepAliveInterval = 1f; const float ScanInterval = 3f; const float FirstScanDelay = 3f; @@ -307,15 +310,20 @@ namespace MSCO if (!IsRemoteOwned(b) || b.Rb == null || b.Attached) continue; if (b.IsVehicle && Time.time >= b.NextPartScan) HoldParts(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) + // Dort, wo das Objekt beim Besitzer JETZT ungefähr ist: letzte Position + Geschwindigkeit * Alter. + // Ohne das hinken schnelle Objekte (fahrende Autos) immer einen Paketabstand hinterher und ruckeln. + float age = Mathf.Min(Time.time - b.TargetTime, MaxExtrapolation); + Vector3 predicted = b.TargetPos + b.TargetVel * age; + if ((b.Rb.position - predicted).sqrMagnitude > SnapDistance * SnapDistance) { - b.Rb.transform.position = b.TargetPos; + b.Rb.transform.position = predicted; b.Rb.transform.rotation = b.TargetRot; } else { - b.Rb.MovePosition(Vector3.Lerp(b.Rb.position, b.TargetPos, 0.35f)); - b.Rb.MoveRotation(Quaternion.Slerp(b.Rb.rotation, b.TargetRot, 0.35f)); + float follow = b.IsVehicle ? 0.5f : 0.35f; + b.Rb.MovePosition(Vector3.Lerp(b.Rb.position, predicted, follow)); + b.Rb.MoveRotation(Quaternion.Slerp(b.Rb.rotation, b.TargetRot, follow)); } } } @@ -342,6 +350,8 @@ namespace MSCO b.Rb.transform.rotation = rot; b.TargetPos = pos; b.TargetRot = rot; + b.TargetVel = Vector3.zero; + b.TargetTime = Time.time; b.AvatarHoldTime = Time.time; } @@ -381,6 +391,8 @@ namespace MSCO FreezeForRemote(b); b.TargetPos = b.Rb.position; b.TargetRot = b.Rb.rotation; + b.TargetVel = Vector3.zero; + b.TargetTime = Time.time; } b.OwnerId = ownerId; } @@ -492,6 +504,8 @@ namespace MSCO SetRemote(b, from, b.OwnerId == from && b.OwnerActive); b.TargetPos = pos; b.TargetRot = rot; + b.TargetVel = vel.sqrMagnitude < 90f * 90f ? vel : Vector3.zero; + b.TargetTime = Time.time; } break; }