Decompiled source of TotemPins v2.1.0

TotemPins.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace TotemPins;

[BepInPlugin("valheimtotems.totempins", "TotemPins", "2.1.0")]
public class TotemPinsPlugin : BaseUnityPlugin
{
	public const string Guid = "valheimtotems.totempins";

	public const string Version = "2.1.0";

	public const string NeutralIconName = "TotemPins_Totem";

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<string> LocationPrefix;

	internal static ConfigEntry<string> IconName;

	internal static ConfigEntry<bool> UseTravelTotemsIcon;

	internal static ConfigEntry<bool> LogIconNames;

	internal static ManualLogSource Log;

	private static FieldInfo _fLocations;

	private static FieldInfo _fPrefabName;

	private static FieldInfo _fPrefab;

	private static FieldInfo _fIconPlaced;

	private static PropertyInfo _pRefName;

	private static int _lastLocationCount = -1;

	private static object _lastList;

	private static object _registeredList;

	private static bool _warnedNoSprite;

	private void Awake()
	{
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Show Travel Totem locations on the map once their area has been generated.");
		LocationPrefix = ((BaseUnityPlugin)this).Config.Bind<string>("General", "LocationPrefix", "VV_TravelTotemLocation", "Locations whose prefab name starts with this get a map pin.");
		UseTravelTotemsIcon = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UseTravelTotemsIcon", true, "Use the Travel Totems map icon. Requires TotemPins on the server AND every player. Set false to use the vanilla IconName below instead (server-only install works).");
		IconName = ((BaseUnityPlugin)this).Config.Bind<string>("General", "IconName", "StartTemple", "Vanilla location icon used only when UseTravelTotemsIcon is false (e.g. StartTemple). Note: with StartTemple, Travel Totems' AllowSelectDefaultSpawn treats pins as spawn points.");
		LogIconNames = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogIconNames", false, "Client: log every map location icon name the game knows.");
		ApplyPatches();
	}

