Files
MSCO/SafetyPatches.cs
T
MrMahoandClaude Opus 5.5 461d94c5fc MSCO 2.9.0: standalone without MSCLoader (Unity Doorstop)
- Bootstrap: Doorstop entry point, loads Harmony/Newtonsoft from the MSCO folder, hooks
  PlayMakerArrayListProxy.Awake and starts MSCO in the main menu; skips the news screen
- No MSCLoader reference anymore; key bindings in PlayerPrefs, bind console command
- Harmony 1.2 and Newtonsoft.Json in lib/ (MIT notices); build copies to <game>\MSCO
- README/CHANGELOG updated

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 23:36:28 +02:00

74 lines
3.0 KiB
C#

using System;
using System.Reflection;
using Harmony;
using HutongGames.PlayMaker;
using UnityEngine;
namespace MSCO
{
/// <summary>
/// Schutz vor Abstürzen durch nachgespielte Aktionen: Wird beim Beitreten eine Montage-Aktion in einer
/// etwas anderen Welt nachgespielt, kann die "SetParent"-Aktion eines Teils ein Objekt unter sein eigenes
/// Kind hängen. Das ergibt einen Kreis in der Hierarchie und Unity stürzt nativ ab (Stack Overflow in
/// Transform::GetClassIDStatic). Solche Aufrufe werden hier abgefangen und übersprungen.
/// </summary>
public static class SafetyPatches
{
static bool applied;
static FieldInfo gameObjectField, parentField;
static int blocked;
public static void Apply()
{
if (applied) return;
applied = true;
try
{
Type action = null;
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
action = asm.GetType("HutongGames.PlayMaker.Actions.SetParent");
if (action != null) break;
}
MethodInfo onEnter = action != null ? action.GetMethod("OnEnter", BindingFlags.Instance | BindingFlags.Public) : null;
if (onEnter == null) { MscoLog.Warning("[MSCO] SetParent action not found - hierarchy guard disabled"); return; }
gameObjectField = action.GetField("gameObject");
parentField = action.GetField("parent");
HarmonyInstance.Create("mbm.msco.safety").Patch(onEnter,
new HarmonyMethod(typeof(SafetyPatches).GetMethod("SetParentPrefix", BindingFlags.Static | BindingFlags.NonPublic)), null);
}
catch (Exception e)
{
MscoLog.Warning("[MSCO] Could not install hierarchy guard: " + e.Message);
}
}
static bool SetParentPrefix(FsmStateAction __instance)
{
try
{
var owner = gameObjectField != null ? gameObjectField.GetValue(__instance) as FsmOwnerDefault : null;
var parent = parentField != null ? parentField.GetValue(__instance) as FsmGameObject : null;
if (owner == null || parent == null || parent.Value == null) return true;
GameObject go = __instance.Fsm.GetOwnerDefaultTarget(owner);
if (go == null) return true;
Transform child = go.transform, newParent = parent.Value.transform;
if (newParent != child && !newParent.IsChildOf(child)) return true;
blocked++;
if (blocked <= 20)
MscoLog.Warning("[MSCO] Blocked SetParent that would crash the game: " + go.name + " -> " + parent.Value.name +
" (" + __instance.Fsm.Name + ")");
__instance.Finish();
return false;
}
catch
{
return true;
}
}
}
}