Fewer hitches: FSM scene scans less often, damage safety check one mesh at a time; hitch detector (per-subsystem timing, reports MSCO part or game) in the F7 console
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,13 @@
|
|||||||
|
|
||||||
Server und Mod müssen beide 2.8 sein (Server: `git pull && docker compose up -d --build`).
|
Server und Mod müssen beide 2.8 sein (Server: `git pull && docker compose up -d --build`).
|
||||||
|
|
||||||
|
**Weniger Hänger**
|
||||||
|
- Der Server holt sich den Spielstand nur noch, wenn sich seit dem letzten etwas geändert hat (Speichern lässt das Spiel
|
||||||
|
kurz hängen), Standard für neue Server alle 10 statt 5 Minuten
|
||||||
|
- Die teure Suche über alle PlayMaker-FSMs läuft seltener; die Schadens-Prüfung liest ab und zu nur noch ein Mesh
|
||||||
|
- Hänger-Erkennung: dauert ein Bild länger als 0,2 s, steht in der F7-Konsole, ob MSCO schuld war (und welcher Teil)
|
||||||
|
oder das Spiel selbst (z.B. beim Speichern)
|
||||||
|
|
||||||
**Behoben: Öl lief aus dem Satsuma**
|
**Behoben: Öl lief aus dem Satsuma**
|
||||||
- Beim Beitreten lief Öl aus, obwohl der Spielstand lokal dicht war: die vom Spiel selbst berechneten Werte
|
- Beim Beitreten lief Öl aus, obwohl der Spielstand lokal dicht war: die vom Spiel selbst berechneten Werte
|
||||||
`LeakOilpan`, `LeakOilfilter`, `LeakRockerCover`, `LeakHeadgasket` (und Raten wie `…LeakRate`) wurden wie echte
|
`LeakOilpan`, `LeakOilfilter`, `LeakRockerCover`, `LeakHeadgasket` (und Raten wie `…LeakRate`) wurden wie echte
|
||||||
|
|||||||
+1
-1
@@ -129,7 +129,7 @@ namespace MSCO
|
|||||||
void Scan()
|
void Scan()
|
||||||
{
|
{
|
||||||
int before = controls.Count;
|
int before = controls.Count;
|
||||||
foreach (PlayMakerFSM fsm in SceneCache.Fsms(5f))
|
foreach (PlayMakerFSM fsm in SceneCache.Fsms(20f))
|
||||||
{
|
{
|
||||||
if (fsm == null || !scanned.Add(fsm)) continue;
|
if (fsm == null || !scanned.Add(fsm)) continue;
|
||||||
string root = fsm.transform.root.name;
|
string root = fsm.transform.root.name;
|
||||||
|
|||||||
+7
-3
@@ -17,7 +17,7 @@ namespace MSCO
|
|||||||
const float CheckInterval = 0.5f; // so oft nach einem Aufprall prüfen
|
const float CheckInterval = 0.5f; // so oft nach einem Aufprall prüfen
|
||||||
const float ImpactWindow = 4f; // so lange nach einem Aufprall prüfen (Verformung läuft ein paar Frames)
|
const float ImpactWindow = 4f; // so lange nach einem Aufprall prüfen (Verformung läuft ein paar Frames)
|
||||||
const float ImpactDeltaV = 2.5f; // plötzliche Geschwindigkeitsänderung (m/s pro Frame) = Aufprall
|
const float ImpactDeltaV = 2.5f; // plötzliche Geschwindigkeitsänderung (m/s pro Frame) = Aufprall
|
||||||
const float SafetyCheckInterval = 30f; // sonst nur selten (z.B. Reparatur in der Werkstatt)
|
const float SafetyCheckInterval = 2f; // sonst nur ab und zu EIN Mesh (z.B. Reparatur in der Werkstatt) - verteilt statt alle auf einmal
|
||||||
const float MinMove = 0.002f;
|
const float MinMove = 0.002f;
|
||||||
const int MaxPerMessage = 4000;
|
const int MaxPerMessage = 4000;
|
||||||
|
|
||||||
@@ -36,6 +36,7 @@ namespace MSCO
|
|||||||
readonly HashSet<MeshFilter> seen = new HashSet<MeshFilter>();
|
readonly HashSet<MeshFilter> seen = new HashSet<MeshFilter>();
|
||||||
readonly List<int> changed = new List<int>();
|
readonly List<int> changed = new List<int>();
|
||||||
float nextScan, nextCheck, nextSafetyCheck;
|
float nextScan, nextCheck, nextSafetyCheck;
|
||||||
|
int safetyIndex;
|
||||||
// Mesh-Daten lesen ist teuer (große Arrays, Speicher-Müll) - nur nach einem Aufprall
|
// Mesh-Daten lesen ist teuer (große Arrays, Speicher-Müll) - nur nach einem Aufprall
|
||||||
readonly Dictionary<Rigidbody, Vector3> lastVelocity = new Dictionary<Rigidbody, Vector3>();
|
readonly Dictionary<Rigidbody, Vector3> lastVelocity = new Dictionary<Rigidbody, Vector3>();
|
||||||
readonly Dictionary<Rigidbody, float> lastImpact = new Dictionary<Rigidbody, float>();
|
readonly Dictionary<Rigidbody, float> lastImpact = new Dictionary<Rigidbody, float>();
|
||||||
@@ -76,16 +77,19 @@ namespace MSCO
|
|||||||
if (Time.time < nextCheck) return;
|
if (Time.time < nextCheck) return;
|
||||||
nextCheck = Time.time + CheckInterval;
|
nextCheck = Time.time + CheckInterval;
|
||||||
bool safety = Time.time >= nextSafetyCheck;
|
bool safety = Time.time >= nextSafetyCheck;
|
||||||
if (safety) nextSafetyCheck = Time.time + SafetyCheckInterval;
|
if (safety) { nextSafetyCheck = Time.time + SafetyCheckInterval; safetyIndex++; }
|
||||||
|
int index = -1;
|
||||||
|
|
||||||
foreach (DamageMesh m in meshes.Values)
|
foreach (DamageMesh m in meshes.Values)
|
||||||
{
|
{
|
||||||
|
index++;
|
||||||
if (m.Filter == null) continue;
|
if (m.Filter == null) continue;
|
||||||
|
bool safetyThis = safety && meshes.Count > 0 && index == safetyIndex % meshes.Count;
|
||||||
int owner = objects.VehicleOwner(m.Root);
|
int owner = objects.VehicleOwner(m.Root);
|
||||||
if (owner != SyncedBody.NoOwner && owner != localId) continue; // der Fahrer schickt die Schäden
|
if (owner != SyncedBody.NoOwner && owner != localId) continue; // der Fahrer schickt die Schäden
|
||||||
float impact;
|
float impact;
|
||||||
bool recentImpact = m.Body != null && lastImpact.TryGetValue(m.Body, out impact) && Time.time - impact < ImpactWindow;
|
bool recentImpact = m.Body != null && lastImpact.TryGetValue(m.Body, out impact) && Time.time - impact < ImpactWindow;
|
||||||
if (!recentImpact && !safety) continue;
|
if (!recentImpact && !safetyThis) continue;
|
||||||
|
|
||||||
Mesh mesh = m.Filter.sharedMesh;
|
Mesh mesh = m.Filter.sharedMesh;
|
||||||
if (mesh == null) continue;
|
if (mesh == null) continue;
|
||||||
|
|||||||
+1
-1
@@ -96,7 +96,7 @@ namespace MSCO
|
|||||||
|
|
||||||
void Scan()
|
void Scan()
|
||||||
{
|
{
|
||||||
foreach (PlayMakerFSM fsm in SceneCache.Fsms(5f))
|
foreach (PlayMakerFSM fsm in SceneCache.Fsms(20f))
|
||||||
{
|
{
|
||||||
if (fsm == null) continue;
|
if (fsm == null) continue;
|
||||||
string root = fsm.transform.root.name;
|
string root = fsm.transform.root.name;
|
||||||
|
|||||||
@@ -183,6 +183,7 @@ namespace MSCO
|
|||||||
public void Host(int port)
|
public void Host(int port)
|
||||||
{
|
{
|
||||||
Disconnect();
|
Disconnect();
|
||||||
|
PartStart();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
session = NetSession.StartHost(port);
|
session = NetSession.StartHost(port);
|
||||||
@@ -944,6 +945,7 @@ namespace MSCO
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
savingMessageUntil = Time.realtimeSinceStartup + 2.5f; // "SAVING GAME..." in der Bildschirmmitte
|
savingMessageUntil = Time.realtimeSinceStartup + 2.5f; // "SAVING GAME..." in der Bildschirmmitte
|
||||||
|
lastSaveTriggered = Time.realtimeSinceStartup;
|
||||||
PlayMakerFSM.BroadcastEvent("SAVEGAME");
|
PlayMakerFSM.BroadcastEvent("SAVEGAME");
|
||||||
MscoLog.Info("[MSCO] Game saved.");
|
MscoLog.Info("[MSCO] Game saved.");
|
||||||
}
|
}
|
||||||
@@ -952,6 +954,7 @@ namespace MSCO
|
|||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
|
CheckHitch();
|
||||||
MeasureFps();
|
MeasureFps();
|
||||||
// Menü-Buttons des Spiels nicht durch unser Fenster hindurch auslösen (z.B. Changelog)
|
// Menü-Buttons des Spiels nicht durch unser Fenster hindurch auslösen (z.B. Changelog)
|
||||||
// Solange das Multiplayer-Fenster offen ist, reagiert das Spielmenü (CONTINUE, QUIT ...) gar nicht;
|
// Solange das Multiplayer-Fenster offen ist, reagiert das Spielmenü (CONTINUE, QUIT ...) gar nicht;
|
||||||
@@ -1866,62 +1869,89 @@ namespace MSCO
|
|||||||
if (sendTimer >= SendInterval)
|
if (sendTimer >= SendInterval)
|
||||||
{
|
{
|
||||||
sendTimer = 0f;
|
sendTimer = 0f;
|
||||||
|
PartStart();
|
||||||
try { SendGame(MsgType.Player, BuildLocalState().Serialize()); }
|
try { SendGame(MsgType.Player, BuildLocalState().Serialize()); }
|
||||||
catch (System.Exception e) { ReportError("player state", e); }
|
catch (System.Exception e) { ReportError("player state", e); }
|
||||||
|
PartEnd("player state");
|
||||||
}
|
}
|
||||||
// Eigene Bedürfnisse (Hunger, Durst ...) pro Spieler auf dem Server sichern
|
// Eigene Bedürfnisse (Hunger, Durst ...) pro Spieler auf dem Server sichern
|
||||||
if (dedicated && worldSynced && Time.realtimeSinceStartup >= nextNeedsSend)
|
if (dedicated && worldSynced && Time.realtimeSinceStartup >= nextNeedsSend)
|
||||||
{
|
{
|
||||||
nextNeedsSend = Time.realtimeSinceStartup + NeedsInterval;
|
nextNeedsSend = Time.realtimeSinceStartup + NeedsInterval;
|
||||||
|
PartStart();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] needs = PlayerNeeds.Build();
|
byte[] needs = PlayerNeeds.Build();
|
||||||
if (needs != null) session.SendTo(NetSession.HostId, MsgType.PlayerNeeds, needs);
|
if (needs != null) session.SendTo(NetSession.HostId, MsgType.PlayerNeeds, needs);
|
||||||
}
|
}
|
||||||
catch (System.Exception e) { ReportError("player needs", e); }
|
catch (System.Exception e) { ReportError("player needs", e); }
|
||||||
|
PartEnd("player needs");
|
||||||
}
|
}
|
||||||
|
PartStart();
|
||||||
try { objects.Update(localPlayer, Time.deltaTime); }
|
try { objects.Update(localPlayer, Time.deltaTime); }
|
||||||
catch (System.Exception e) { ReportError("object sync", e); }
|
catch (System.Exception e) { ReportError("object sync", e); }
|
||||||
|
PartStart();
|
||||||
|
PartEnd("object sync");
|
||||||
try { vehicleFx.Update(objects, SendGame, Time.deltaTime, IsWorldAuthority); }
|
try { vehicleFx.Update(objects, SendGame, Time.deltaTime, IsWorldAuthority); }
|
||||||
catch (System.Exception e) { ReportError("vehicle lights/sound", e); }
|
catch (System.Exception e) { ReportError("vehicle lights/sound", e); }
|
||||||
|
PartStart();
|
||||||
|
PartEnd("vehicle lights/sound");
|
||||||
try { worldSync.Update(IsWorldAuthority, SendGame, Time.unscaledDeltaTime); }
|
try { worldSync.Update(IsWorldAuthority, SendGame, Time.unscaledDeltaTime); }
|
||||||
catch (System.Exception e) { ReportError("time/weather sync", e); }
|
catch (System.Exception e) { ReportError("time/weather sync", e); }
|
||||||
|
PartEnd("time/weather sync");
|
||||||
|
|
||||||
// Geld erst beobachten, wenn das Spiel fertig geladen ist
|
// Geld erst beobachten, wenn das Spiel fertig geladen ist
|
||||||
|
PartStart();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (objects.ScanComplete) moneySync.Begin();
|
if (objects.ScanComplete) moneySync.Begin();
|
||||||
moneySync.Update(SendGame);
|
moneySync.Update(SendGame);
|
||||||
}
|
}
|
||||||
catch (System.Exception e) { ReportError("money sync", e); }
|
catch (System.Exception e) { ReportError("money sync", e); }
|
||||||
|
PartEnd("money sync");
|
||||||
|
|
||||||
// Türen, Tore, Hauben (z.B. Garagentor)
|
// Türen, Tore, Hauben (z.B. Garagentor)
|
||||||
|
PartStart();
|
||||||
try { if (objects.ScanComplete) doorSync.Update(SendGame); }
|
try { if (objects.ScanComplete) doorSync.Update(SendGame); }
|
||||||
catch (System.Exception e) { ReportError("door sync", e); }
|
catch (System.Exception e) { ReportError("door sync", e); }
|
||||||
|
PartEnd("door sync");
|
||||||
|
|
||||||
// Gesamtzustand der Fahrzeuge (Tank, Öl, Verschleiß ...)
|
// Gesamtzustand der Fahrzeuge (Tank, Öl, Verschleiß ...)
|
||||||
|
PartStart();
|
||||||
try { if (objects.ScanComplete) vehicleState.Update(objects, localId, SendGame); }
|
try { if (objects.ScanComplete) vehicleState.Update(objects, localId, SendGame); }
|
||||||
catch (System.Exception e) { ReportError("vehicle state sync", e); }
|
catch (System.Exception e) { ReportError("vehicle state sync", e); }
|
||||||
|
PartEnd("vehicle state sync");
|
||||||
// Unfallschäden (verbeulte Karosserie)
|
// Unfallschäden (verbeulte Karosserie)
|
||||||
|
PartStart();
|
||||||
try { if (objects.ScanComplete) damageSync.Update(objects, localId, SendGame); }
|
try { if (objects.ScanComplete) damageSync.Update(objects, localId, SendGame); }
|
||||||
catch (System.Exception e) { ReportError("crash damage sync", e); }
|
catch (System.Exception e) { ReportError("crash damage sync", e); }
|
||||||
|
PartEnd("crash damage sync");
|
||||||
// Zündung, Motor, Licht, Choke ... der Fahrzeuge
|
// Zündung, Motor, Licht, Choke ... der Fahrzeuge
|
||||||
|
PartStart();
|
||||||
try { if (objects.ScanComplete && localPlayer != null) controls.Update(objects, localId, localPlayer.position, SendGame); }
|
try { if (objects.ScanComplete && localPlayer != null) controls.Update(objects, localId, localPlayer.position, SendGame); }
|
||||||
catch (System.Exception e) { ReportError("vehicle controls sync", e); }
|
catch (System.Exception e) { ReportError("vehicle controls sync", e); }
|
||||||
|
PartEnd("vehicle controls sync");
|
||||||
// Türen, Motorhaube, Kofferraum der Fahrzeuge
|
// Türen, Motorhaube, Kofferraum der Fahrzeuge
|
||||||
|
PartStart();
|
||||||
try { if (objects.ScanComplete && localPlayer != null) hinges.Update(objects, localId, localPlayer.position, Time.deltaTime, SendGame); }
|
try { if (objects.ScanComplete && localPlayer != null) hinges.Update(objects, localId, localPlayer.position, Time.deltaTime, SendGame); }
|
||||||
catch (System.Exception e) { ReportError("car door sync", e); }
|
catch (System.Exception e) { ReportError("car door sync", e); }
|
||||||
|
PartEnd("car door sync");
|
||||||
// Jobs, Aufträge, Laden
|
// Jobs, Aufträge, Laden
|
||||||
|
PartStart();
|
||||||
try { if (objects.ScanComplete) worldVars.Update(SendGame); }
|
try { if (objects.ScanComplete) worldVars.Update(SendGame); }
|
||||||
catch (System.Exception e) { ReportError("jobs/shop sync", e); }
|
catch (System.Exception e) { ReportError("jobs/shop sync", e); }
|
||||||
|
PartEnd("jobs/shop sync");
|
||||||
// Verkehr: die Welt-Autorität simuliert, alle anderen fahren nach
|
// Verkehr: die Welt-Autorität simuliert, alle anderen fahren nach
|
||||||
|
PartStart();
|
||||||
try { if (objects.ScanComplete) traffic.Update(IsWorldAuthority, Time.deltaTime, SendGame); }
|
try { if (objects.ScanComplete) traffic.Update(IsWorldAuthority, Time.deltaTime, SendGame); }
|
||||||
catch (System.Exception e) { ReportError("traffic sync", e); }
|
catch (System.Exception e) { ReportError("traffic sync", e); }
|
||||||
|
PartEnd("traffic sync");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (PlayerInfo p in players.Values)
|
foreach (PlayerInfo p in players.Values)
|
||||||
{
|
{
|
||||||
if (p.Avatar == null) continue;
|
if (p.Avatar == null) continue;
|
||||||
|
PartStart();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Sitzt der Mitspieler in einem Fahrzeug, die Figur an unsere Kopie dieses Fahrzeugs hängen
|
// Sitzt der Mitspieler in einem Fahrzeug, die Figur an unsere Kopie dieses Fahrzeugs hängen
|
||||||
@@ -1937,6 +1967,7 @@ namespace MSCO
|
|||||||
objects.ApplyAvatarHold(p.Id, p.Avatar.HeldId, pos, rot);
|
objects.ApplyAvatarHold(p.Id, p.Avatar.HeldId, pos, rot);
|
||||||
}
|
}
|
||||||
catch (System.Exception e) { ReportError("player figure", e); }
|
catch (System.Exception e) { ReportError("player figure", e); }
|
||||||
|
PartEnd("player figure");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abgefangene Schraub-/Montage-Aktionen verschicken
|
// Abgefangene Schraub-/Montage-Aktionen verschicken
|
||||||
@@ -1947,12 +1978,52 @@ namespace MSCO
|
|||||||
foreach (FsmEventMsg msg in FsmSync.Outbox) SendGame(MsgType.FsmEvent, msg.Serialize());
|
foreach (FsmEventMsg msg in FsmSync.Outbox) SendGame(MsgType.FsmEvent, msg.Serialize());
|
||||||
}
|
}
|
||||||
catch (System.Exception e) { ReportError("part/bolt sync", e); }
|
catch (System.Exception e) { ReportError("part/bolt sync", e); }
|
||||||
|
PartEnd("part/bolt sync");
|
||||||
FsmSync.Outbox.Clear();
|
FsmSync.Outbox.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly Dictionary<string, float> lastErrorReport = new Dictionary<string, float>();
|
readonly Dictionary<string, float> lastErrorReport = new Dictionary<string, float>();
|
||||||
|
|
||||||
/// <summary>Fehler eines Teilsystems melden (höchstens alle 30 s pro Teilsystem, damit das Log nicht vollläuft).</summary>
|
/// <summary>Fehler eines Teilsystems melden (höchstens alle 30 s pro Teilsystem, damit das Log nicht vollläuft).</summary>
|
||||||
|
// ---------------------------------------------------------------- Hänger erkennen
|
||||||
|
// Jeder Sync-Teil wird gemessen. Dauert ein Bild sehr lange, steht in der F7-Konsole, ob MSCO schuld war
|
||||||
|
// (und welcher Teil) oder das Spiel selbst (z.B. beim Speichern).
|
||||||
|
readonly System.Diagnostics.Stopwatch partWatch = System.Diagnostics.Stopwatch.StartNew();
|
||||||
|
long partStart;
|
||||||
|
double frameMsco, slowestMs;
|
||||||
|
string slowestPart;
|
||||||
|
float nextHitchReport, lastSaveTriggered = -100f;
|
||||||
|
const float HitchSeconds = 0.2f;
|
||||||
|
|
||||||
|
void PartStart() { partStart = partWatch.ElapsedTicks; }
|
||||||
|
|
||||||
|
void PartEnd(string name)
|
||||||
|
{
|
||||||
|
double ms = (partWatch.ElapsedTicks - partStart) * 1000.0 / System.Diagnostics.Stopwatch.Frequency;
|
||||||
|
frameMsco += ms;
|
||||||
|
if (ms > slowestMs) { slowestMs = ms; slowestPart = name; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Zu Beginn jedes Bilds: war das letzte Bild ein Hänger? Dann Ursache melden (höchstens alle 20 s).</summary>
|
||||||
|
void CheckHitch()
|
||||||
|
{
|
||||||
|
float dt = Time.unscaledDeltaTime;
|
||||||
|
if (dt > HitchSeconds && MenuHelper.InGame && Time.realtimeSinceStartup >= nextHitchReport)
|
||||||
|
{
|
||||||
|
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)"));
|
||||||
|
}
|
||||||
|
frameMsco = 0;
|
||||||
|
slowestMs = 0;
|
||||||
|
slowestPart = null;
|
||||||
|
}
|
||||||
|
|
||||||
void ReportError(string what, System.Exception e)
|
void ReportError(string what, System.Exception e)
|
||||||
{
|
{
|
||||||
float now = Time.realtimeSinceStartup, last;
|
float now = Time.realtimeSinceStartup, last;
|
||||||
@@ -1965,25 +2036,37 @@ namespace MSCO
|
|||||||
void FixedUpdate()
|
void FixedUpdate()
|
||||||
{
|
{
|
||||||
if (!IsPeerReady || !MenuHelper.InGame) return;
|
if (!IsPeerReady || !MenuHelper.InGame) return;
|
||||||
|
PartStart();
|
||||||
try { objects.FixedUpdate(); }
|
try { objects.FixedUpdate(); }
|
||||||
catch (System.Exception e) { ReportError("object movement", e); }
|
catch (System.Exception e) { ReportError("object movement", e); }
|
||||||
|
PartEnd("object movement");
|
||||||
|
PartStart();
|
||||||
try { traffic.FixedUpdate(); }
|
try { traffic.FixedUpdate(); }
|
||||||
catch (System.Exception e) { ReportError("traffic movement", e); }
|
catch (System.Exception e) { ReportError("traffic movement", e); }
|
||||||
|
PartEnd("traffic movement");
|
||||||
|
PartStart();
|
||||||
try { hinges.FixedUpdate(); }
|
try { hinges.FixedUpdate(); }
|
||||||
catch (System.Exception e) { ReportError("car door movement", e); }
|
catch (System.Exception e) { ReportError("car door movement", e); }
|
||||||
|
PartEnd("car door movement");
|
||||||
}
|
}
|
||||||
|
|
||||||
void LateUpdate()
|
void LateUpdate()
|
||||||
{
|
{
|
||||||
InputLock.KeepCursorFree(); // das Spiel sperrt den Zeiger im selben Frame evtl. wieder
|
InputLock.KeepCursorFree(); // das Spiel sperrt den Zeiger im selben Frame evtl. wieder
|
||||||
// Nach den Spiel-FSMs, damit Lichter/Motorgeräusch der Fahrzeuge anderer gewinnen
|
// Nach den Spiel-FSMs, damit Lichter/Motorgeräusch der Fahrzeuge anderer gewinnen
|
||||||
|
PartStart();
|
||||||
try { if (IsPeerReady && MenuHelper.InGame) vehicleFx.Apply(objects); }
|
try { if (IsPeerReady && MenuHelper.InGame) vehicleFx.Apply(objects); }
|
||||||
catch (System.Exception e) { ReportError("vehicle lights/sound", e); }
|
catch (System.Exception e) { ReportError("vehicle lights/sound", e); }
|
||||||
|
PartEnd("vehicle lights/sound");
|
||||||
|
PartStart();
|
||||||
try { if (IsPeerReady && MenuHelper.InGame) wheelSpin.Apply(objects, Time.deltaTime); }
|
try { if (IsPeerReady && MenuHelper.InGame) wheelSpin.Apply(objects, Time.deltaTime); }
|
||||||
catch (System.Exception e) { ReportError("wheels", e); }
|
catch (System.Exception e) { ReportError("wheels", e); }
|
||||||
|
PartEnd("wheels");
|
||||||
// Beifahrer nach der Fahrzeugbewegung auf den Sitz setzen
|
// Beifahrer nach der Fahrzeugbewegung auf den Sitz setzen
|
||||||
|
PartStart();
|
||||||
try { if (localPlayer != null && MenuHelper.InGame) passenger.LateUpdate(localPlayer, playerCamera, objects); }
|
try { if (localPlayer != null && MenuHelper.InGame) passenger.LateUpdate(localPlayer, playerCamera, objects); }
|
||||||
catch (System.Exception e) { ReportError("passenger", e); }
|
catch (System.Exception e) { ReportError("passenger", e); }
|
||||||
|
PartEnd("passenger");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -2122,6 +2205,7 @@ namespace MSCO
|
|||||||
System.Collections.IEnumerator UploadSave(int requestId)
|
System.Collections.IEnumerator UploadSave(int requestId)
|
||||||
{
|
{
|
||||||
if (!MenuHelper.InGame || !dedicated || session == null) yield break;
|
if (!MenuHelper.InGame || !dedicated || session == null) yield break;
|
||||||
|
lastSaveTriggered = Time.realtimeSinceStartup;
|
||||||
PlayMakerFSM.BroadcastEvent("SAVEGAME");
|
PlayMakerFSM.BroadcastEvent("SAVEGAME");
|
||||||
float until = Time.realtimeSinceStartup + 3f; // das Spiel schreibt die Dateien über mehrere Frames
|
float until = Time.realtimeSinceStartup + 3f; // das Spiel schreibt die Dateien über mehrere Frames
|
||||||
while (Time.realtimeSinceStartup < until) yield return null;
|
while (Time.realtimeSinceStartup < until) yield return null;
|
||||||
|
|||||||
+1
-1
@@ -159,7 +159,7 @@ namespace MSCO
|
|||||||
void Scan()
|
void Scan()
|
||||||
{
|
{
|
||||||
int before = vars.Count;
|
int before = vars.Count;
|
||||||
foreach (PlayMakerFSM fsm in SceneCache.Fsms(5f))
|
foreach (PlayMakerFSM fsm in SceneCache.Fsms(20f))
|
||||||
{
|
{
|
||||||
// Schon erfasste FSMs nicht jedes Mal neu durchgehen (Pfad + Hash kosten)
|
// Schon erfasste FSMs nicht jedes Mal neu durchgehen (Pfad + Hash kosten)
|
||||||
if (fsm == null || !scanned.Add(fsm)) continue;
|
if (fsm == null || !scanned.Add(fsm)) continue;
|
||||||
|
|||||||
+1
-1
@@ -163,7 +163,7 @@ namespace MSCO
|
|||||||
{
|
{
|
||||||
nextDiscover = Time.time + DiscoverRetry;
|
nextDiscover = Time.time + DiscoverRetry;
|
||||||
tracked.Clear();
|
tracked.Clear();
|
||||||
foreach (PlayMakerFSM fsm in SceneCache.Fsms(5f))
|
foreach (PlayMakerFSM fsm in SceneCache.Fsms(20f))
|
||||||
{
|
{
|
||||||
if (fsm == null) continue;
|
if (fsm == null) continue;
|
||||||
if (Array.IndexOf(TrackedFsmNames, fsm.FsmName) < 0) continue;
|
if (Array.IndexOf(TrackedFsmNames, fsm.FsmName) < 0) continue;
|
||||||
|
|||||||
+1
-1
@@ -111,7 +111,7 @@ namespace MSCO
|
|||||||
void Scan()
|
void Scan()
|
||||||
{
|
{
|
||||||
int before = vars.Count;
|
int before = vars.Count;
|
||||||
foreach (PlayMakerFSM fsm in SceneCache.Fsms(5f))
|
foreach (PlayMakerFSM fsm in SceneCache.Fsms(20f))
|
||||||
{
|
{
|
||||||
if (fsm == null || !scanned.Add(fsm)) continue;
|
if (fsm == null || !scanned.Add(fsm)) continue;
|
||||||
if (Array.IndexOf(Roots, fsm.transform.root.name) < 0) continue;
|
if (Array.IndexOf(Roots, fsm.transform.root.name) < 0) continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user