Decompiled source of Treasure Map Overhaul v1.0.5

Erenshor.TreasureMapOverhaul.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace TreasureMapOverhaul;

[HarmonyPatch(typeof(ItemDatabase), "GetItemByID", new Type[] { typeof(string) })]
public static class Bank_GetItemByID_Fallback
{
	private const string TornMapId = "99999999";

	private const string PreferredAssetName = "GEN - A Torn Map";

	public static void Postfix(ItemDatabase __instance, string __0, ref Item __result)
	{
		try
		{
			if (__0 != "99999999" || ((Object)(object)__result != (Object)null && !IsEmpty(__result)) || !TmoAssets.EnsureLoaded())
			{
				return;
			}
			Item val = null;
			if (!string.IsNullOrWhiteSpace("GEN - A Torn Map"))
			{
				val = TmoAssets.Load<Item>("GEN - A Torn Map");
			}
			if ((Object)(object)val == (Object)null)
			{
				val = ((IEnumerable<Item>)TmoAssets.LoadAll<Item>()).FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && ((BaseScriptableObject)i).Id == "99999999"));
			}
			if (!((Object)(object)val == (Object)null))
			{
				((BaseScriptableObject)val).Id = "99999999";
				List<Item> list = (__instance.ItemDB ?? Array.Empty<Item>()).ToList();
				list.RemoveAll((Item i) => (Object)(object)i != (Object)null && ((BaseScriptableObject)i).Id == "99999999");
				list.Add(val);
				__instance.ItemDB = list.ToArray();
				__result = val;
			}
		}
		catch (Exception arg)
		{
			Plugin.Log.LogError((object)$"[TMO] BankFallback: Exception {arg}");
		}
	}

	private static bool IsEmpty(Item item)
	{
		try
		{
			return item == GameData.PlayerInv.Empty || string.Equals(item.ItemName, "Empty", StringComparison.OrdinalIgnoreCase);
		}
		catch
		{
			return false;
		}
	}
}
[HarmonyPatch(typeof(GlobalBank), "LoadBank")]
public static class BankPatch
{
	private static readonly string[] OldMapNames = new string[4] { "GEN - Torn Map Top Left", "GEN - Torn Map Top Right", "GEN - Torn Map Bottom Left", "GEN - Torn Map Bottom Right" };

	private const string NewTornMapName = "GEN - A Torn Map";

	[HarmonyPostfix]
	public static void OnBankLoad(GlobalBank __instance)
	{
		try
		{
			if ((Object)(object)__instance == (Object)null)
			{
				Plugin.Log.LogError((object)"[TMO] BankPatch: GlobalBank instance is null.");
				return;
			}
			if (__instance.StoredItems == null || __instance.Quantities == null)
			{
				Plugin.Log.LogError((object)"[TMO] BankPatch: StoredItems or Quantities is null.");
				return;
			}
			Item val = GameData.ItemDB?.ItemDB?.FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && ((Object)i).name == "GEN - A Torn Map"));
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[TMO] BankPatch: 'GEN - A Torn Map' not found in ItemDB; skipping bank conversion.");
				return;
			}
			int num = 0;
			int num2 = Math.Min(__instance.StoredItems.Count, __instance.Quantities.Count);
			for (int j = 0; j < num2; j++)
			{
				Item val2 = __instance.StoredItems[j];
				if ((Object)(object)val2 != (Object)null && OldMapNames.Contains(((Object)val2).name))
				{
					num += Math.Max(0, __instance.Quantities[j]);
					__instance.StoredItems[j] = val;
				}
			}
			if (num <= 0)
			{
				return;
			}
			try
			{
				__instance.DisplayBankPage();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"[TMO] BankPatch: UI refresh failed after convert: {arg}");
			}
			try
			{
				__instance.SaveBank();
			}
			catch (Exception arg2)
			{
				Plugin.Log.LogError((object)$"[TMO] BankPatch: SaveBank failed after convert: {arg2}");
			}
		}
		catch (Exception arg3)
		{
			Plugin.Log.LogError((object)$"[TMO] BankPatch: Exception: {arg3}");
		}
	}
}
[HarmonyPatch(typeof(CharSelectManager), "Play")]
public static class InventoryPatch
{
	private static readonly string[] OldMapNames = new string[4] { "GEN - Torn Map Top Left", "GEN - Torn Map Top Right", "GEN - Torn Map Bottom Left", "GEN - Torn Map Bottom Right" };

