Decompiled source of Valheim Blue Archive Mod v1.1.0

plugins/Valheim_Blue_Archive_Mod.dll

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

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ValheimBlueArchiveMod;

[BepInPlugin("com.ayok.valheim.bluearchive", "Valheim_Blue_Archive_Mod", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class BlueArchivePlugin : BaseUnityPlugin
{
	public class KeptItemData
	{
		public ItemData Item { get; }

		public bool WasEquipped { get; }

		public bool IsTool { get; }

		public KeptItemData(ItemData item, bool wasEquipped, bool isTool)
		{
			Item = item;
			WasEquipped = wasEquipped;
			IsTool = isTool;
		}
	}

	[HarmonyPatch(typeof(Player), "CreateTombStone")]
	[HarmonyAfter(new string[] { "randyknapp.mods.equipmentandquickslots" })]
	public static class CreateTombStone_Patch
	{
		[HarmonyPrefix]
		[HarmonyAfter(new string[] { "randyknapp.mods.equipmentandquickslots" })]
		public static bool Prefix(Player __instance, out List<KeptItemData> __state)
		{
			__state = new List<KeptItemData>();
			if (!ModEnabled.Value || (Object)(object)__instance == (Object)null)
			{
				return true;
			}
			if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (VanillaKeepsEntireInventory())
			{
				return true;
			}
			Inventory inventory = ((Humanoid)__instance).GetInventory();
			if (inventory == null)
			{
				return true;
			}
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems == null)
			{
				return true;
			}
			try
			{
				for (int num = allItems.Count - 1; num >= 0; num--)
				{
					ItemData item = allItems[num];
					if (ShouldKeepItem(__instance, item))
					{
						bool wasEquipped = IsEquipped(__instance, item);
						bool isTool = IsTool(item);
						__state.Add(new KeptItemData(item, wasEquipped, isTool));
						allItems.RemoveAt(num);
					}
				}
				if (__state.Count > 0)
				{
					int num2 = 0;
					int num3 = 0;
					for (int i = 0; i < __state.Count; i++)
					{
						if (__state[i].WasEquipped)
						{
							num3++;
						}
						else if (__state[i].IsTool)
						{
							num2++;
						}
					}
					if (Log != null)
					{
						Log.LogInfo((object)("Player '" + __instance.GetPlayerName() + "' died: preserving " + num2 + " unequipped tools and " + num3 + " equipped items that vanilla would have dropped."));
					}
				}
				return HasDroppableRemainder(allItems);
			}
			catch (Exception ex)
			{
				if (Log != null)
				{
					Log.LogError((object)("Error in CreateTombStone Prefix: " + ex));
				}
				return true;
			}
		}

		[HarmonyPostfix]
		[HarmonyAfter(new string[] { "randyknapp.mods.equipmentandquickslots" })]
		public static void Postfix(Player __instance, List<KeptItemData> __state)
		{
			if (!ModEnabled.Value || (Object)(object)__instance == (Object)null || __state == null || __state.Count == 0 || ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				return;
			}
			Inventory inventory = ((Humanoid)__instance).GetInventory();
			if (inventory == null)
			{
				return;
			}
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems == null)
			{
				return;
			}
			try
			{
				int num = 0;
				int num2 = 0;
				for (int i = 0; i < __state.Count; i++)
				{
					KeptItemData keptItemData = __state[i];
					if (keptItemData.Item != null)
					{
						keptItemData.Item.m_equipped = keptItemData.WasEquipped;
						if (!allItems.Contains(keptItemData.Item))
						{
							allItems.Add(keptItemData.Item);
						}
						if (keptItemData.WasEquipped)
						{
							num2++;
						}
						else if (keptItemData.IsTool)
						{
							num++;
						}
					}
				}
				if (inventory.m_onChanged != null)
				{
					inventory.m_onChanged();
				}
				if (NotificationOnDeath.Value && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && (num > 0 || num2 > 0))
				{
					((Character)__instance).Message((MessageType)2, "Death Protection: " + num + " tools & " + num2 + " equipped items preserved.", 0, (Sprite)null, false);
				}
			}
			catch (Exception ex)
			{
				if (Log != null)
				{
					Log.LogError((object)("Error in CreateTombStone Postfix: " + ex));
				}
			}
		}

		private static bool HasDroppableRemainder(List<ItemData> inventoryList)
		{
			for (int i = 0; i < inventoryList.Count; i++)
			{
				ItemData val = inventoryList[i];
				if (val != null && val.m_shared != null && !val.m_shared.m_questItem)
				{
					return true;
				}
			}
			return false;
		}
	}

	public const string ModGUID = "com.ayok.valheim.bluearchive";

	public const string ModName = "Valheim_Blue_Archive_Mod";

	public const string ModVersion = "1.1.0";

	public const string EquipmentAndQuickSlotsGUID = "randyknapp.mods.equipmentandquickslots";

	public static ConfigEntry<bool> ModEnabled;

	public static ConfigEntry<bool> KeepTools;

	public static ConfigEntry<bool> KeepEquippedItems;

	public static ConfigEntry<bool> NotificationOnDeath;

	public static ConfigEntry<bool> KeepBuildingAndFarmingTools;

	public static ConfigEntry<bool> KeepPickaxes;

	public static ConfigEntry<bool> KeepAxes;

	public static ConfigEntry<bool> KeepFishingRod;

	public static ConfigEntry<bool> KeepButcherKnife;

	public static ConfigEntry<string> IncludePrefabs;

	public static ConfigEntry<string> ExcludePrefabs;

	private static readonly HashSet<string> IncludeList = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private static readonly HashSet<string> ExcludeList = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private Harmony _harmony;

	public static BlueArchivePlugin Instance { get; private set; }

	public static ManualLogSource Log
	{
		get
		{
			if (!((Object)(object)Instance != (Object)null))
			{
				return null;
			}
			return ((BaseUnityPlugin)Instance).Logger;
		}
	}

	private void Awake()
	{
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d5: Expected O, but got Unknown
		Instance = this;
		ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable or disable Valheim_Blue_Archive_Mod.");
		KeepTools = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "KeepTools", true, "Keep unequipped tools in your inventory on death instead of dropping them into the gravestone.");
		KeepEquippedItems = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "KeepEquippedItems", true, "Keep equipped items when the world would otherwise unequip and drop them. No-op if the world already keeps equipped items.");
		NotificationOnDeath = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowDeathNotification", true, "Display a brief on-screen message upon death showing how many tools and equipped items were preserved.");
		KeepBuildingAndFarmingTools = ((BaseUnityPlugin)this).Config.Bind<bool>("ToolTypes", "KeepBuildingAndFarmingTools", true, "Keep construction and farming tools (Hammer, Hoe, Cultivator, and other ItemType.Tool items).");
		KeepPickaxes = ((BaseUnityPlugin)this).Config.Bind<bool>("ToolTypes", "KeepPickaxes", true, "Keep mining pickaxes (Antler, Bronze, Iron, Blackmetal, and modded pickaxes).");
		KeepAxes = ((BaseUnityPlugin)this).Config.Bind<bool>("ToolTypes", "KeepAxes", true, "Keep woodcutting axes (Stone, Flint, Bronze, Iron, Blackmetal, Jotun Bane, battleaxes, and modded axes).");
		KeepFishingRod = ((BaseUnityPlugin)this).Config.Bind<bool>("ToolTypes", "KeepFishingRod", true, "Keep fishing rods.");
		KeepButcherKnife = ((BaseUnityPlugin)this).Config.Bind<bool>("ToolTypes", "KeepButcherKnife", true, "Keep butcher knives.");
		IncludePrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("CustomFilters", "IncludePrefabs", "", "Comma-separated list of additional prefab names or localization tokens to treat as tools and keep on death (e.g. 'MyCustomTool,SpecialAxe').");
		ExcludePrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("CustomFilters", "ExcludePrefabs", "", "Comma-separated list of prefab names or localization tokens to explicitly exclude from tool protection.");
		IncludePrefabs.SettingChanged += delegate
		{
			RefreshCustomFilters();
		};
		ExcludePrefabs.SettingChanged += delegate
		{
			RefreshCustomFilters();
		};
		RefreshCustomFilters();
		_harmony = new Harmony("com.ayok.valheim.bluearchive");
		_harmony.PatchAll(Assembly.GetExecutingAssembly());
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Valheim_Blue_Archive_Mod v1.1.0 loaded.");
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}

	private static void RefreshCustomFilters()
	{
		RebuildSet(IncludeList, (IncludePrefabs != null) ? IncludePrefabs.Value : null);
		RebuildSet(ExcludeList, (ExcludePrefabs != null) ? ExcludePrefabs.Value : null);
	}

	private static void RebuildSet(HashSet<string> target, string raw)
	{
		target.Clear();
		if (string.IsNullOrEmpty(raw))
		{
			return;
		}
		string[] array = raw.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text.Length > 0)
			{
				target.Add(StripClone(text));
			}
		}
	}

	public static bool ShouldKeepItem(Player player, ItemData item)
	{
		if (item == null || item.m_shared == null)
		{
			return false;
		}
		if (item.m_shared.m_questItem)
		{
			return false;
		}
		if (KeepTools.Value && IsTool(item))
		{
			return true;
		}
		if (KeepEquippedItems.Value && IsEquipped(player, item) && VanillaWillDropEquipped())
		{
			return true;
		}
		return false;
	}

	public static bool IsEquipped(Player player, ItemData item)
	{
		if (item.m_equipped)
		{
			return true;
		}
		if ((Object)(object)player != (Object)null)
		{
			return ((Humanoid)player).IsItemEquiped(item);
		}
		return false;
	}

	public static bool VanillaWillDropEquipped()
	{
		ZoneSystem instance = ZoneSystem.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return true;
		}
		if (instance.GetGlobalKey((GlobalKeys)23))
		{
			return false;
		}
		if (instance.GetGlobalKey((GlobalKeys)19))
		{
			return false;
		}
		return true;
	}

	public static bool VanillaKeepsEntireInventory()
	{
		ZoneSystem instance = ZoneSystem.instance;
		if ((Object)(object)instance != (Object)null)
		{
			return instance.GetGlobalKey((GlobalKeys)23);
		}
		return false;
	}

	public static bool IsTool(ItemData item)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Invalid comparison between Unknown and I4
		if (item == null || item.m_shared == null)
		{
			return false;
		}
		string prefabName = PrefabName(item);
		string sharedName = item.m_shared.m_name ?? "";
		if (IsListed(ExcludeList, prefabName, sharedName))
		{
			return false;
		}
		if (IsListed(IncludeList, prefabName, sharedName))
		{
			return true;
		}
		ItemType itemType = item.m_shared.m_itemType;
		if (IsWearableOrNonToolType(itemType))
		{
			return false;
		}
		if ((int)itemType == 19)
		{
			if (!KeepFishingRod.Value && IsFishingRod(item, prefabName, sharedName))
			{
				return false;
			}
			if (!KeepButcherKnife.Value && IsButcherKnife(item, prefabName, sharedName))
			{
				return false;
			}
			if (KeepBuildingAndFarmingTools.Value)
			{
				return true;
			}
			if (KeepFishingRod.Value && IsFishingRod(item, prefabName, sharedName))
			{
				return true;
			}
			if (KeepButcherKnife.Value && IsButcherKnife(item, prefabName, sharedName))
			{
				return true;
			}
			return false;
		}
		if (KeepPickaxes.Value && IsPickaxe(item, prefabName, sharedName))
		{
			return true;
		}
		if (KeepAxes.Value && IsWoodcuttingAxe(item, prefabName, sharedName))
		{
			return true;
		}
		if (KeepFishingRod.Value && IsFishingRod(item, prefabName, sharedName))
		{
			return true;
		}
		if (KeepButcherKnife.Value && IsButcherKnife(item, prefabName, sharedName))
		{
			return true;
		}
		return false;
	}

	private static bool IsWearableOrNonToolType(ItemType itemType)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Expected I4, but got Unknown
		switch (itemType - 1)
		{
		case 0:
		case 1:
		case 3:
		case 4:
		case 5:
		case 6:
		case 8:
		case 9:
		case 10:
		case 11:
		case 12:
		case 14:
		case 16:
		case 17:
		case 20:
		case 22:
		case 23:
			return true;
		default:
			return false;
		}
	}

	private static bool IsPickaxe(ItemData item, string prefabName, string sharedName)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Invalid comparison between Unknown and I4
		if ((int)item.m_shared.m_skillType == 12)
		{
			return true;
		}
		return IsPickaxeName(prefabName, sharedName);
	}

	private static bool IsWoodcuttingAxe(ItemData item, string prefabName, string sharedName)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Invalid comparison between Unknown and I4
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Invalid comparison between Unknown and I4
		if (IsPickaxeName(prefabName, sharedName))
		{
			return false;
		}
		SkillType skillType = item.m_shared.m_skillType;
		if (((int)skillType == 7 || (int)skillType == 13) && item.m_shared.m_damages.m_chop > 0f)
		{
			return true;
		}
		return IsAxeName(prefabName, sharedName);
	}

	private static bool IsAxeName(string prefabName, string sharedName)
	{
		if (IsPickaxeName(prefabName, sharedName))
		{
			return false;
		}
		if (StartsWithIgnoreCase(prefabName, "Axe") || StartsWithIgnoreCase(prefabName, "Battleaxe"))
		{
			return true;
		}
		if (ContainsIgnoreCase(sharedName, "$item_battleaxe") || ContainsIgnoreCase(sharedName, "battleaxe"))
		{
			return true;
		}
		if (ContainsIgnoreCase(sharedName, "$item_axe"))
		{
			return true;
		}
		return false;
	}

	private static bool IsPickaxeName(string prefabName, string sharedName)
	{
		if (StartsWithIgnoreCase(prefabName, "Pickaxe") || ContainsIgnoreCase(prefabName, "Pickaxe"))
		{
			return true;
		}
		if (ContainsIgnoreCase(sharedName, "$item_pickaxe") || ContainsIgnoreCase(sharedName, "pickaxe"))
		{
			return true;
		}
		return false;
	}

	private static bool IsFishingRod(ItemData item, string prefabName, string sharedName)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Invalid comparison between Unknown and I4
		if ((int)item.m_shared.m_skillType == 104)
		{
			return true;
		}
		if (!ContainsIgnoreCase(prefabName, "fishingrod") && !ContainsIgnoreCase(sharedName, "fishingrod"))
		{
			return ContainsIgnoreCase(sharedName, "$item_fishingrod");
		}
		return true;
	}

	private static bool IsButcherKnife(ItemData item, string prefabName, string sharedName)
	{
		if (!ContainsIgnoreCase(prefabName, "butcher") && !ContainsIgnoreCase(sharedName, "butcher"))
		{
			return ContainsIgnoreCase(sharedName, "$item_butcher");
		}
		return true;
	}

	private static bool IsListed(HashSet<string> list, string prefabName, string sharedName)
	{
		if (list.Count == 0)
		{
			return false;
		}
		if (!string.IsNullOrEmpty(prefabName) && list.Contains(prefabName))
		{
			return true;
		}
		if (!string.IsNullOrEmpty(sharedName) && list.Contains(sharedName))
		{
			return true;
		}
		return false;
	}

	private static string PrefabName(ItemData item)
	{
		if ((Object)(object)item.m_dropPrefab == (Object)null)
		{
			return "";
		}
		return StripClone(((Object)item.m_dropPrefab).name);
	}

	private static string StripClone(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return "";
		}
		if (name.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase))
		{
			return name.Substring(0, name.Length - "(Clone)".Length).Trim();
		}
		return name;
	}

	private static bool StartsWithIgnoreCase(string value, string prefix)
	{
		if (!string.IsNullOrEmpty(value))
		{
			return value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
		}
		return false;
	}

	private static bool ContainsIgnoreCase(string value, string token)
	{
		if (!string.IsNullOrEmpty(value))
		{
			return value.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return false;
	}
}