MSCO 2.10.1: car doors and garage door synced, door lock fix, perf tools
- Car doors (FSM with bool "Open" and "Open door"/"Close door") are synced as open/closed: the receiver removes the hold joint and frees the hinge, closing runs the game's own logic - Fix: every synced close of an already closed Satsuma door added another FixedJoint, so the door could not be opened anymore; extra joints are removed automatically - Hinge sync also covers world doors/gates with hinges (garage door), interaction by bounds - Scene name read once per frame (Application.loadedLevelName allocates a string per call) - Console "perf" (FPS, ms per MSCO part incl. OnGUI, GC, hook calls), -msco-perf start option - Console "fsmdump <text>" / -msco-dump: PlayMaker FSMs and hinges to MSCO\fsmdump.txt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+110
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using HutongGames.PlayMaker;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MSCO
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public static class FsmDump
|
||||
{
|
||||
public static string Write(string filter)
|
||||
{
|
||||
string[] filters = (filter ?? "").ToLowerInvariant().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (filters.Length == 0) return "fsmdump <text>[,text2] - e.g. fsmdump garage";
|
||||
var sb = new StringBuilder();
|
||||
int count = 0;
|
||||
foreach (PlayMakerFSM fsm in Resources.FindObjectsOfTypeAll<PlayMakerFSM>())
|
||||
{
|
||||
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<HingeJoint>())
|
||||
{
|
||||
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<Rigidbody>();
|
||||
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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user