using System; using System.IO; using System.Reflection; using System.Text; using HutongGames.PlayMaker; using UnityEngine; namespace MSCO { /// /// Diagnose: PlayMaker-FSMs (Zustände, Aktionen mit Werten, Übergänge) und Scharniere von Objekten, deren Pfad einen /// Suchtext enthält, in MSCO\fsmdump.txt schreiben. Konsole (F7): "fsmdump <text>". Mit der Startoption /// "-msco-dump text1,text2" automatisch 25 s nach dem Laden des Spiels. /// public static class FsmDump { public static string Write(string filter) { string[] filters = (filter ?? "").ToLowerInvariant().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (filters.Length == 0) return "fsmdump [,text2] - e.g. fsmdump garage"; var sb = new StringBuilder(); int count = 0; foreach (PlayMakerFSM fsm in Resources.FindObjectsOfTypeAll()) { if (fsm == null || fsm.gameObject == null || fsm.gameObject.hideFlags != HideFlags.None) continue; string path, lower; try { path = FsmSync.PathOf(fsm.transform); lower = (path + "|" + fsm.FsmName).ToLowerInvariant(); } catch { continue; } if (Array.FindIndex(filters, f => lower.Contains(f.Trim())) < 0) continue; if (++count > 400) break; try { Dump(sb, fsm, path); } catch (Exception e) { sb.Append(" (error: ").Append(e.Message).Append(")").AppendLine(); } } foreach (HingeJoint j in Resources.FindObjectsOfTypeAll()) { if (j == null || j.gameObject.hideFlags != HideFlags.None) continue; string path = FsmSync.PathOf(j.transform); if (Array.FindIndex(filters, f => path.ToLowerInvariant().Contains(f.Trim())) < 0) continue; Rigidbody rb = j.GetComponent(); try { sb.Append("HINGE ").Append(path).Append(" -> ").Append(j.connectedBody != null ? FsmSync.PathOf(j.connectedBody.transform) : "-") .Append(" | active ").Append(j.gameObject.activeInHierarchy).Append(" angle ").Append(j.angle.ToString("0.0")) .Append(" limits ").Append(j.useLimits).Append(' ').Append(j.limits.min.ToString("0")).Append("..").Append(j.limits.max.ToString("0")) .Append(" spring ").Append(j.useSpring).Append(' ').Append(j.spring.spring.ToString("0")).Append('/').Append(j.spring.targetPosition.ToString("0")) .Append(" motor ").Append(j.useMotor) .Append(" kinematic ").Append(rb != null && rb.isKinematic).Append(" break ").Append(j.breakForce).AppendLine(); } catch (Exception e) { sb.Append(" (error: ").Append(e.Message).Append(")").AppendLine(); } } string file = Path.Combine(Bootstrap.Folder ?? ".", "fsmdump.txt"); File.WriteAllText(file, sb.ToString()); return count + " FSM(s) written to " + file; } static void Dump(StringBuilder sb, PlayMakerFSM fsm, string path) { sb.Append("==== ").Append(path).Append(" | ").Append(fsm.FsmName).Append(" | active ").Append(fsm.gameObject.activeInHierarchy) .Append(" | state ").Append(fsm.ActiveStateName).AppendLine(); try { FsmVariables fv = fsm.FsmVariables; var vb = new StringBuilder(); foreach (FsmFloat f in fv.FloatVariables) vb.Append(" ").Append(f.Name).Append("=").Append(f.Value.ToString("0.###")); foreach (FsmInt n in fv.IntVariables) vb.Append(" ").Append(n.Name).Append("=").Append(n.Value); foreach (FsmBool b in fv.BoolVariables) vb.Append(" ").Append(b.Name).Append("=").Append(b.Value); foreach (FsmString t in fv.StringVariables) vb.Append(" ").Append(t.Name).Append("=\"").Append(t.Value).Append("\""); if (vb.Length > 0) sb.Append(" VARS").Append(vb).AppendLine(); } catch { } if (fsm.FsmGlobalTransitions != null) foreach (FsmTransition t in fsm.FsmGlobalTransitions) sb.Append(" GLOBAL ").Append(t.EventName).Append(" -> ").Append(t.ToState).AppendLine(); if (fsm.FsmStates == null) return; foreach (FsmState s in fsm.FsmStates) { if (s == null) continue; if (!s.ActionsLoaded) s.LoadActions(); sb.Append(" [").Append(s.Name).Append(']'); if (s.Transitions != null) foreach (FsmTransition t in s.Transitions) if (t != null) sb.Append(" ").Append(t.EventName).Append("->").Append(t.ToState); sb.AppendLine(); if (s.Actions == null) continue; foreach (FsmStateAction a in s.Actions) { if (a == null) continue; sb.Append(" ").Append(a.GetType().Name).Append(Fields(a)).AppendLine(); } } } static string Fields(FsmStateAction a) { var sb = new StringBuilder(); foreach (FieldInfo f in a.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)) { object v; try { v = f.GetValue(a); } catch { continue; } string text = Describe(v); if (text == null) continue; sb.Append(' ').Append(f.Name).Append('=').Append(text); } return sb.ToString(); } static string Describe(object v) { if (v == null) return null; var named = v as NamedVariable; if (named != null) { string value; try { value = Convert.ToString(v.GetType().GetProperty("Value").GetValue(v, null)); } catch { value = "?"; } return (string.IsNullOrEmpty(named.Name) ? "" : "{" + named.Name + "}") + value; } var ev = v as FsmEvent; if (ev != null) return "event:" + ev.Name; var owner = v as FsmOwnerDefault; if (owner != null) return owner.OwnerOption == OwnerDefaultOption.UseOwner ? "owner" : Describe(owner.GameObject); if (v is string || v is bool || v is int || v is float || v.GetType().IsEnum) return Convert.ToString(v); return null; } } }