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:
+4
-7
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user