2.10.8: fewer hitches
- Sending on a background thread (the game thread blocked whenever the TCP buffer was full, e.g. while uploading the save); small frames are batched - Server save requests: routine saves wait for a calm moment (not while driving fast) and are announced; urgent flag from server 2.10.5 - Dynamic built-in font for all MSCO GUI (Unity logged hundreds of "Font size and style overrides" warnings with stutters) - Admin VEHICLE tab rescans every 30 s / after actions instead of every 5 s; time/weather FSM search less often - Reused buffers for Build/Frame/Poll (less garbage, fewer GC pauses) - Hitch log: GC and save detection, count of hitches between reports - Show Bolt Size 1.0.1: finds the FPSCamera (Camera.main may be missing), uses MSCO's shared FSM list instead of FindObjectsOfType every 2 s Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+66
-13
@@ -1635,7 +1635,12 @@ namespace MSCO
|
||||
|
||||
case MsgType.SaveRequest:
|
||||
// Server möchte den aktuellen Spielstand (für neue Spieler / zum Sichern)
|
||||
StartCoroutine(UploadSave(r.ReadInt32()));
|
||||
{
|
||||
int requestId = r.ReadInt32();
|
||||
// Neuere Server sagen, ob es eilt (jemand tritt bei) - sonst darf auf einen ruhigen Moment gewartet werden
|
||||
bool urgent = r.BaseStream.Position >= r.BaseStream.Length || r.ReadBoolean();
|
||||
StartCoroutine(UploadSave(requestId, urgent));
|
||||
}
|
||||
break;
|
||||
|
||||
case MsgType.Reconnect:
|
||||
@@ -2290,19 +2295,34 @@ namespace MSCO
|
||||
}
|
||||
|
||||
/// <summary>Zu Beginn jedes Bilds: war das letzte Bild ein Hänger? Dann Ursache melden (höchstens alle 20 s).</summary>
|
||||
int lastGcCount = -1;
|
||||
int hitchesSinceReport;
|
||||
|
||||
void CheckHitch()
|
||||
{
|
||||
float dt = Time.unscaledDeltaTime;
|
||||
if (dt > HitchSeconds && MenuHelper.InGame && Time.realtimeSinceStartup >= nextHitchReport)
|
||||
// Lief in diesem Frame der Garbage Collector? (hält bei großem Speicher das ganze Spiel an)
|
||||
int gc = System.GC.CollectionCount(0);
|
||||
bool gcRan = lastGcCount >= 0 && gc != lastGcCount;
|
||||
lastGcCount = gc;
|
||||
if (dt > HitchSeconds && MenuHelper.InGame)
|
||||
{
|
||||
nextHitchReport = Time.realtimeSinceStartup + 20f;
|
||||
int total = Mathf.RoundToInt(dt * 1000f);
|
||||
if (frameMsco > dt * 1000f * 0.4f)
|
||||
MscoLog.Warning("[MSCO] Hitch " + total + " ms - caused by MSCO: " + slowestPart + " " + slowestMs.ToString("0") +
|
||||
" ms (MSCO total " + frameMsco.ToString("0") + " ms)");
|
||||
else
|
||||
MscoLog.Info("[MSCO] Hitch " + total + " ms - not MSCO (MSCO used " + frameMsco.ToString("0") + " ms)" +
|
||||
(Time.realtimeSinceStartup - lastSaveTriggered < 5f ? " - the game was saving" : " - the game itself (loading, saving, physics)"));
|
||||
hitchesSinceReport++;
|
||||
if (Time.realtimeSinceStartup >= nextHitchReport)
|
||||
{
|
||||
nextHitchReport = Time.realtimeSinceStartup + 20f;
|
||||
int total = Mathf.RoundToInt(dt * 1000f);
|
||||
string more = hitchesSinceReport > 1 ? " [" + hitchesSinceReport + " hitches since the last report]" : "";
|
||||
hitchesSinceReport = 0;
|
||||
// Speichern friert genau den Frame ein, in dem es ausgelöst wurde - also auch so weit zurück schauen
|
||||
bool saving = Time.realtimeSinceStartup - lastSaveTriggered < dt + 5f;
|
||||
if (frameMsco > dt * 1000f * 0.4f)
|
||||
MscoLog.Warning("[MSCO] Hitch " + total + " ms - caused by MSCO: " + slowestPart + " " + slowestMs.ToString("0") +
|
||||
" ms (MSCO total " + frameMsco.ToString("0") + " ms)" + (gcRan ? ", garbage collection ran" : "") + more);
|
||||
else
|
||||
MscoLog.Info("[MSCO] Hitch " + total + " ms - not MSCO (MSCO used " + frameMsco.ToString("0") + " ms)" +
|
||||
(saving ? " - the game was saving" : gcRan ? " - garbage collection (memory cleanup)" : " - the game itself (loading, physics)") + more);
|
||||
}
|
||||
}
|
||||
frameMsco = 0;
|
||||
slowestMs = 0;
|
||||
@@ -2490,9 +2510,30 @@ namespace MSCO
|
||||
/// genau die aktuelle Welt - Schrauben, Teile, alles - statt eines alten Stands mit nachgespielten Aktionen.
|
||||
/// Der eigene Spielstand ist davon nicht betroffen: er liegt gesichert im Backup und kommt im Hauptmenü zurück.
|
||||
/// </summary>
|
||||
System.Collections.IEnumerator UploadSave(int requestId)
|
||||
System.Collections.IEnumerator UploadSave(int requestId, bool urgent)
|
||||
{
|
||||
if (!MenuHelper.InGame || !dedicated || session == null) yield break;
|
||||
// Speichern lässt das Spiel einige Sekunden hängen: bei einer Routine-Anfrage nicht mitten in schneller Fahrt,
|
||||
// sondern einen ruhigen Moment abwarten (höchstens 20 s - der Server wartet länger)
|
||||
if (!urgent)
|
||||
{
|
||||
float giveUp = Time.realtimeSinceStartup + 20f;
|
||||
while (Time.realtimeSinceStartup < giveUp && localPlayer != null && session != null)
|
||||
{
|
||||
Vector3 from = localPlayer.position;
|
||||
float t0 = Time.realtimeSinceStartup;
|
||||
while (Time.realtimeSinceStartup < t0 + 0.5f) yield return null;
|
||||
if (localPlayer == null) break;
|
||||
float speed = (localPlayer.position - from).magnitude / Mathf.Max(0.05f, Time.realtimeSinceStartup - t0);
|
||||
if (speed < 3f) break;
|
||||
}
|
||||
if (session == null || !MenuHelper.InGame) yield break;
|
||||
}
|
||||
// Erst den Hinweis zeigen, dann speichern (sonst friert das Bild ein, bevor man ihn sieht)
|
||||
centerMessage = "Saving the world for the server ...";
|
||||
centerMessageUntil = Time.realtimeSinceStartup + 4f;
|
||||
yield return null;
|
||||
yield return null;
|
||||
lastSaveTriggered = Time.realtimeSinceStartup;
|
||||
PlayMakerFSM.BroadcastEvent("SAVEGAME");
|
||||
float until = Time.realtimeSinceStartup + 3f; // das Spiel schreibt die Dateien über mehrere Frames
|
||||
@@ -2630,10 +2671,21 @@ namespace MSCO
|
||||
void OnGUI()
|
||||
{
|
||||
PartStart();
|
||||
// Eigene dynamische Schrift (siehe UiTheme.DynamicFont); danach wieder die bisherige
|
||||
GUISkin skin = GUI.skin;
|
||||
Font previousFont = skin.font;
|
||||
Font font = UiTheme.DynamicFont;
|
||||
if (font != null) skin.font = font;
|
||||
try { DrawGui(); }
|
||||
finally { PartEnd("interface (OnGUI)"); }
|
||||
finally
|
||||
{
|
||||
skin.font = previousFont;
|
||||
PartEnd("interface (OnGUI)");
|
||||
}
|
||||
}
|
||||
|
||||
string centerMessageSource, centerMessageUpper; // Großschreibung nur einmal pro Meldung (nicht jedes Frame)
|
||||
|
||||
void DrawGui()
|
||||
{
|
||||
InputLock.KeepCursorFree();
|
||||
@@ -2652,7 +2704,8 @@ namespace MSCO
|
||||
{
|
||||
int oldSize = savingStyle.fontSize;
|
||||
savingStyle.fontSize = 30;
|
||||
GUI.Label(new Rect(0, Screen.height / 2f - 40, Screen.width, 80), centerMessage.ToUpper(), savingStyle);
|
||||
if (!ReferenceEquals(centerMessage, centerMessageSource)) { centerMessageSource = centerMessage; centerMessageUpper = centerMessage.ToUpper(); }
|
||||
GUI.Label(new Rect(0, Screen.height / 2f - 40, Screen.width, 80), centerMessageUpper, savingStyle);
|
||||
savingStyle.fontSize = oldSize;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user