	private const string NewTornMapName = "GEN - A Torn Map";

	[HarmonyPostfix]
	public static void OnCharacterEnter()
	{
		try
		{
			Inventory playerInv = GameData.PlayerInv;
			if ((Object)(object)playerInv == (Object)null)
			{
				Plugin.Log.LogError((object)"[TMO] InventoryPatch: PlayerInv is null.");
				return;
			}
			Item val = GameData.ItemDB?.ItemDB?.FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && ((Object)i).name == "GEN - A Torn Map"));
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[TMO] InventoryPatch: New map 'GEN - A Torn Map' not found in ItemDB; skipping migration.");
				return;
			}
			List<ItemIcon> storedSlots = playerInv.StoredSlots;
			if (storedSlots == null)
			{
				Plugin.Log.LogError((object)"[TMO] InventoryPatch: StoredSlots is null.");
				return;
			}
			int num = 0;
			for (int j = 0; j < storedSlots.Count; j++)
			{
				ItemIcon val2 = storedSlots[j];
				if (!((Object)(object)val2 == (Object)null))
				{
					Item myItem = val2.MyItem;
					if ((Object)(object)myItem != (Object)null && OldMapNames.Contains(((Object)myItem).name))
					{
						num += Math.Max(1, val2.Quantity);
						val2.MyItem = playerInv.Empty;
						val2.Quantity = 1;
						val2.UpdateSlotImage();
					}
				}
			}
			if (num <= 0)
			{
				return;
			}
			int num2 = 0;
			for (int k = 0; k < num; k++)
			{
				if (playerInv.AddItemToInv(val))
				{
					num2++;
				}
			}
		}
		catch (Exception arg)
		{
			Plugin.Log.LogError((object)$"[TMO] InventoryPatch exception: {arg}");
		}
	}
}
[HarmonyPatch(typeof(ItemDatabase), "Start")]
public static class ItemDBPatch
{
	private const string TornMapId = "99999999";

	private const string PreferredAssetName = "";

	[HarmonyPostfix]
	public static void InjectCustomItem(ItemDatabase __instance)
	{
		try
		{
			if ((Object)(object)__instance == (Object)null || __instance.ItemDB == null)
			{
				Plugin.Log.LogError((object)"[TMO] ItemDBPatch: ItemDatabase or ItemDB is null.");
			}
			else
			{
				if (!TmoAssets.EnsureLoaded())
				{
					return;
				}
				Item val = null;
				if (!string.IsNullOrWhiteSpace(""))
				{
					val = TmoAssets.Load<Item>("");
				}
				if ((Object)(object)val == (Object)null)
				{
					val = ((IEnumerable<Item>)TmoAssets.LoadAll<Item>()).FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && ((BaseScriptableObject)i).Id == "99999999"));
				}
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogError((object)"[TMO] Could not find custom Item in bundle (set PreferredAssetName or ensure Id == 99999999).");
					return;
				}
				((BaseScriptableObject)val).Id = "99999999";
				List<Item> list = __instance.ItemDB.ToList();
				list.RemoveAll((Item i) => (Object)(object)i != (Object)null && ((BaseScriptableObject)i).Id == "99999999");
				list.Add(val);
				__instance.ItemDB = list.ToArray();
				if (GameData.GM?.Maps != null)
				{
					GameData.GM.Maps.Clear();
					GameData.GM.Maps.Add(val);
				}
				else
				{
					Plugin.Log.LogWarning((object)"[TMO] GM.Maps not available.");
				}
			}
		}
		catch (Exception arg)
		{
			Plugin.Log.LogError((object)$"[TMO] ItemDBPatch failed: {arg}");
		}
	}
}
internal static class TmoIds
{
	internal const string TornMapId = "99999999";

