From a6e5abfc0538165d96f1727f84da4f3f301a888d Mon Sep 17 00:00:00 2001 From: MrMaho Date: Sun, 27 Sep 2026 11:25:29 +0200 Subject: [PATCH] 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 --- VehicleFx.cs | 11 ++++------- VehicleStateSync.cs | 32 +++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/VehicleFx.cs b/VehicleFx.cs index c5a204f..e6ea003 100644 --- a/VehicleFx.cs +++ b/VehicleFx.cs @@ -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(); } diff --git a/VehicleStateSync.cs b/VehicleStateSync.cs index debde65..6384457 100644 --- a/VehicleStateSync.cs +++ b/VehicleStateSync.cs @@ -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; }