Decompiled source of ValheimWorldConvertDiag v1.2.0

ValheimWorldConvertDiag.dll

Decompiled 5 hours ago
using 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
			{
			}
		}
	}
}