	internal const string PreferredAssetName = "";
}
[HarmonyPatch(typeof(ItemDatabase), "GetItemByID", new Type[] { typeof(string) })]
public static class ItemDB_GetItemByID_Fallback
{
	public static void Postfix(ItemDatabase __instance, string __0, ref Item __result)
	{
		try
		{
			if (!string.Equals(__0, "99999999", StringComparison.Ordinal) || ((Object)(object)__result != (Object)null && !IsEmpty(__result)) || !TmoAssets.EnsureLoaded())
			{
				return;
			}
			Item val = null;
			if (!string.IsNullOrWhiteSpace(""))
			{
				val = TmoAssets.Load<Item>("");
			}
			if ((Object)(object)val == (Object)null)
			{
				val = ((IEnumerable<Item>)TmoAssets.LoadAll<Item>()).FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && ((BaseScriptableObject)i).Id == "99999999"));
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			((BaseScriptableObject)val).Id = "99999999";
			List<Item> list = (__instance.ItemDB ?? Array.Empty<Item>()).ToList();
			list.RemoveAll((Item i) => (Object)(object)i != (Object)null && ((BaseScriptableObject)i).Id == "99999999");
			list.Add(val);
			__instance.ItemDB = list.ToArray();
			__result = val;
			try
			{
				if (GameData.GM?.Maps != null)
				{
					GameData.GM.Maps.Clear();
					GameData.GM.Maps.Add(val);
				}
			}
			catch
			{
			}
		}
		catch (Exception arg)
		{
			Plugin.Log.LogWarning((object)$"[TMO] GetItemByID fallback failed: {arg}");
		}
	}

	private static bool IsEmpty(Item item)
	{
		try
		{
			return item == GameData.PlayerInv.Empty || string.Equals(item.ItemName, "Empty", StringComparison.OrdinalIgnoreCase);
		}
		catch
		{
			return false;
		}
	}
}
[HarmonyPatch(typeof(LootTable), "InitLootTable")]
public static class LootTable_InitLootTable_MapChance_Transpiler
{
	[HarmonyTranspiler]
	public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>(instructions);
		List<CodeInstruction> list2 = new List<CodeInstruction>(list.Count);
		bool flag = false;
		int num = 0;
		while (num < list.Count)
		{
			CodeInstruction val = list[num];
			if (!flag && val.opcode == OpCodes.Ldc_R4 && val.operand is float num2 && Mathf.Approximately(num2, 0.0125f))
			{
				list2.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(LootTable_InitLootTable_MapChance_Transpiler), "ConfigChance", (Type[])null, (Type[])null)));
				int num3 = num + 1;
				if (num3 < list.Count && IsLoadLike(list[num3]))
				{
					num3++;
				}
				if (num3 < list.Count && list[num3].opcode == OpCodes.Mul)
				{
					num3++;
				}
				num = num3;
				flag = true;
			}
			else
			{
				list2.Add(val);
				num++;
			}
		}
		if (!flag)
		{
			Plugin.Log.LogWarning((object)"[TMO] MapChance Transpiler: 0.0125f constant not found; map gate not patched.");
		}
		return list2;
	}

	private static bool IsLoadLike(CodeInstruction ci)
	{
		OpCode opcode = ci.opcode;
		return opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S || opcode == OpCodes.Ldloc_0 || opcode == OpCodes.Ldloc_1 || opcode == OpCodes.Ldloc_2 || opcode == OpCodes.Ldloc_3 || opcode == OpCodes.Ldsfld || opcode == OpCodes.Ldfld || opcode == OpCodes.Call;
	}

	public static float ConfigChance()
	{
		try
		{
			float normalizedChance = Plugin.GetNormalizedChance(Plugin.TreasureMapDropChancePercent);
			return Mathf.Clamp01(normalizedChance);
		}
		catch
		{
			return 0.0125f;
		}
	}
}
[BepInPlugin("et508.erenshor.treasuremapoverhaul", "Treasure Map Overhaul", "1.0.5")]
public class Plugin : BaseUnityPlugin
{
	internal static ManualLogSource Log;

	public static ConfigEntry<float> TreasureMapDropChancePercent;

