Smoother sync: predict remote objects/cars from their velocity, 30 updates/s for objects and players

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-27 09:22:07 +02:00
co-authored by Claude Opus 5.5
parent bdd86336c2
commit b853425037
2 changed files with 20 additions and 6 deletions
+1 -1
View File
@@ -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
+19 -5
View File
@@ -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;
}