Crash safety: vehicle state sync skips FSMs that set scale/position (value could make a size 0 -> PhysX crash), never applies NaN; light/effect sync no longer activates parent objects

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-27 11:25:29 +02:00
co-authored by Claude Opus 5.5
parent b3405d3752
commit a6e5abfc05
2 changed files with 35 additions and 8 deletions
+4 -7
View File
@@ -199,20 +199,17 @@ namespace MSCO
if (light.enabled) light.enabled = false;
return;
}
// Nur die Lampe selbst einschalten - übergeordnete Objekte NICHT aktivieren: das weckt Spiel-Logik auf
// (FSMs im OnEnable), die dort nicht laufen soll, und kann das Spiel abstürzen lassen
if (!light.enabled) light.enabled = true;
// Lichter werden im Spiel oft über ein übergeordnetes Objekt ein-/ausgeschaltet
for (Transform t = light.transform; t != null && t != root; t = t.parent)
if (!t.gameObject.activeSelf) t.gameObject.SetActive(true);
}
static void SetParticles(ParticleSystem ps, bool playing, Transform root)
{
if (playing)
{
// Effekte hängen oft an einem abgeschalteten Objekt (z.B. "Fire"), das die Spiel-Logik aktiviert
for (Transform t = ps.transform; t != null && t != root; t = t.parent)
if (!t.gameObject.activeSelf) t.gameObject.SetActive(true);
if (!ps.isPlaying) ps.Play();
// Nur Effekte auf bereits aktiven Objekten starten (Objekte aktivieren weckt Spiel-Logik - Absturzgefahr)
if (ps.gameObject.activeInHierarchy && !ps.isPlaying) ps.Play();
}
else if (ps.isPlaying) ps.Stop();
}
+31 -1
View File
@@ -138,6 +138,9 @@ namespace MSCO
if (fsm == null || !scanned.Add(fsm)) continue;
string root = fsm.transform.root.name;
if (!IsVehicle(root)) continue;
// FSMs, die Größen/Positionen setzen (z.B. Füllstands-Anzeigen), NICHT anfassen: ein übertragener Wert
// kann dort eine Größe 0 ergeben - Unity stürzt dann in der Physik ab ("cleaning the mesh failed")
if (TouchesTransform(fsm)) continue;
string prefix = FsmSync.PathOf(fsm.transform) + "|" + fsm.FsmName + "|";
FsmVariables fv = fsm.FsmVariables;
foreach (FsmFloat f in fv.FloatVariables) Register(prefix, root, f, 1);
@@ -147,6 +150,29 @@ namespace MSCO
if (vars.Count != before) MscoLog.Info("[MSCO] Vehicle state: " + vars.Count + " values synced");
}
static readonly string[] TransformActionWords = { "Scale", "Position", "Rotate", "Rotation", "Translate", "Parent" };
static bool TouchesTransform(PlayMakerFSM fsm)
{
try
{
foreach (FsmState state in fsm.FsmStates)
{
if (!state.ActionsLoaded) state.LoadActions();
if (state.Actions == null) continue;
foreach (FsmStateAction action in state.Actions)
{
if (action == null) continue;
string type = action.GetType().Name;
foreach (string word in TransformActionWords)
if (type.Contains(word)) return true;
}
}
}
catch { return true; } // im Zweifel nicht anfassen
return false;
}
void Register(string prefix, string root, NamedVariable variable, byte type)
{
if (variable == null || string.IsNullOrEmpty(variable.Name) || !Wanted(variable.Name)) return;
@@ -211,7 +237,11 @@ namespace MSCO
if (type != v.Type) return;
switch (type)
{
case 1: ((FsmFloat)v.Variable).Value = BitConverter.ToSingle(value, 0); break;
case 1:
float f = BitConverter.ToSingle(value, 0);
if (float.IsNaN(f) || float.IsInfinity(f)) return; // nie ungültige Werte übernehmen
((FsmFloat)v.Variable).Value = f;
break;
case 2: ((FsmInt)v.Variable).Value = BitConverter.ToInt32(value, 0); break;
default: ((FsmBool)v.Variable).Value = value[0] != 0; break;
}