From 9b8c64d0c6166d9e6b4d83871d3bd14f19adc393 Mon Sep 17 00:00:00 2001 From: MrMaho Date: Sun, 27 Sep 2026 15:03:45 +0200 Subject: [PATCH] Performance: time-sliced checks for idle objects, fewer allocations, rarer damage checks for parked cars Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 6 ++++++ DamageSync.cs | 8 ++++++-- ObjectSync.cs | 11 +++++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 249b7bd..b1862b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,12 @@ Server und Mod müssen beide 2.8 sein (Server: `git pull && docker compose up -d - **Verkehr**: NPC-Autos fahren bei allen an derselben Stelle (der erste Spieler simuliert, die anderen folgen) - `vehicles` in der F7-Konsole zeigt, wie viele Karosserie-Meshes, Job-Werte und Verkehrsautos synchronisiert werden +**Leistung** +- Mod: herumliegende Objekte werden nur noch jedes 4. Frame geprüft (eigene/gehaltene/gefahrene weiterhin jedes Frame), + weniger Speicher-Allokationen pro Frame, Gelenke fremd gefahrener Autos seltener geprüft +- Server: Nachrichten an alle werden nur einmal verpackt; der Server wartet auf eingehende Daten statt fest zu schlafen + (geringere Verzögerung, fast keine CPU-Last im Leerlauf) + ## 2.7 Server und Mod müssen beide 2.7 sein (Server: `git pull && docker compose up -d --build`). diff --git a/DamageSync.cs b/DamageSync.cs index 7a802cf..9d69222 100644 --- a/DamageSync.cs +++ b/DamageSync.cs @@ -14,7 +14,8 @@ namespace MSCO public class DamageSync { const float ScanInterval = 10f; - const float CheckInterval = 1f; + const float CheckInterval = 1f; // Fahrzeuge, die wir fahren + const float FreeCheckInterval = 5f; // geparkte Fahrzeuge (Unfall nur durch Anstoßen) seltener const float MinMove = 0.002f; const int MaxPerMessage = 4000; @@ -31,7 +32,7 @@ namespace MSCO readonly Dictionary meshes = new Dictionary(); readonly HashSet seen = new HashSet(); readonly List changed = new List(); - float nextScan, nextCheck; + float nextScan, nextCheck, nextFreeCheck; static List types; public int Count { get { return meshes.Count; } } @@ -52,12 +53,15 @@ namespace MSCO } if (Time.time < nextCheck) return; nextCheck = Time.time + CheckInterval; + bool checkFree = Time.time >= nextFreeCheck; + if (checkFree) nextFreeCheck = Time.time + FreeCheckInterval; foreach (DamageMesh m in meshes.Values) { if (m.Filter == null) continue; int owner = objects.VehicleOwner(m.Root); if (owner != SyncedBody.NoOwner && owner != localId) continue; // der Fahrer schickt die Schäden + if (owner == SyncedBody.NoOwner && !checkFree) continue; Mesh mesh = m.Filter.sharedMesh; if (mesh == null) continue; diff --git a/ObjectSync.cs b/ObjectSync.cs index 09f16c8..5052a90 100644 --- a/ObjectSync.cs +++ b/ObjectSync.cs @@ -129,6 +129,8 @@ namespace MSCO float loadTime; float nextScan; + int frame; + readonly List drivenList = new List(); float sendTimer; FsmGameObject pickedObject; @@ -191,7 +193,8 @@ namespace MSCO /// Fahrzeuge, die gerade ein anderer Spieler aktiv fährt. public List RemoteDrivenVehicles() { - var list = new List(); + var list = drivenList; // wird jedes Frame gebraucht: Liste wiederverwenden + list.Clear(); foreach (SyncedBody b in byId.Values) if (b.IsVehicle && IsRemoteOwned(b) && b.OwnerActive && b.Rb != null) list.Add(b); return list; @@ -296,8 +299,12 @@ namespace MSCO bool motionClaimAllowed = Time.time - loadTime > MotionClaimGrace; removeList.Clear(); + frame++; foreach (SyncedBody b in byId.Values) { + // Leistung: freie Objekte (der Großteil, meist liegen sie nur herum) nur jedes 4. Frame prüfen - + // eigene, fremde, gehaltene und gefahrene jedes Frame + if (b.OwnerId == SyncedBody.NoOwner && ((b.Id ^ frame) & 3) != 0 && b != held && b != driven) continue; if (b.Rb == null) { // Ganzes Objekt weg (gegessen, getrunken, verbraucht) - nicht nur der Rigidbody (Teil angebaut). @@ -471,7 +478,7 @@ namespace MSCO void HoldParts(SyncedBody b) { - b.NextPartScan = Time.time + 1f; // später angebaute Teile ebenfalls + b.NextPartScan = Time.time + 2f; // später angebaute Teile ebenfalls if (b.HeldJoints == null) b.HeldJoints = new Dictionary(); foreach (Joint j in b.Rb.GetComponentsInChildren(true)) {