Beta Release
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Harmony;
|
||||
using HutongGames.PlayMaker;
|
||||
using MSCLoader;
|
||||
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) { ModConsole.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)
|
||||
{
|
||||
ModConsole.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)
|
||||
ModConsole.Warning("[MSCO] Blocked SetParent that would crash the game: " + go.name + " -> " + parent.Value.name +
|
||||
" (" + __instance.Fsm.Name + ")");
|
||||
__instance.Finish();
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user