Decompiled source of BossMapMarkers v1.0.0

BepInEx\plugins\BossMapMarkers\BossMapMarkers.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.NET.Common;
using HarmonyLib;
using ModSettingsMenu.Api;
using RomesteadLocalizationAPI.Api;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]
[assembly: AssemblyCompany("BossMapMarkers")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BossMapMarkers")]
[assembly: AssemblyTitle("BossMapMarkers")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace BossMapMarkers;

internal static class I18n
{
	public static readonly RomesteadLocalizer L = RomesteadLocalization.For("local.romestead.boss-map-markers");
}
public static class WorldMapPatches
{
	private static int _cachedCount = -1;

	private static string? _cachedWorldId = null;

	private static object[]? _cachedMarkers = null;

	private static readonly BindingFlags IF = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private static readonly BindingFlags SF = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

	private static readonly Dictionary<string, string> BossIcons = new Dictionary<string, string>
	{
		{ "boss:satyrboss", "map_marker:gravestone" },
		{ "boss:phoenix", "map_marker:gravestone" },
		{ "boss:talos", "map_marker:gravestone" },
		{ "boss:minervas_owl", "map_marker:gravestone" },
		{ "boss:cyclops_eye", "map_marker:cyclop" }
	};

	public static void DrawMapMarkers_Prefix(object __instance)
	{
		//IL_0336: Unknown result type (might be due to invalid IL or missing references)
		//IL_033d: Expected O, but got Unknown
		//IL_029d: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a4: Expected O, but got Unknown
		bool flag = default(bool);
		try
		{
			object obj = __instance.GetType().GetField("_reuseMarkersList", IF)?.GetValue(__instance);
			if (Plugin.ImmediateMapMarkerType == null && obj != null && obj.GetType().IsGenericType)
			{
				Plugin.CacheMarkerType(obj.GetType().GetGenericArguments()[0]);
			}
			ConfigEntry<bool>? enabledEntry = Plugin.EnabledEntry;
			if (enabledEntry != null && !enabledEntry.Value)
			{
				return;
			}
			Type gameStateType = Plugin.GameStateType;
			if (gameStateType == null || obj == null || Plugin.ImmediateMapMarkerType == null)
			{
				return;
			}
			float tileW = 16f;
			float tileH = 16f;
			object obj2 = gameStateType.GetField("Config", SF)?.GetValue(null);
			if (obj2 != null)
			{
				object obj3 = obj2.GetType().GetField("TileSize", IF)?.GetValue(obj2);
				if (obj3 != null)
				{
					tileW = Convert.ToSingle(obj3.GetType().GetField("X", IF)?.GetValue(obj3) ?? ((object)16f));
					tileH = Convert.ToSingle(obj3.GetType().GetField("Y", IF)?.GetValue(obj3) ?? ((object)16f));
				}
			}
			object obj4 = gameStateType.GetField("BossLocations", SF)?.GetValue(null);
			if (!(obj4 is IEnumerable enumerable))
			{
				return;
			}
			int num = (obj4 as ICollection)?.Count ?? 0;
			if (num == 0)
			{
				return;
			}
			string currentWorldId = GetCurrentWorldId(__instance, gameStateType);
			if (_cachedMarkers == null || _cachedCount != num || _cachedWorldId != currentWorldId)
			{
				_cachedCount = num;
				_cachedWorldId = currentWorldId;
				List<object> list = new List<object>();
				foreach (object item in enumerable)
				{
					object fieldVal = GetFieldVal(item, "value");
					if (fieldVal == null || !Plugin.IsBossEnabled(GetStr(fieldVal, "BossId") ?? ""))
					{
						continue;
					}
					string str = GetStr(fieldVal, "WorldId");
					if (currentWorldId == null || string.IsNullOrEmpty(str) || !(str != currentWorldId))
					{
						object obj5 = CreateMarker(fieldVal, tileW, tileH);
						if (obj5 != null)
						{
							list.Add(obj5);
						}
					}
				}
				_cachedMarkers = list.ToArray();
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[BossMapMarkers] ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_cachedMarkers.Length);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" boss marker(s) ready.");
				}
				logger.LogInfo(val);
			}
			MethodInfo method = obj.GetType().GetMethod("Add");
			if (!(method == null))
			{
				object[] cachedMarkers = _cachedMarkers;
				foreach (object obj6 in cachedMarkers)
				{
					method.Invoke(obj, new object[1] { obj6 });
				}
			}
		}
		catch (Exception ex)
		{
			ManualLogSource logger2 = Plugin.Logger;
			BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(17, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[BossMapMarkers] ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
			}
			logger2.LogError(val2);
		}
	}

	private static object? CreateMarker(object bossLoc, float tileW, float tileH)
	{
		//IL_019e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Expected O, but got Unknown
		try
		{
			object obj = Activator.CreateInstance(Plugin.ImmediateMapMarkerType);
			string text = GetStr(bossLoc, "BossId") ?? "";
			object obj2 = GetFieldVal(bossLoc, "IconLocation") ?? GetFieldVal(bossLoc, "Location");
			if (obj2 != null && Plugin.TilePositionField != null)
			{
				float num = Convert.ToSingle(obj2.GetType().GetField("X", IF)?.GetValue(obj2) ?? ((object)0f));
				float num2 = Convert.ToSingle(obj2.GetType().GetField("Y", IF)?.GetValue(obj2) ?? ((object)0f));
				object obj3 = MakeVec2(Plugin.TilePositionField.FieldType, num / tileW, num2 / tileH);
				if (obj3 != null)
				{
					Plugin.TilePositionField.SetValue(obj, obj3);
				}
			}
			Plugin.IconIdField?.SetValue(obj, BossIcons.TryGetValue(text, out string value) ? value : "map_marker:gravestone");
			Plugin.HoverTextField?.SetValue(obj, Plugin.GetLocalizedName(text));
			Plugin.IsDecorativeField?.SetValue(obj, false);
			Plugin.StickyField?.SetValue(obj, true);
			if (Plugin.ScaleField?.FieldType == typeof(float))
			{
				Plugin.ScaleField.SetValue(obj, 1.2f);
			}
			return obj;
		}
		catch (Exception ex)
		{
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(31, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[BossMapMarkers] CreateMarker: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
			}
			logger.LogWarning(val);
			return null;
		}
	}

	private static object? MakeVec2(Type vec2Type, float x, float y)
	{
		try
		{
			object obj = Activator.CreateInstance(vec2Type);
			vec2Type.GetField("X", IF)?.SetValue(obj, x);
			vec2Type.GetField("Y", IF)?.SetValue(obj, y);
			return obj;
		}
		catch
		{
			return null;
		}
	}

	private static string? GetCurrentWorldId(object worldMap, Type gs)
	{
		object fieldVal = GetFieldVal(worldMap, "World");
		if (fieldVal != null)
		{
			object obj = GetFieldVal(fieldVal, "Id") ?? GetFieldVal(fieldVal, "WorldId");
			if (obj != null)
			{
				return obj.ToString();
			}
		}
		object obj2 = gs.GetField("CurrentWorld", SF)?.GetValue(null);
		if (obj2 != null)
		{
			return (GetFieldVal(obj2, "Id") ?? GetFieldVal(obj2, "WorldId"))?.ToString();
		}
		return null;
	}

	public static void ClearCache()
	{
		_cachedMarkers = null;
		_cachedCount = -1;
		_cachedWorldId = null;
	}

	private static object? GetFieldVal(object? obj, string name)
	{
		return obj?.GetType().GetField(name, IF)?.GetValue(obj);
	}

	private static string? GetStr(object? obj, string name)
	{
		return GetFieldVal(obj, name)?.ToString();
	}
}
[BepInPlugin("local.romestead.boss-map-markers", "Boss Map Markers", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BasePlugin
{
	public const string PluginGuid = "local.romestead.boss-map-markers";

	public const string PluginName = "Boss Map Markers";

	public const string PluginVersion = "1.0.0";

	public static ManualLogSource Logger = null;

	public static Type? GameStateType;

	public static ConfigEntry<bool>? EnabledEntry;

	public static readonly Dictionary<string, ConfigEntry<bool>> BossEnabledEntries = new Dictionary<string, ConfigEntry<bool>>();

	private static readonly (string BossId, string ConfigKey, int Order)[] BossSettings = new(string, string, int)[5]
	{
		("boss:satyrboss", "ShowSatyrBoss", 2),
		("boss:phoenix", "ShowPhoenix", 3),
		("boss:talos", "ShowTalos", 4),
		("boss:minervas_owl", "ShowMinervasOwl", 5),
		("boss:cyclops_eye", "ShowCyclops", 6)
	};

	public static Type? ImmediateMapMarkerType;

	public static FieldInfo? TilePositionField;

	public static FieldInfo? IconIdField;

	public static FieldInfo? HoverTextField;

	public static FieldInfo? ScaleField;

	public static FieldInfo? IsDecorativeField;

	public static FieldInfo? StickyField;

	private bool _settingsRegistered;

	public override void Load()
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Expected O, but got Unknown
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Expected O, but got Unknown
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Expected O, but got Unknown
		Logger = ((BasePlugin)this).Log;
		I18n.L.RegisterJson(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "localization.json"));
		RomesteadLocalization.LocalizationApplied += OnLocalizationApplied;
		Harmony val = new Harmony("local.romestead.boss-map-markers");
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			Type[] types;
			try
			{
				types = assembly.GetTypes();
			}
			catch
			{
				continue;
			}
			Type[] array = types;
			foreach (Type type in array)
			{
				if (type.FullName == "Candide.GameModels.GameState")
				{
					GameStateType = type;
				}
				else if (type.FullName == "Candide.World.WorldMap")
				{
					MethodInfo method = type.GetMethod("DrawMapMarkers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (method != null)
					{
						val.Patch((MethodBase)method, new HarmonyMethod(typeof(WorldMapPatches).GetMethod("DrawMapMarkers_Prefix", BindingFlags.Static | BindingFlags.Public)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					}
				}
			}
		}
		ManualLogSource logger = Logger;
		bool flag = default(bool);
		BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(9, 2, ref flag);
		if (flag)
		{
			((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("Boss Map Markers");
			((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
			((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.0.0");
			((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded.");
		}
		logger.LogInfo(val2);
	}

	private ConfigDescription BuildEnabledDescription()
	{
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Expected O, but got Unknown
		return new ConfigDescription(I18n.L.Text("entry.enabled.desc", Array.Empty<object>()), (AcceptableValueBase)null, new object[2]
		{
			ModSettingsTags.Section("General", I18n.L.Text("section.general", Array.Empty<object>()), (int?)10, (bool?)null),
			ModSettingsTags.Entry(I18n.L.Text("entry.enabled", Array.Empty<object>()), I18n.L.Text("entry.enabled.desc", Array.Empty<object>()), (int?)1, (double?)null, (bool?)null)
		});
	}

	private static ConfigDescription BuildBossDescription(string bossId, int order)
	{
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Expected O, but got Unknown
		string text = I18n.L.Text("entry.boss.enabled.desc", Array.Empty<object>());
		return new ConfigDescription(text, (AcceptableValueBase)null, new object[2]
		{
			ModSettingsTags.Section("General", I18n.L.Text("section.general", Array.Empty<object>()), (int?)10, (bool?)null),
			ModSettingsTags.Entry(I18n.L.Text("entry.boss.enabled", Array.Empty<object>()).Replace("{boss}", I18n.L.Text(bossId, Array.Empty<object>())), text.Replace("{boss}", I18n.L.Text(bossId, Array.Empty<object>())), (int?)order, (double?)null, (bool?)null)
		});
	}

	private void OnLocalizationApplied(string locale)
	{
		//IL_0159: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ab: Expected O, but got Unknown
		WorldMapPatches.ClearCache();
		if (!_settingsRegistered)
		{
			_settingsRegistered = true;
			EnabledEntry = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, BuildEnabledDescription());
			EnabledEntry.SettingChanged += delegate
			{
				WorldMapPatches.ClearCache();
			};
			(string, string, int)[] bossSettings = BossSettings;
			for (int num = 0; num < bossSettings.Length; num++)
			{
				(string, string, int) tuple = bossSettings[num];
				ConfigEntry<bool> val = ((BasePlugin)this).Config.Bind<bool>("Bosses", tuple.Item2, true, BuildBossDescription(tuple.Item1, tuple.Item3));
				val.SettingChanged += delegate
				{
					WorldMapPatches.ClearCache();
				};
				BossEnabledEntries[tuple.Item1] = val;
			}
		}
		else
		{
			SetDescription((ConfigEntryBase?)(object)EnabledEntry, BuildEnabledDescription());
			(string, string, int)[] bossSettings = BossSettings;
			for (int num = 0; num < bossSettings.Length; num++)
			{
				(string, string, int) tuple2 = bossSettings[num];
				if (BossEnabledEntries.TryGetValue(tuple2.Item1, out ConfigEntry<bool> value))
				{
					SetDescription((ConfigEntryBase?)(object)value, BuildBossDescription(tuple2.Item1, tuple2.Item3));
				}
			}
		}
		ModSettingsRegistry.Register("local.romestead.boss-map-markers", I18n.L.Text("mod.name", Array.Empty<object>()), ((BasePlugin)this).Config, new ModSettingsModOptions
		{
			Icon = "map",
			Version = "1.0.0",
			Author = "wwwshe",
			Description = I18n.L.Text("mod.description", Array.Empty<object>()),
			Order = 60
		});
	}

	public override bool Unload()
	{
		RomesteadLocalization.LocalizationApplied -= OnLocalizationApplied;
		return true;
	}

	public static string GetLocalizedName(string bossId)
	{
		return I18n.L.Text(bossId, Array.Empty<object>());
	}

	public static bool IsBossEnabled(string bossId)
	{
		if (BossEnabledEntries.TryGetValue(bossId, out ConfigEntry<bool> value))
		{
			return value.Value;
		}
		return true;
	}

	private static void SetDescription(ConfigEntryBase? entry, ConfigDescription description)
	{
		if (entry != null)
		{
			typeof(ConfigEntryBase).GetField("<Description>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(entry, description);
		}
	}

	public static void CacheMarkerType(Type type)
	{
		if (!(ImmediateMapMarkerType == type))
		{
			ImmediateMapMarkerType = type;
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			TilePositionField = type.GetField("TilePosition", bindingAttr);
			IconIdField = type.GetField("IconId", bindingAttr);
			HoverTextField = type.GetField("HoverText", bindingAttr);
			ScaleField = type.GetField("Scale", bindingAttr);
			IsDecorativeField = type.GetField("IsDecorative", bindingAttr);
			StickyField = type.GetField("Sticky", bindingAttr);
			Logger.LogInfo((object)"[BossMapMarkers] ImmediateMapMarker cached.");
		}
	}
}