Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of NullReferenceFix v1.0.20
NullReferenceFix.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using NullReferenceFix.Patches; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("NullReferenceFix")] [assembly: AssemblyDescription("Fixes a vanilla Valheim NullReferenceException loop in ZNetScene.RemoveObjects.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("KorCaptain")] [assembly: AssemblyProduct("NullReferenceFix")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("B3C1F0F1-6E8C-4B7A-9B2E-1E7F5C9A2D41")] [assembly: AssemblyFileVersion("1.0.20")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.20.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace NullReferenceFix { [BepInPlugin("KorCaptain.NullReferenceFix", "NullReferenceFix", "1.0.20")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class NullReferenceFixPlugin : BaseUnityPlugin { internal const string ModVersion = "1.0.20"; internal const string ModName = "NullReferenceFix"; internal const string Author = "KorCaptain"; private const string ModGUID = "KorCaptain.NullReferenceFix"; private readonly Harmony _harmony = new Harmony("KorCaptain.NullReferenceFix"); public static ManualLogSource NullReferenceFixLogger; public void Awake() { NullReferenceFixLogger = ((BaseUnityPlugin)this).Logger; _harmony.PatchAll(Assembly.GetExecutingAssembly()); TMPLocalizationFallbackFontRegistrar.Initialize(); NullReferenceFixLogger.LogInfo((object)"NullReferenceFix v1.0.20 loaded."); } } } namespace NullReferenceFix.Patches { [HarmonyPatch(typeof(ZNetScene), "RemoveObjects")] public static class ZNetScene_RemoveObjects_NullGuard_Patch { private static readonly FieldInfo? InstancesField = typeof(ZNetScene).GetField("m_instances", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static Exception? Finalizer(ZNetScene __instance, Exception __exception) { if (!(__exception is NullReferenceException)) { return __exception; } try { if (!(InstancesField?.GetValue(__instance) is Dictionary<ZDO, ZNetView> dictionary)) { return null; } List<ZDO> list = new List<ZDO>(); foreach (KeyValuePair<ZDO, ZNetView> item in dictionary) { if ((Object)(object)item.Value == (Object)null) { list.Add(item.Key); } } foreach (ZDO item2 in list) { dictionary.Remove(item2); } if (list.Count > 0) { NullReferenceFixPlugin.NullReferenceFixLogger.LogWarning((object)string.Format("[NullFix] Cleared {0} stale ZNetView entr{1} that caused a ZNetScene.RemoveObjects NullReferenceException.", list.Count, (list.Count == 1) ? "y" : "ies")); } } catch (Exception arg) { NullReferenceFixPlugin.NullReferenceFixLogger.LogError((object)$"Failed to clean up stale ZNetView entries: {arg}"); } return null; } } [HarmonyPatch] public static class AzuCraftyBoxes_HaveRequirements_NullGuard_Patch { private const string AzuCraftyBoxesPluginGuid = "Azumatt.AzuCraftyBoxes"; private static readonly FieldInfo? ContainersField = ResolveContainersField(); private static bool Prepare() { return TargetMethod() != null; } private static MethodBase? TargetMethod() { Type type = ResolveAzuCraftyBoxesType("AzuCraftyBoxes.Patches.PlayerHaveRequirementsPatchRBoolInt"); return (type == null) ? null : AccessTools.DeclaredMethod(type, "Postfix", (Type[])null, (Type[])null); } private static FieldInfo? ResolveContainersField() { Type type = ResolveAzuCraftyBoxesType("AzuCraftyBoxes.Util.Functions.Boxes"); return (type == null) ? null : AccessTools.Field(type, "Containers"); } private static Type? ResolveAzuCraftyBoxesType(string typeName) { if (!Chainloader.PluginInfos.TryGetValue("Azumatt.AzuCraftyBoxes", out var value)) { return null; } return ((object)value.Instance)?.GetType().Assembly.GetType(typeName); } private static Exception? Finalizer(Exception __exception) { if (!(__exception is NullReferenceException)) { return __exception; } int num = RemoveDestroyedContainers(); NullReferenceFixPlugin.NullReferenceFixLogger.LogWarning((object)((num > 0) ? string.Format("[NullFix] Cleared {0} stale (destroyed) container entr{1} that caused an AzuCraftyBoxes NullReferenceException during a recipe check.", num, (num == 1) ? "y" : "ies") : "[NullFix] Swallowed a NullReferenceException from AzuCraftyBoxes' recipe container check.")); return null; } private static int RemoveDestroyedContainers() { try { if (!(ContainersField?.GetValue(null) is HashSet<Container> hashSet)) { return 0; } List<Container> list = new List<Container>(); foreach (Container item in hashSet) { if ((Object)(object)item == (Object)null) { list.Add(item); } } foreach (Container item2 in list) { hashSet.Remove(item2); } return list.Count; } catch (Exception arg) { NullReferenceFixPlugin.NullReferenceFixLogger.LogError((object)$"Failed to clean up stale AzuCraftyBoxes container entries: {arg}"); return 0; } } } [HarmonyPatch(typeof(EnemyHud), "ShowHud")] public static class EnemyHud_ShowHud_NullGuard_Patch { private static readonly FieldInfo? HudsField = typeof(EnemyHud).GetField("m_huds", BindingFlags.Instance | BindingFlags.NonPublic); private static FieldInfo? _guiField; private static Exception? Finalizer(EnemyHud __instance, Character c, Exception __exception) { if (!(__exception is NullReferenceException)) { return __exception; } try { if (RemoveStaleHud(__instance, c)) { NullReferenceFixPlugin.NullReferenceFixLogger.LogWarning((object)"[NullFix] Cleared a stale EnemyHud entry that caused a NullReferenceException in a mod's EnemyHud.ShowHud patch (seen with EpicMMOSystem's PvP name-color patch when another mod force-refreshes EnemyHud.ShowHud)."); } else { NullReferenceFixPlugin.NullReferenceFixLogger.LogWarning((object)"[NullFix] Swallowed a NullReferenceException thrown from a mod's EnemyHud.ShowHud patch."); } } catch (Exception arg) { NullReferenceFixPlugin.NullReferenceFixLogger.LogError((object)$"Failed to clean up stale EnemyHud entry: {arg}"); } return null; } private static bool RemoveStaleHud(EnemyHud instance, Character c) { if (!(HudsField?.GetValue(instance) is IDictionary dictionary) || !dictionary.Contains(c)) { return false; } object obj = dictionary[c]; if (obj != null) { if ((object)_guiField == null) { _guiField = obj.GetType().GetField("m_gui", BindingFlags.Instance | BindingFlags.Public); } object? obj2 = _guiField?.GetValue(obj); GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null); if (val != null && (Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } dictionary.Remove(c); return true; } } [HarmonyPatch] public static class TMP_Text_LoadFontAsset_MissingFont_Patch { private static TMP_FontAsset? _fallbackFont; private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(TextMeshProUGUI), "LoadFontAsset", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(TextMeshPro), "LoadFontAsset", (Type[])null, (Type[])null); } private static void Prefix(TMP_Text __instance) { if (!((Object)(object)__instance.font != (Object)null)) { TMP_FontAsset val = _fallbackFont ?? (_fallbackFont = ResolveFallbackFont()); if (!((Object)(object)val == (Object)null)) { __instance.font = val; } } } private static TMP_FontAsset? ResolveFallbackFont() { if ((Object)(object)TMP_Settings.defaultFontAsset != (Object)null) { return TMP_Settings.defaultFontAsset; } TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); return (array.Length != 0) ? array[0] : null; } } public static class TMPLocalizationFallbackFontRegistrar { private static readonly string[] TargetFontNames = new string[12] { "NotoSansArabic-Regular SDF", "NotoSansArmenian-Regular SDF", "NotoSansBengali-Regular SDF", "NotoSansDevanagari-Regular SDF", "NotoSansGeorgian-Regular SDF", "NotoSansHebrew-Regular SDF", "NotoSansJP-Regular SDF", "NotoSansKR-Regular SDF", "NotoSansMalayalam-Regular SDF", "NotoSansSC-Regular SDF", "NotoSansThai-Regular SDF", "NotoEmoji-Regular SDF" }; private const string WarningSubstring = "font asset or any potential fallbacks"; private static readonly HashSet<string> _pending = new HashSet<string>(TargetFontNames); private static bool _subscribed; public static void Initialize() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown if (!_subscribed) { RegisterAndReport(FindLocalizationFontAssets()); if (_pending.Count != 0) { _subscribed = true; Application.logMessageReceived += new LogCallback(OnLogMessageReceived); } } } private static void OnLogMessageReceived(string message, string stackTrace, LogType type) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 if (_pending.Count == 0) { Unsubscribe(); } else if ((int)type == 2 && message.Contains("font asset or any potential fallbacks")) { RegisterAndReport(FindLocalizationFontAssets()); if (_pending.Count == 0) { Unsubscribe(); } } } private static void Unsubscribe() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown Application.logMessageReceived -= new LogCallback(OnLogMessageReceived); _subscribed = false; } private static void RegisterAndReport(List<TMP_FontAsset> found) { if (found.Count == 0) { return; } List<string> list = new List<string>(); foreach (TMP_FontAsset item in found) { _pending.Remove(((Object)item).name); if (!TMP_Settings.fallbackFontAssets.Contains(item)) { TMP_Settings.fallbackFontAssets.Add(item); list.Add(((Object)item).name); } } if (list.Count > 0) { StringBuilder stringBuilder = new StringBuilder("[NullFix] Added "); stringBuilder.Append(list.Count); stringBuilder.Append(" localization fallback font(s) to TMP's global fallback list: "); stringBuilder.Append(string.Join(", ", list)); stringBuilder.Append(" - so text in those scripts (e.g. player nicknames, guild names, info panels) renders instead of showing blank spaces or missing-glyph boxes."); NullReferenceFixPlugin.NullReferenceFixLogger.LogWarning((object)stringBuilder.ToString()); } } private static List<TMP_FontAsset> FindLocalizationFontAssets() { List<TMP_FontAsset> list = new List<TMP_FontAsset>(); TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>(); TMP_FontAsset[] array2 = array; foreach (TMP_FontAsset val in array2) { if (_pending.Contains(((Object)val).name)) { list.Add(val); } } foreach (string name in _pending) { if (!list.Exists((TMP_FontAsset f) => ((Object)f).name == name)) { TMP_FontAsset val2 = Resources.Load<TMP_FontAsset>("Fonts & Materials/" + name); if ((Object)(object)val2 != (Object)null) { list.Add(val2); } } } return list; } } }