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 BossIcons = new Dictionary { { "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? 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 list = new List(); 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(_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(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(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? EnabledEntry; public static readonly Dictionary> BossEnabledEntries = new Dictionary>(); 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("Boss Map Markers"); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted("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()), (AcceptableValueBase)null, new object[2] { ModSettingsTags.Section("General", I18n.L.Text("section.general", Array.Empty()), (int?)10, (bool?)null), ModSettingsTags.Entry(I18n.L.Text("entry.enabled", Array.Empty()), I18n.L.Text("entry.enabled.desc", Array.Empty()), (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()); return new ConfigDescription(text, (AcceptableValueBase)null, new object[2] { ModSettingsTags.Section("General", I18n.L.Text("section.general", Array.Empty()), (int?)10, (bool?)null), ModSettingsTags.Entry(I18n.L.Text("entry.boss.enabled", Array.Empty()).Replace("{boss}", I18n.L.Text(bossId, Array.Empty())), text.Replace("{boss}", I18n.L.Text(bossId, Array.Empty())), (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("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 val = ((BasePlugin)this).Config.Bind("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 value)) { SetDescription((ConfigEntryBase?)(object)value, BuildBossDescription(tuple2.Item1, tuple2.Item3)); } } } ModSettingsRegistry.Register("local.romestead.boss-map-markers", I18n.L.Text("mod.name", Array.Empty()), ((BasePlugin)this).Config, new ModSettingsModOptions { Icon = "map", Version = "1.0.0", Author = "wwwshe", Description = I18n.L.Text("mod.description", Array.Empty()), Order = 60 }); } public override bool Unload() { RomesteadLocalization.LocalizationApplied -= OnLocalizationApplied; return true; } public static string GetLocalizedName(string bossId) { return I18n.L.Text(bossId, Array.Empty()); } public static bool IsBossEnabled(string bossId) { if (BossEnabledEntries.TryGetValue(bossId, out ConfigEntry value)) { return value.Value; } return true; } private static void SetDescription(ConfigEntryBase? entry, ConfigDescription description) { if (entry != null) { typeof(ConfigEntryBase).GetField("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."); } } }