Jump to content

Simple empty mod causes game to crash


Recommended Posts

Hi all,

While developing my own mod I've stumbled upon a nasty failure.

I've managed to limit the scope to the simple mod with a single file and following listing:

using HarmonyLib;

[HarmonyPatch(typeof(Door))]
public static class ObjectEvents {

[HarmonyPrefix]
[HarmonyPatch(nameof(Door.OrderUnseal))]
private static void ObjectEventsPostfix() { }

}

After having this mod compiled and install you need to:

1) Load saved game with some doors
2) Click Lock on any Door
3) un-pause game

You can find player.log attached.
 

I'm still quite confused how the empty patch (I've tried non-empty as well) does affect the game.

From a glance it seems to be connected to the fact that Harmony does initialize static fields of the class while patching it.

I hope someone (developers perhaps? :) ) could help here.

Player.log

Link to comment
Share on other sites

Hi guys,

We're working with the OP on the same mod and I've traced the problem with this particular Door patch. Turned out it's related to Door.OVERRIDE_ANIMS static field which is being initialized during the patch

Spoiler

  at Assets.GetAnim (HashedString name) [0x00000] in -\Assets.cs:591 
  at Door..cctor () [0x00000] in <cd4b9bd5aa6c4ec38ec00dca1dc79105>:0 
  at System.RuntimeMethodHandle.GetFunctionPointer (System.IntPtr m) [0x00000] in <695d1cc93cca45069c528c15c9fdd749>:0 
  at System.RuntimeMethodHandle.GetFunctionPointer () [0x00000] in <695d1cc93cca45069c528c15c9fdd749>:0 
  at MonoMod.RuntimeDetour.Platforms.DetourRuntimeILPlatform.GetFunctionPointer (System.Reflection.MethodBase method, System.RuntimeMethodHandle handle) [0x00000] in <2f5aaaa000594d07b9998f4cff1e9662>:0 
  at MonoMod.RuntimeDetour.Platforms.DetourRuntimeILPlatform.GetNativeStart (System.Reflection.MethodBase method) [0x00000] in <2f5aaaa000594d07b9998f4cff1e9662>:0 
  at MonoMod.RuntimeDetour.DetourHelper.GetNativeStart (System.Reflection.MethodBase method) [0x00000] in <2f5aaaa000594d07b9998f4cff1e9662>:0 
  at HarmonyLib.Memory.GetMethodStart (System.Reflection.MethodBase method, System.Exception& exception) [0x00000] in <2f5aaaa000594d07b9998f4cff1e9662>:0 
  at HarmonyLib.Memory.DetourMethod (System.Reflection.MethodBase original, System.Reflection.MethodBase replacement) [0x00000] in <2f5aaaa000594d07b9998f4cff1e9662>:0 
  at HarmonyLib.Memory.DetourMethodAndPersist (System.Reflection.MethodBase original, System.Reflection.MethodBase replacement) [0x00000] in <2f5aaaa000594d07b9998f4cff1e9662>:0 
  at HarmonyLib.PatchFunctions.UpdateWrapper (System.Reflection.MethodBase original, HarmonyLib.PatchInfo patchInfo) [0x00000] in <2f5aaaa000594d07b9998f4cff1e9662>:0 
  at HarmonyLib.PatchClassProcessor.ProcessPatchJob (HarmonyLib.PatchJobs`1+Job[T] job) [0x00000] in <2f5aaaa000594d07b9998f4cff1e9662>:0 
  at HarmonyLib.PatchClassProcessor.PatchWithAttributes (System.Reflection.MethodBase& lastOriginal) [0x00000] in <2f5aaaa000594d07b9998f4cff1e9662>:0 
  at HarmonyLib.PatchClassProcessor.Patch () [0x00000] in <2f5aaaa000594d07b9998f4cff1e9662>:0 
  at MultiplayerMod.Core.Loader.ModLoader.OnLoad (HarmonyLib.Harmony harmony) [0x00000] in <0361fe183078446597d3f44f6a59d5d5>:0 
  at KMod.DLLLoader.LoadDLLs (KMod.Mod ownerMod, System.String harmonyId, System.String path, System.Boolean isDev) [0x0021b] in KMod\DLLLoader.cs:124 
  at KMod.Mod.Load (KMod.Content content) [0x000a5] in KMod\Mod.cs:656 
  at KMod.Manager.Load (KMod.Content content) [0x0004f] in KMod\Manager.cs:447 
  at Global.Awake () [0x00171] in -\Global.cs:342 
  at UnityEngine.Object.Internal_InstantiateSingleWithParent_Injected (UnityEngine.Object data, UnityEngine.Transform parent, UnityEngine.Vector3& pos, UnityEngine.Quaternion& rot) [0x00000] in <faa1d4bf73af4cbca302a933fa3e0da0>:0 
  at UnityEngine.Object.Internal_InstantiateSingleWithParent (UnityEngine.Object data, UnityEngine.Transform parent, UnityEngine.Vector3 pos, UnityEngine.Quaternion rot) [0x00000] in <faa1d4bf73af4cbca302a933fa3e0da0>:0 
  at UnityEngine.Object.Instantiate (UnityEngine.Object original, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, UnityEngine.Transform parent) [0x00000] in <faa1d4bf73af4cbca302a933fa3e0da0>:0 
  at UnityEngine.Object.Instantiate[T] (T original, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, UnityEngine.Transform parent) [0x00000] in <faa1d4bf73af4cbca302a933fa3e0da0>:0 
  at Util.KInstantiate (UnityEngine.GameObject original, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, UnityEngine.GameObject parent, System.String name, System.Boolean initialize_id, System.Int32 gameLayer) [0x00076] in -\Util.cs:259 
  at Util.KInstantiate (UnityEngine.GameObject original, UnityEngine.GameObject parent, System.String name) [0x00000] in -\Util.cs:231 
  at LaunchInitializer.Update () [0x000ea] in -\LaunchInitializer.cs:63 

and since it called Assets.GetAnim which hadn't initialized yet a null value was written to OVERRIDE_ANIMS.

Thus the game fails when it's switching to the animation with the remote (anim_use_remote_kanim) when locking / unlocking doors, because the override animation is null.

Seems like we can't avoid the field initialization, because it's a part of the C# detouring mechanism. Because we actually patch a lot of classes with static initialization inside, we thought maybe from our side we can "delay" the patching process until everything that can be used in static is initialized. I think that theoretically can be done in the end of LaunchInitializer.Update(), but we still unsure if that's okay. What do you think?

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.

×
  • Create New...