	internal static void ApplyPatches()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Expected O, but got Unknown
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Expected O, but got Unknown
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Expected O, but got Unknown
		if (!ResolveFields())
		{
			return;
		}
		Type type = AccessTools.TypeByName("ZoneSystem");
		Harmony val = new Harmony("valheimtotems.totempins");
		HarmonyMethod val2 = new HarmonyMethod(AccessTools.Method(typeof(TotemPinsPlugin), "EnsureFlagsPrefix", (Type[])null, (Type[])null));
		HarmonyMethod val3 = new HarmonyMethod(AccessTools.Method(typeof(TotemPinsPlugin), "RenameIconsPostfix", (Type[])null, (Type[])null));
		int num = 0;
		MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (MethodInfo methodInfo in methods)
		{
			if (methodInfo.Name == "PlaceLocations")
			{
				val.Patch((MethodBase)methodInfo, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				num++;
			}
			else if (methodInfo.Name == "GetLocationIcons")
			{
				val.Patch((MethodBase)methodInfo, val2, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				num++;
			}
		}
		Type type2 = AccessTools.TypeByName("Minimap");
		HarmonyMethod val4 = new HarmonyMethod(AccessTools.Method(typeof(TotemPinsPlugin), "RegisterIconPatch", (Type[])null, (Type[])null));
		MethodInfo methodInfo2 = AccessTools.Method(type2, "Start", (Type[])null, (Type[])null);
		MethodInfo methodInfo3 = AccessTools.Method(type2, "UpdateLocationPins", (Type[])null, (Type[])null);
		if (methodInfo2 != null)
		{
			MethodInfo methodInfo4 = methodInfo2;
			HarmonyMethod val5 = val4;
			val.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, val5, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
		if (methodInfo3 != null)
		{
			val.Patch((MethodBase)methodInfo3, val4, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
		Log.LogInfo((object)(string.Format("TotemPins {0} loaded ({1} methods patched). Prefix='{2}', ", "2.1.0", num, LocationPrefix.Value) + ((!UseTravelTotemsIcon.Value) ? $"using vanilla icon '{IconName.Value}'." : "using Travel Totems icon.")));
	}

	private static void RegisterIconPatch(object __instance)
	{
		if (__instance == null || !Enabled.Value)
		{
			return;
		}
		try
		{
			if (!(AccessTools.Field(__instance.GetType(), "m_locationIcons")?.GetValue(__instance) is IList list) || object.ReferenceEquals(list, _registeredList))
			{
				return;
			}
			Type type = ((!list.GetType().IsGenericType) ? null : list.GetType().GetGenericArguments()[0]);
			FieldInfo fieldInfo = ((!(type != null)) ? null : AccessTools.Field(type, "m_name"));
			FieldInfo fieldInfo2 = ((!(type != null)) ? null : AccessTools.Field(type, "m_icon"));
			if (fieldInfo == null || fieldInfo2 == null)
			{
				_registeredList = list;
				Log.LogWarning((object)"Minimap icon list has an unexpected format.");
				return;
			}
			HashSet<string> hashSet = new HashSet<string>();
			string text = default(string);
			foreach (object item in list)
			{
				if (item != null)
				{
					object obj = fieldInfo.GetValue(item) as string;
					if (obj != null)
					{
						text = (string)obj;
						obj = text;
					}
					if (obj != null)
					{
						hashSet.Add(text);
					}
				}
			}
			if (LogIconNames.Value)
			{
				Log.LogInfo((object)("Map location icons: " + string.Join(", ", new List<string>(hashSet).ToArray())));
			}
			object obj2 = null;
			Type type2 = AccessTools.TypeByName("VentureValheim.TravelTotems.AssetManager");
			PropertyInfo propertyInfo = ((!(type2 != null)) ? null : AccessTools.Property(type2, "TotemMapSprite"));
			if (propertyInfo != null)
			{
				obj2 = propertyInfo.GetValue(null, null);
			}
			if (obj2 == null)
			{
				if (!_warnedNoSprite)
				{
					_warnedNoSprite = true;
					Log.LogWarning((object)"Travel Totems map sprite not available yet; will retry.");
				}
				return;
			}
			if (!hashSet.Contains("TotemPins_Totem"))
			{
				object obj3 = Activator.CreateInstance(type);
				fieldInfo.SetValue(obj3, "TotemPins_Totem");
				fieldInfo2.SetValue(obj3, obj2);
				list.Add(obj3);
			}
			_registeredList = list;
			Log.LogInfo((object)string.Format("Registered Travel Totems map icon as '{0}'.", "TotemPins_Totem"));
		}
		catch (Exception ex)
		{
			_registeredList = null;
			Log.LogWarning((object)("Could not register totem map icon: " + ex.Message));
		}
	}

	internal static bool ResolveFields()
	{
		Type type = AccessTools.TypeByName("ZoneSystem");
		Type type2 = AccessTools.TypeByName("ZoneLocation");
		if (type == null || type2 == null)
		{
			Log.LogError((object)"Could not find ZoneSystem/ZoneLocation - game version not supported.");
			return false;
		}
		_fLocations = AccessTools.Field(type, "m_locations");
		_fPrefabName = AccessTools.Field(type2, "m_prefabName");
		_fPrefab = AccessTools.Field(type2, "m_prefab");
		_fIconPlaced = AccessTools.Field(type2, "m_iconPlaced");
		if (_fPrefab != null)
		{
			_pRefName = AccessTools.Property(_fPrefab.FieldType, "Name");
		}
		if (_fLocations == null || _fIconPlaced == null || (_fPrefab == null && _fPrefabName == null))
		{
			Log.LogError((object)"Expected ZoneSystem/ZoneLocation fields are missing - game version not supported.");
			return false;
		}
		return true;
	}

	private static string GetLocationName(object zoneLocation)
	{
		if (_fPrefab != null && _pRefName != null)
		{
			try
			{
				object value = _fPrefab.GetValue(zoneLocation);
				string text = ((value == null) ? null : (_pRefName.GetValue(value, null) as string));
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			catch (Exception)
			{
			}
		}
		return (!(_fPrefabName != null)) ? null : (_fPrefabName.GetValue(zoneLocation) as string);
	}

	private static void EnsureFlagsPrefix(object __instance)
	{
		if (!Enabled.Value || __instance == null)
		{
			return;
		}
		try
		{
			if (!(_fLocations.GetValue(__instance) is IList list) || (object.ReferenceEquals(list, _lastList) && list.Count == _lastLocationCount))
			{
				return;
			}
			_lastList = list;
			_lastLocationCount = list.Count;
			string value = LocationPrefix.Value;
			int num = 0;
			foreach (object item in list)
			{
				if (item == null)
				{
					continue;
				}
				string locationName = GetLocationName(item);
				if (locationName != null && locationName.StartsWith(value, StringComparison.Ordinal))
				{
					if (!(bool)_fIconPlaced.GetValue(item))
					{
						_fIconPlaced.SetValue(item, true);
					}
					num++;
				}
			}
			Log.LogInfo((object)$"Flagged {num} location type(s) matching '{value}' for map icons.");
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("EnsureFlags failed: " + ex.Message));
		}
	}

	private static void RenameIconsPostfix(object __0)
	{
		if (!Enabled.Value || !(__0 is IDictionary { Count: not 0 } dictionary))
		{
			return;
		}
		try
		{
			string value = LocationPrefix.Value;
			List<object> list = new List<object>();
			foreach (DictionaryEntry item in dictionary)
			{
				if (item.Value is string text && text.StartsWith(value, StringComparison.Ordinal))
				{
					list.Add(item.Key);
				}
			}
			string value2 = ((!UseTravelTotemsIcon.Value) ? IconName.Value : "TotemPins_Totem");
			foreach (object item2 in list)
			{
				dictionary[item2] = value2;
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("RenameIcons failed: " + ex.Message));
		}
	}
}