	private void Awake()
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected O, but got Unknown
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		TreasureMapDropChancePercent = ((BaseUnityPlugin)this).Config.Bind<float>("Drop Chance", "TreasureMapDropChance", 1.25f, new ConfigDescription("Chance to drop A Torn Treasure Map (0.0-100%). Default: 2.0%. Reload scene or wait for new respawns for changes to apply.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
		Log = ((BaseUnityPlugin)this).Logger;
		Log.LogInfo((object)"Treasure Map Overhaul loaded.");
		Harmony val = new Harmony("et508.erenshor.treasuremapoverhaul");
		val.PatchAll();
	}

	public static float GetNormalizedChance(ConfigEntry<float> entry)
	{
		return Mathf.Clamp01(entry.Value / 100f);
	}
}
[HarmonyPatch(typeof(QuestDB), "Start")]
public static class QuestDBPatch
{
	private const string PreferredQuestAssetName = "Treasure Map Repair";

	private const string TargetQuestDbName = "TreasureMap";

	[HarmonyPostfix]
	public static void Postfix(QuestDB __instance)
	{
		try
		{
			if ((Object)(object)__instance == (Object)null)
			{
				Plugin.Log.LogError((object)"[TMO] QuestReplace: __instance is null.");
				return;
			}
			GameObject gameObject = ((Component)__instance).gameObject;
			if ((Object)(object)gameObject.GetComponent<TmoQuestReplacer>() == (Object)null)
			{
				TmoQuestReplacer tmoQuestReplacer = gameObject.AddComponent<TmoQuestReplacer>();
				tmoQuestReplacer.Init(__instance, "Treasure Map Repair", "TreasureMap");
			}
		}
		catch (Exception arg)
		{
			Plugin.Log.LogError((object)$"[TMO] QuestReplace: Exception in Postfix: {arg}");
		}
	}
}
public class TmoQuestReplacer : MonoBehaviour
{
	[CompilerGenerated]
	private sealed class <Run>d__5 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public TmoQuestReplacer <>4__this;

		private float <timeoutAt>5__1;

		private Quest <donor>5__2;

		private Quest <live>5__3;

		private Quest[] <all>5__4;

		private string <json>5__5;

		private Exception <ex>5__6;

		private Exception <ex>5__7;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <Run>d__5(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<donor>5__2 = null;
			<live>5__3 = null;
			<all>5__4 = null;
			<json>5__5 = null;
			<ex>5__6 = null;
			<ex>5__7 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				<timeoutAt>5__1 = Time.realtimeSinceStartup + 15f;
				break;
			case 2:
				<>1__state = -1;
				break;
			}
			if ((Object)(object)GameData.ItemDB == (Object)null)
			{
				if (Time.realtimeSinceStartup > <timeoutAt>5__1)
				{
					Plugin.Log.LogError((object)"[TMO] QuestReplace: Timed out waiting for GameData.ItemDB.");
					Object.Destroy((Object)(object)<>4__this);
					return false;
				}
				<>2__current = null;
				<>1__state = 2;
				return true;
			}
			if (!TmoAssets.EnsureLoaded())
			{
				Plugin.Log.LogError((object)"[TMO] QuestReplace: Asset bundle not available.");
				Object.Destroy((Object)(object)<>4__this);
				return false;
			}
			<donor>5__2 = null;
			if (!string.IsNullOrWhiteSpace(<>4__this._questAssetName))
			{
				<donor>5__2 = TmoAssets.Load<Quest>(<>4__this._questAssetName);
				if ((Object)(object)<donor>5__2 == (Object)null)
				{
					Plugin.Log.LogWarning((object)("[TMO] QuestReplace: Preferred quest asset '" + <>4__this._questAssetName + "' not found in bundle."));
				}
			}
			if ((Object)(object)<donor>5__2 == (Object)null)
			{
				<all>5__4 = TmoAssets.LoadAll<Quest>();
				<donor>5__2 = ((IEnumerable<Quest>)<all>5__4).FirstOrDefault((Func<Quest, bool>)((Quest q) => (Object)(object)q != (Object)null && MatchesQuest(q, <>4__this._targetDbName)));
				<all>5__4 = null;
			}
			if ((Object)(object)<donor>5__2 == (Object)null)
			{
				Plugin.Log.LogError((object)"[TMO] QuestReplace: Could not find donor Quest in bundle.");
				Object.Destroy((Object)(object)<>4__this);
				return false;
			}
			<live>5__3 = FindLiveQuest(<>4__this._questDb, <>4__this._targetDbName);
			if ((Object)(object)<live>5__3 == (Object)null)
			{
				Plugin.Log.LogError((object)"[TMO] QuestReplace: Target quest not found in QuestDB.");
				Object.Destroy((Object)(object)<>4__this);
				return false;
			}
			try
			{
				<json>5__5 = JsonUtility.ToJson((object)<donor>5__2);
				JsonUtility.FromJsonOverwrite(<json>5__5, (object)<live>5__3);
				<json>5__5 = null;
			}
			catch (Exception ex)
			{
				<ex>5__6 = ex;
				Plugin.Log.LogError((object)$"[TMO] QuestReplace: FromJsonOverwrite failed: {<ex>5__6}");
			}
			try
			{
				RemapQuestItemsToLiveDB_ByNameThenId(<live>5__3, GameData.ItemDB);
			}
			catch (Exception ex)
			{
				<ex>5__7 = ex;
				Plugin.Log.LogWarning((object)$"[TMO] QuestReplace: Remap failed: {<ex>5__7}");
			}
			Object.Destroy((Object)(object)<>4__this);
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	private QuestDB _questDb;

