/// <summary> /// Registers an assembly as loaded by a particular mod. /// </summary> /// <param name="assembly">The assembly to register.</param> /// <param name="owner">The owning mod.</param> internal void RegisterAssembly(Assembly assembly, ModDebugInfo owner) { if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); } if (owner == null) { throw new ArgumentNullException(nameof(owner)); } string fullName = assembly.FullName; var oldMod = modAssemblies.GetOrAdd(fullName, owner); if (oldMod != owner) { // Possible if multiple mods include the same dependency DLL DebugLogger.LogDebug("Assembly \"{0}\" is used by multiple mods:", fullName); DebugLogger.LogDebug("First loaded by {0} (used), also loaded by {1} (ignored)", oldMod.ModName, owner.ModName); } else { owner.ModAssemblies.Add(assembly); } }
/// <summary> /// Retrieves the debug information for the specified mod, registering it if it has /// not been seen before. /// </summary> /// <param name="mod">The mod to retrieve.</param> /// <returns>The debug information about that mod.</returns> internal ModDebugInfo GetDebugInfo(Mod mod) { if (mod == null) { throw new ArgumentNullException(nameof(mod)); } return(debugInfo.GetOrAdd(ModDebugInfo.GetIdentifier(mod), (_) => new ModDebugInfo(mod))); }
/// <summary> /// Returns the owning mod of the specified assembly. Returns null if no mod appears to /// own this assembly. /// </summary> /// <param name="assembly">The assembly to query.</param> /// <returns>The owning mod, or null if no owning mod could be determined.</returns> internal ModDebugInfo OwnerOfAssembly(Assembly assembly) { ModDebugInfo mod = null; if (assembly != null) { modAssemblies.TryGetValue(assembly.FullName, out mod); } return(mod); }
/// <summary> /// Disables the offending mod and restarts the game. /// </summary> /// <param name="info">The mod to disable, or null to not disable any mods.</param> private static void DisableAndRestart(ModDebugInfo info) { var manager = Global.Instance.modManager; if (info != null) { manager.EnableMod(info.Mod.label, false, manager); manager.Save(); } App.instance.Restart(); }
/// <summary> /// Gets the mod that most recently appeared on the provided call stack. /// </summary> /// <param name="stackTrace">The call stack of the exception thrown.</param> /// <returns>The mod that is most likely at fault, or null if no mods appear on the stack.</returns> internal static ModDebugInfo GetFirstModOnCallStack(this StackTrace stackTrace) { ModDebugInfo mod = null; if (stackTrace != null) { var registry = ModDebugRegistry.Instance; int n = stackTrace.FrameCount; // Search for first method that has a mod in the registry for (int i = 0; i < n && mod == null; i++) { var method = stackTrace.GetFrame(i)?.GetMethod(); if (method != null) { mod = registry.OwnerOfType(method.DeclaringType); } } } return(mod); }