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 ValheimWorldConvertDiag v1.2.0
ValheimWorldConvertDiag.dll
Decompiled 5 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ValheimWorldConvertDiag")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ValheimWorldConvertDiag")] [assembly: AssemblyTitle("ValheimWorldConvertDiag")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ValheimWorldConvertDiag { [BepInPlugin("sonicdm.valheimworldconvertdiag", "Valheim World Convert Diagnostic", "1.2.0")] public sealed class ValheimWorldConvertDiagPlugin : BaseUnityPlugin { public const string PluginGuid = "sonicdm.valheimworldconvertdiag"; public const string PluginName = "Valheim World Convert Diagnostic"; public const string PluginVersion = "1.2.0"; internal static ManualLogSource Log; internal static readonly object Sync = new object(); internal static bool InWorldConversion; internal static string CurrentInventory = "<none>"; internal static string CurrentZdo = "<none>"; internal static string InventorySourceZdo = "<none>"; internal static string LastNamedItem = "<none>"; internal static string LastTempItem = "<none>"; internal static string LastComparison = "<none>"; internal static readonly Queue<string> RecentNamedItems = new Queue<string>(); internal static string DiagnosticFile; private Harmony _harmony; private const BindingFlags AllMethods = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private void Awake() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; DiagnosticFile = GetDiagnosticPath(); Write("============================================================"); Write("Valheim World Convert Diagnostic 1.2.0 loading"); Write("Diagnostic file: " + DiagnosticFile); try { _harmony = new Harmony("sonicdm.valheimworldconvertdiag"); PatchRequiredMethods(_harmony); Write("Diagnostic patches installed successfully."); Write("Waiting for ZDOMan.ConvertInventories(). No world data is modified by this plugin."); } catch (Exception ex) { Write("FATAL: Failed to install diagnostic patches:\n" + ex); throw; } } private void OnDestroy() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } private static void PatchRequiredMethods(Harmony harmony) { //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Expected O, but got Unknown //IL_02a6: Expected O, but got Unknown //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Expected O, but got Unknown //IL_02dc: Expected O, but got Unknown //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Expected O, but got Unknown //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Expected O, but got Unknown //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Expected O, but got Unknown //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Expected O, but got Unknown Type type = FindType("ZDOMan"); Type type2 = FindType("Inventory"); Type type3 = FindType("ItemDrop+ItemData"); Type type4 = FindType("ZDO"); if (type == null) { throw new TypeLoadException("Could not find Valheim type ZDOMan"); } if (type2 == null) { throw new TypeLoadException("Could not find Valheim type Inventory"); } if (type3 == null) { throw new TypeLoadException("Could not find Valheim type ItemDrop+ItemData"); } if (type4 == null) { throw new TypeLoadException("Could not find Valheim type ZDO"); } MethodInfo methodInfo = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "ConvertInventories"); if (methodInfo == null) { throw new MissingMethodException("Could not find ZDOMan.ConvertInventories"); } MethodInfo methodInfo2 = type2.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "LoadOld"); if (methodInfo2 == null) { throw new MissingMethodException("Could not find Inventory.LoadOld"); } List<MethodInfo> list = (from m in type2.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "AddItem" select m).Where(delegate(MethodInfo m) { ParameterInfo[] parameters = m.GetParameters(); return parameters.Length != 0 && parameters[0].ParameterType == typeof(string); }).ToList(); if (list.Count == 0) { throw new MissingMethodException("Could not find Inventory.AddItem(string, ...)"); } List<MethodInfo> list2 = (from m in type2.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "AddTempItem" select m).Where(delegate(MethodInfo m) { ParameterInfo[] parameters = m.GetParameters(); return parameters.Length != 0 && parameters[0].ParameterType == typeof(int); }).ToList(); if (list2.Count == 0) { throw new MissingMethodException("Could not find Inventory.AddTempItem(int, ...)"); } List<MethodInfo> list3 = (from m in type3.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "IsSameType" select m).ToList(); if (list3.Count == 0) { throw new MissingMethodException("Could not find ItemDrop.ItemData.IsSameType"); } List<MethodInfo> list4 = (from m in type4.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "GetString" || m.Name == "GetByteArray" || m.Name == "GetBytes" select m).Where(delegate(MethodInfo m) { ParameterInfo[] parameters = m.GetParameters(); return parameters.Length != 0 && (parameters[0].ParameterType == typeof(string) || parameters[0].ParameterType == typeof(int)); }).ToList(); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ValheimWorldConvertDiagPlugin), "ConvertInventoriesPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ValheimWorldConvertDiagPlugin), "ConvertInventoriesFinalizer", (Type[])null), (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(ValheimWorldConvertDiagPlugin), "InventoryLoadOldPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ValheimWorldConvertDiagPlugin), "InventoryLoadOldFinalizer", (Type[])null), (HarmonyMethod)null); foreach (MethodInfo item in list) { harmony.Patch((MethodBase)item, new HarmonyMethod(typeof(ValheimWorldConvertDiagPlugin), "AddItemStringPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } foreach (MethodInfo item2 in list2) { harmony.Patch((MethodBase)item2, new HarmonyMethod(typeof(ValheimWorldConvertDiagPlugin), "AddTempItemPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } foreach (MethodInfo item3 in list3) { harmony.Patch((MethodBase)item3, new HarmonyMethod(typeof(ValheimWorldConvertDiagPlugin), "IsSameTypePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } foreach (MethodInfo item4 in list4) { harmony.Patch((MethodBase)item4, new HarmonyMethod(typeof(ValheimWorldConvertDiagPlugin), "ZdoInventoryGetterPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } Write($"Patched: ConvertInventories=1, LoadOld=1, AddItem(string)={list.Count}, AddTempItem={list2.Count}, IsSameType={list3.Count}, ZDO inventory getters={list4.Count}"); } public static void ConvertInventoriesPrefix(MethodBase __originalMethod, object[] __args) { SafeDiagnostic(delegate { lock (Sync) { InWorldConversion = true; CurrentInventory = "<not started>"; CurrentZdo = "<none yet>"; InventorySourceZdo = "<none yet>"; LastNamedItem = "<none>"; LastTempItem = "<none>"; LastComparison = "<none>"; RecentNamedItems.Clear(); } Write("=== LEGACY WORLD INVENTORY CONVERSION STARTED ==="); Write("ConvertInventories args: " + FormatArguments(__originalMethod, __args)); }); } public static Exception ConvertInventoriesFinalizer(Exception __exception) { SafeDiagnostic(delegate { if (__exception != null) { Write("=== ConvertInventories EXITED WITH EXCEPTION ==="); WriteFailureReport(__exception, null); } else { Write("=== LEGACY WORLD INVENTORY CONVERSION COMPLETED ==="); } lock (Sync) { InWorldConversion = false; } }); return __exception; } public static void InventoryLoadOldPrefix(object __instance, MethodBase __originalMethod, object[] __args) { if (!InWorldConversion) { return; } SafeDiagnostic(delegate { lock (Sync) { CurrentInventory = DescribeInventory(__instance); InventorySourceZdo = CurrentZdo; LastNamedItem = "<none in this inventory yet>"; LastTempItem = "<none in this inventory yet>"; LastComparison = "<none in this inventory yet>"; RecentNamedItems.Clear(); } }); } public static Exception InventoryLoadOldFinalizer(Exception __exception, object __instance) { if (!InWorldConversion || __exception == null) { return __exception; } SafeDiagnostic(delegate { Write("!!! Inventory.LoadOld FAILED !!!"); WriteFailureReport(__exception, __instance); }); return __exception; } public static void AddItemStringPrefix(MethodBase __originalMethod, object __instance, object[] __args) { if (!InWorldConversion) { return; } SafeDiagnostic(delegate { string text = FormatArguments(__originalMethod, __args); lock (Sync) { CurrentInventory = DescribeInventory(__instance); LastNamedItem = text; RecentNamedItems.Enqueue(text); while (RecentNamedItems.Count > 12) { RecentNamedItems.Dequeue(); } } }); } public static void AddTempItemPrefix(MethodBase __originalMethod, object __instance, object[] __args) { if (!InWorldConversion) { return; } SafeDiagnostic(delegate { lock (Sync) { CurrentInventory = DescribeInventory(__instance); LastTempItem = FormatArguments(__originalMethod, __args); } }); } public static void ZdoInventoryGetterPrefix(object __instance, MethodBase __originalMethod, object[] __args) { if (!InWorldConversion || __args == null || __args.Length == 0) { return; } SafeDiagnostic(delegate { object obj = __args[0]; bool flag = false; if (obj is string a) { flag = string.Equals(a, "items", StringComparison.Ordinal); } else if (obj is int num) { flag = num == StableHash("items"); } if (!flag) { return; } lock (Sync) { CurrentZdo = DescribeZdo(__instance); } }); } public static void IsSameTypePrefix(object __instance, MethodBase __originalMethod, object[] __args) { if (!InWorldConversion) { return; } SafeDiagnostic(delegate { object item = ((__args != null && __args.Length != 0) ? __args[0] : null); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("THIS ItemData:"); stringBuilder.AppendLine(DescribeItemData(__instance)); stringBuilder.AppendLine("OTHER ItemData:"); stringBuilder.AppendLine(DescribeItemData(item)); lock (Sync) { LastComparison = stringBuilder.ToString().TrimEnd(); } }); } private static void WriteFailureReport(Exception ex, object inventoryInstance) { string currentInventory; string inventorySourceZdo; string lastNamedItem; string lastTempItem; string lastComparison; string[] array; lock (Sync) { currentInventory = CurrentInventory; inventorySourceZdo = InventorySourceZdo; lastNamedItem = LastNamedItem; lastTempItem = LastTempItem; lastComparison = LastComparison; array = RecentNamedItems.ToArray(); } Write("---------------- CONVERSION FAILURE REPORT ----------------"); Write("Inventory snapshot: " + ((inventoryInstance != null) ? DescribeInventory(inventoryInstance) : currentInventory)); Write("Source ZDO candidate: " + inventorySourceZdo); Write("Last Inventory.AddItem(string, ...) call:\n" + lastNamedItem); Write("Last Inventory.AddTempItem(int prefabHash, ...) call:\n" + lastTempItem); Write("Last ItemData.IsSameType comparison:\n" + lastComparison); if (array.Length != 0) { Write("Recent named items in this inventory, oldest -> newest:"); for (int i = 0; i < array.Length; i++) { Write($" [{i + 1:00}] {array[i]}"); } } Write("Exception:\n" + ex); Write("-----------------------------------------------------------"); } private static string DescribeZdo(object zdo) { if (zdo == null) { return "<null ZDO>"; } try { List<string> list = new List<string>(); list.Add("type=" + zdo.GetType().FullName); string[] array = new string[7] { "m_uid", "m_position", "m_sector", "m_prefab", "m_type", "m_owner", "m_dataRevision" }; foreach (string text in array) { object memberValue = GetMemberValue(zdo, text); if (memberValue != null) { list.Add(text + "=" + FormatSimple(memberValue)); } } array = new string[2] { "GetPosition", "GetPrefab" }; foreach (string methodName in array) { try { MethodInfo methodInfo = zdo.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo x) => x.Name == methodName && x.GetParameters().Length == 0); if (methodInfo != null) { object obj = methodInfo.Invoke(zdo, null); if (obj != null) { list.Add(methodName + "=" + FormatSimple(obj)); } } } catch { } } return string.Join(", ", list); } catch (Exception ex) { return "<failed to describe ZDO: " + ex.GetType().Name + ": " + ex.Message + ">"; } } private static int StableHash(string str) { int num = 5381; int num2 = num; for (int i = 0; i < str.Length && str[i] != 0; i += 2) { num = ((num << 5) + num) ^ str[i]; if (i == str.Length - 1 || str[i + 1] == '\0') { break; } num2 = ((num2 << 5) + num2) ^ str[i + 1]; } return num + num2 * 1566083941; } private static string DescribeInventory(object inventory) { if (inventory == null) { return "<null Inventory>"; } try { object memberValue = GetMemberValue(inventory, "m_name"); object memberValue2 = GetMemberValue(inventory, "m_width"); object memberValue3 = GetMemberValue(inventory, "m_height"); int? collectionCount = GetCollectionCount(GetMemberValue(inventory, "m_inventory")); return "type=" + inventory.GetType().FullName + ", name=" + FormatSimple(memberValue) + ", size=" + FormatSimple(memberValue2) + "x" + FormatSimple(memberValue3) + ", loadedItemCount=" + (collectionCount.HasValue ? collectionCount.Value.ToString() : "?"); } catch (Exception ex) { return "<failed to describe Inventory: " + ex.Message + ">"; } } private static string DescribeItemData(object item) { if (item == null) { return " <null>"; } try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(" runtimeType=" + item.GetType().FullName); AppendMember(stringBuilder, item, "m_dropPrefab", describeUnityName: true); AppendMember(stringBuilder, item, "m_stack"); AppendMember(stringBuilder, item, "m_durability"); AppendMember(stringBuilder, item, "m_quality"); AppendMember(stringBuilder, item, "m_variant"); AppendMember(stringBuilder, item, "m_crafterID"); AppendMember(stringBuilder, item, "m_crafterName"); AppendMember(stringBuilder, item, "m_worldLevel"); AppendMember(stringBuilder, item, "m_equipped"); AppendMember(stringBuilder, item, "m_gridPos"); object memberValue = GetMemberValue(item, "m_shared"); if (memberValue == null) { stringBuilder.AppendLine(" m_shared=<null> <<< IMPORTANT"); } else { stringBuilder.AppendLine(" m_shared.runtimeType=" + memberValue.GetType().FullName); AppendMember(stringBuilder, memberValue, "m_name", describeUnityName: false, " m_shared."); AppendMember(stringBuilder, memberValue, "m_itemType", describeUnityName: false, " m_shared."); AppendMember(stringBuilder, memberValue, "m_maxStackSize", describeUnityName: false, " m_shared."); AppendMember(stringBuilder, memberValue, "m_maxQuality", describeUnityName: false, " m_shared."); AppendMember(stringBuilder, memberValue, "m_weight", describeUnityName: false, " m_shared."); AppendMember(stringBuilder, memberValue, "m_dlc", describeUnityName: false, " m_shared."); } return stringBuilder.ToString().TrimEnd(); } catch (Exception ex) { return " <failed to describe ItemData: " + ex?.ToString() + ">"; } } private static void AppendMember(StringBuilder sb, object obj, string memberName, bool describeUnityName = false, string prefix = " ") { object memberValue = GetMemberValue(obj, memberName); string text = (describeUnityName ? DescribeUnityObject(memberValue) : FormatSimple(memberValue)); sb.AppendLine(prefix + memberName + "=" + text); } private static string DescribeUnityObject(object value) { if (value == null) { return "<null> <<< IMPORTANT"; } try { object memberValue = GetMemberValue(value, "name"); if (memberValue != null) { return value.GetType().FullName + " name=" + FormatSimple(memberValue); } } catch { } return "<" + value.GetType().FullName + ">"; } private static string FormatArguments(MethodBase method, object[] args) { try { ParameterInfo[] parameters = method.GetParameters(); List<string> list = new List<string>(); int num = Math.Max(parameters.Length, (args != null) ? args.Length : 0); for (int i = 0; i < num; i++) { string text = ((i < parameters.Length) ? parameters[i].Name : ("arg" + i)); object value = ((args != null && i < args.Length) ? args[i] : null); list.Add(text + "=" + FormatSimple(value)); } return method.DeclaringType?.FullName + "." + method.Name + "(" + string.Join(", ", list.ToArray()) + ")"; } catch (Exception ex) { return "<failed to format method arguments: " + ex.Message + ">"; } } private static string FormatSimple(object value) { if (value == null) { return "<null>"; } Type type = value.GetType(); if (value is string text) { return "\"" + text.Replace("\r", "\\r").Replace("\n", "\\n") + "\""; } if (type.IsPrimitive || type.IsEnum || value is decimal) { return Convert.ToString(value, CultureInfo.InvariantCulture); } if (value is IDictionary dictionary) { return $"<{type.FullName} Count={dictionary.Count}>"; } if (value is ICollection collection) { return $"<{type.FullName} Count={collection.Count}>"; } if (type.IsValueType) { try { return value.ToString(); } catch { return "<" + type.FullName + ">"; } } return "<" + type.FullName + ">"; } private static object GetMemberValue(object instance, string name) { if (instance == null) { return null; } Type type = instance.GetType(); while (type != null) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(instance); } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.GetIndexParameters().Length == 0) { return property.GetValue(instance, null); } type = type.BaseType; } return null; } private static int? GetCollectionCount(object value) { if (value == null) { return null; } if (value is ICollection collection) { return collection.Count; } PropertyInfo property = value.GetType().GetProperty("Count", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object value2 = property.GetValue(value, null); if (value2 is int) { return (int)value2; } } return null; } private static Type FindType(string fullName) { Type type = AccessTools.TypeByName(fullName); if (type != null) { return type; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type2 = assemblies[i].GetType(fullName, throwOnError: false); if (type2 != null) { return type2; } } return null; } private static string GetDiagnosticPath() { try { if (Directory.Exists("/config/bepinex")) { return Path.Combine("/config/bepinex", "ValheimWorldConvertDiag.log"); } } catch { } try { return Path.Combine(Paths.ConfigPath, "ValheimWorldConvertDiag.log"); } catch { return Path.Combine(Environment.CurrentDirectory, "ValheimWorldConvertDiag.log"); } } private static void SafeDiagnostic(Action action) { try { action(); } catch (Exception ex) { try { Write("Diagnostic code caught its own exception and ignored it: " + ex); } catch { } } } private static void Write(string message) { string text = "[ValheimWorldConvertDiag] " + message; try { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)message); } } catch { } try { lock (Sync) { File.AppendAllText(DiagnosticFile, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " " + text + Environment.NewLine); } } catch { } } } }