	private string _questAssetName;

	private string _targetDbName;

	public void Init(QuestDB questDb, string questAssetName, string targetDbName)
	{
		_questDb = questDb;
		_questAssetName = questAssetName;
		_targetDbName = targetDbName;
	}

	private void OnEnable()
	{
		((MonoBehaviour)this).StartCoroutine(Run());
	}

	[IteratorStateMachine(typeof(<Run>d__5))]
	private IEnumerator Run()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <Run>d__5(0)
		{
			<>4__this = this
		};
	}

	private static bool MatchesQuest(Quest q, string dbName)
	{
		if ((Object)(object)q == (Object)null)
		{
			return false;
		}
		if (string.IsNullOrWhiteSpace(dbName))
		{
			return false;
		}
		FieldInfo field = ((object)q).GetType().GetField("DBName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field != null)
		{
			string a = field.GetValue(q) as string;
			return string.Equals(a, dbName, StringComparison.OrdinalIgnoreCase);
		}
		return false;
	}

	private static Quest FindLiveQuest(QuestDB db, string dbName)
	{
		try
		{
			if (!(((object)db).GetType().GetField("QuestDatabase", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(db) is Quest[] source))
			{
				return null;
			}
			return ((IEnumerable<Quest>)source).FirstOrDefault((Func<Quest, bool>)((Quest q) => (Object)(object)q != (Object)null && MatchesQuest(q, dbName)));
		}
		catch
		{
			return null;
		}
	}

	private static string GetQuestName(Quest q)
	{
		try
		{
			string text = ((object)q).GetType().GetField("DBName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(q) as string;
			return string.IsNullOrEmpty(text) ? ((Object)q).name : text;
		}
		catch
		{
			return ((q != null) ? ((Object)q).name : null) ?? "(null)";
		}
	}

	private static void RemapQuestItemsToLiveDB_ByNameThenId(Quest quest, ItemDatabase liveDb)
	{
		if ((Object)(object)quest == (Object)null || (Object)(object)liveDb == (Object)null)
		{
			return;
		}
		FieldInfo field = ((object)quest).GetType().GetField("RequiredItems", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field == null)
		{
			return;
		}
		object value = field.GetValue(quest);
		if (value is Item[] array)
		{
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = FindLiveByNameThenId(liveDb, array[i]) ?? array[i];
			}
			field.SetValue(quest, array);
		}
		else if (value is List<Item> list)
		{
			for (int j = 0; j < list.Count; j++)
			{
				list[j] = FindLiveByNameThenId(liveDb, list[j]) ?? list[j];
			}
			field.SetValue(quest, list);
		}
	}

	private static Item FindLiveByNameThenId(ItemDatabase db, Item donorItem)
	{
		if ((Object)(object)donorItem == (Object)null)
		{
			return null;
		}
		string donorName = ((Object)donorItem).name;
		if (!string.IsNullOrEmpty(donorName))
		{
			Item val = db.ItemDB?.FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && ((Object)i).name == donorName));
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
		}
		string donorId = GetItemId(donorItem);
		if (!string.IsNullOrEmpty(donorId))
		{
			Item val2 = db.ItemDB?.FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && GetItemId(i) == donorId));
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
		}
		return null;
	}

	private static string GetItemId(Item it)
	{
		try
		{
			FieldInfo field = ((object)it).GetType().GetField("Id", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field?.FieldType == typeof(string))
			{
				return (string)field.GetValue(it);
			}
			PropertyInfo property = ((object)it).GetType().GetProperty("Id", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property?.PropertyType == typeof(string))
			{
				return (string)property.GetValue(it, null);
			}
		}
		catch
		{
		}
		return null;
	}
}
internal static class TmoAssets
{
	internal const string BundleFileName = "tmo_assets";

	private static AssetBundle _bundle;

	private static bool _loggedAttempt;

	internal static AssetBundle Bundle => _bundle;

	internal static bool EnsureLoaded()
	{
		if ((Object)(object)_bundle != (Object)null)
		{
			return true;
		}
		if (!_loggedAttempt)
		{
			_loggedAttempt = true;
			Plugin.Log.LogInfo((object)"[TMO] Loading shared asset bundle…");
		}
		try
		{
			string directoryName = Path.GetDirectoryName(typeof(Plugin).Assembly.Location);
			string text = Path.Combine(directoryName ?? ".", "tmo_assets");
			_bundle = AssetBundle.LoadFromFile(text);
			if ((Object)(object)_bundle == (Object)null)
			{
				Plugin.Log.LogError((object)("[TMO] Failed to load AssetBundle at: " + text));
				return false;
			}
			return true;
		}
		catch (Exception arg)
		{
			Plugin.Log.LogError((object)$"[TMO] EnsureLoaded exception: {arg}");
			return false;
		}
	}

	internal static T Load<T>(string name) where T : Object
	{
		if (!EnsureLoaded())
		{
			return default(T);
		}
		try
		{
			return _bundle.LoadAsset<T>(name);
		}
		catch (Exception arg)
		{
			Plugin.Log.LogError((object)$"[TMO] Load<{typeof(T).Name}>('{name}') failed: {arg}");
			return default(T);
		}
	}

	internal static T[] LoadAll<T>() where T : Object
	{
		if (!EnsureLoaded())
		{
			return Array.Empty<T>();
		}
		try
		{
			return _bundle.LoadAllAssets<T>();
		}
		catch (Exception arg)
		{
			Plugin.Log.LogError((object)$"[TMO] LoadAll<{typeof(T).Name}> failed: {arg}");
			return Array.Empty<T>();
		}
	}
}
[HarmonyPatch(typeof(Water), "Start")]
public static class WaterPatch
{
	private const string OldFishableName = "GEN - Torn Map Top Right";

	private const string NewTornMapName = "GEN - A Torn Map";

	[HarmonyPostfix]
	public static void OnWaterStart(Water __instance)
	{
		try
		{
			if ((Object)(object)__instance == (Object)null)
			{
				Plugin.Log.LogError((object)"[TMO] WaterPatch: Water instance is null.");
				return;
			}
			Item val = GameData.ItemDB?.ItemDB?.FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && ((Object)i).name == "GEN - A Torn Map"));
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[TMO] WaterPatch: Torn Map 'GEN - A Torn Map' not found in ItemDB; skipping fishable replacement.");
				return;
			}
			int num = 0;
			num += ReplaceInList(__instance.DayFishables, val);
			num += ReplaceInList(__instance.NightFishables, val);
			num += ReplaceInList(__instance.Fishables, val);
			if (num > 0)
			{
				Plugin.Log.LogInfo((object)string.Format("[TMO] WaterPatch: Replaced {0} old fishable map entries with Torn Map '{1}'.", num, "GEN - A Torn Map"));
			}
		}
		catch (Exception arg)
		{
			Plugin.Log.LogError((object)$"[TMO] WaterPatch exception: {arg}");
		}
	}

	private static int ReplaceInList(List<Item> list, Item tornMap)
	{
		if (list == null)
		{
			return 0;
		}
		int num = 0;
		for (int i = 0; i < list.Count; i++)
		{
			Item val = list[i];
			if ((Object)(object)val != (Object)null && ((Object)val).name == "GEN - Torn Map Top Right")
			{
				list[i] = tornMap;
				num++;
			}
		}
		return num;
	}
}