using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BetterMap.Scripts.Creatures; using BetterMap.Scripts.Map; using BetterMap.Scripts.Pins; using BetterMap.Scripts.Vehicles; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using Splatform; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("BetterMap")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BetterMap")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: Guid("0FFBB82E-5492-486C-A8A5-346DED8E95E7")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: ComVisible(false)] [assembly: AssemblyVersion("1.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace BetterMap { [BepInPlugin("xtav1m.BetterMap", "BetterMap", "1.0.0")] public class Plugin : BaseUnityPlugin { public static ConfigEntry showCreatures; public static ConfigEntry creatureRefreshInterval; public static ConfigEntry showEntityNames; public static ConfigEntry tintTamedCreatures; public static ConfigEntry tintHostileCreatures; public static ConfigEntry showBoats; public static ConfigEntry showCarts; public static ConfigEntry rotateBoatIcons; public static ConfigEntry showVehicleNames; public static ConfigEntry vehicleRefreshInterval; public static ConfigEntry autoPin; public static ConfigEntry autoPinPortals; public static ConfigEntry nameTraderPins; public static ConfigEntry revealTraders; public static ConfigEntry autoPinMergeDistance; public static ConfigEntry autoPinInterval; public const PinType AutoPinType = (PinType)3; public static ConfigEntry deathMarkersKept; public static ConfigEntry explorationRadius; public static ConfigEntry iconScale; public static ConfigEntry debugMode; public static ConfigEntry forgetPinned; public static readonly ManualLogSource Logger = Logger.CreateLogSource("BetterMap"); private static readonly ConfigSync configSync = new ConfigSync("xtav1m.BetterMap") { DisplayName = "BetterMap", CurrentVersion = "1.0.0", MinimumRequiredVersion = "1.0.0" }; private void Awake() { InitializeConfig(); InitializeHarmonyPatches(); Logger.LogInfo((object)"BetterMap 1.0.0 loaded"); } private void Update() { CreatureTracker.Tick(); DeathMarkers.Tick(); VehicleTracker.Tick(); VehicleIndex.Tick(); AutoPins.Tick(); } private ConfigEntry ConfigSync(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags); ConfigEntry val2 = ((BaseUnityPlugin)this).Config.Bind(group, name, value, val); configSync.AddConfigEntry(val2).SynchronizedConfig = synchronizedSetting; return val2; } private void InitializeConfig() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Expected O, but got Unknown //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Expected O, but got Unknown //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Expected O, but got Unknown //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Expected O, but got Unknown //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Expected O, but got Unknown //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Expected O, but got Unknown //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Expected O, but got Unknown //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Expected O, but got Unknown //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Expected O, but got Unknown //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Expected O, but got Unknown //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Expected O, but got Unknown //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Expected O, but got Unknown //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Expected O, but got Unknown //IL_03d7: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Expected O, but got Unknown ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; ConfigEntry lockingConfig = ConfigSync("1 - ServerSync", "Lock Configuration", value: true, new ConfigDescription("If enabled, the configuration is locked and can be changed by server admins only.", (AcceptableValueBase)null, Array.Empty())); configSync.AddLockingConfigEntry(lockingConfig); showCreatures = ConfigSync("Creatures", "Show Creatures", value: true, new ConfigDescription("Show creatures on the minimap and the map, using their trophy as the icon.", (AcceptableValueBase)null, Array.Empty())); creatureRefreshInterval = ConfigSync("Creatures", "Creature Refresh Interval", 0.5f, new ConfigDescription("How often, in seconds, the set of tracked creatures is rebuilt. Their pins follow them every frame regardless.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 5f), Array.Empty())); showEntityNames = ConfigSync("Creatures", "Show Creature Names", value: false, new ConfigDescription("Show a name under every creature pin. Creatures with no trophy icon, and tamed creatures that have been given a name, always show theirs regardless of this setting.", (AcceptableValueBase)null, Array.Empty())); tintTamedCreatures = ConfigSync("Creatures", "Tint Tamed Creatures", value: true, new ConfigDescription("Tint the pins of tamed creatures green so they stand out from the wildlife.", (AcceptableValueBase)null, Array.Empty())); tintHostileCreatures = ConfigSync("Creatures", "Tint Hostile Creatures", value: true, new ConfigDescription("Tint red the pins of creatures that will attack you on sight. Only applies to creatures with no trophy to use as an icon, which are drawn with a plain pin: a creature drawn as its own trophy is already recognisable.", (AcceptableValueBase)null, Array.Empty())); showBoats = ConfigSync("Vehicles", "Show Boats", value: true, new ConfigDescription("Show boats on the map. Boats are found anywhere in the world, not only near you, which is what makes one you left adrift findable. Playing alone or hosting, that means every boat there is. As a guest on a server you get the ones in every area you have loaded since connecting, and a boat far away sits where it was when you were last near it.", (AcceptableValueBase)null, Array.Empty())); showCarts = ConfigSync("Vehicles", "Show Carts", value: true, new ConfigDescription("Show carts on the map, wherever you left them.", (AcceptableValueBase)null, Array.Empty())); rotateBoatIcons = ConfigSync("Vehicles", "Rotate Boat Icons", value: true, new ConfigDescription("Turn boat icons to point the way the boat is facing. While you are sailing, this also replaces the game's own boat marker so both look the same.", (AcceptableValueBase)null, Array.Empty())); showVehicleNames = ConfigSync("Vehicles", "Show Vehicle Names", value: true, new ConfigDescription("Show what each vehicle is under its icon, so a raft can be told from a longship.", (AcceptableValueBase)null, Array.Empty())); vehicleRefreshInterval = ConfigSync("Vehicles", "Vehicle Refresh Interval", 5f, new ConfigDescription("How often, in seconds, vehicles anywhere in the world are looked up. Vehicles near the player follow them continuously.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 60f), Array.Empty())); autoPin = ConfigSync("Auto Pins", "Enable", value: true, new ConfigDescription("Pin resources as you come across them. What gets pinned is chosen biome by biome below, and a pin you delete is never put back.", (AcceptableValueBase)null, Array.Empty())); autoPinInterval = ConfigSync("Auto Pins", "Sweep Interval", 2f, new ConfigDescription("How often, in seconds, the loaded world is looked over for anything worth pinning.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 30f), Array.Empty())); autoPinPortals = ConfigSync("Auto Pins", "Pin Portals", value: true, new ConfigDescription("Pin portals where they stand, named by their tag, using the game's own portal icon. Renaming a portal renames its pin.", (AcceptableValueBase)null, Array.Empty())); revealTraders = ConfigSync("Auto Pins", "Reveal Traders", value: false, new ConfigDescription("Put every trader in the world on your map at once, Haldor and Hildir and the bog witch, without having to stumble across them. Off by default because finding them is part of the game. On a server this is decided by the server, and takes effect the next time you connect.", (AcceptableValueBase)null, Array.Empty())); nameTraderPins = ConfigSync("Auto Pins", "Name Trader Pins", value: true, new ConfigDescription("Put the trader's name on the pin the game already places for them, so Haldor, Hildir and the bog witch can be told apart on the map.", (AcceptableValueBase)null, Array.Empty())); autoPinMergeDistance = ConfigSync("Auto Pins", "Merge Distance", 5f, new ConfigDescription("Do not place an automatic pin within this many meters of one that is already there, so walking past the same deposit does not stack pins on it.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f), Array.Empty())); deathMarkersKept = ConfigSync("Map", "Death Markers Kept", 3, new ConfigDescription("How many of your death markers to keep on the map. The game drops a marker where you died but never saves it, so without this they are gone the next time you load the world.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 20), Array.Empty())); explorationRadius = ConfigSync("Map", "Exploration Radius", 100f, new ConfigDescription("How much of the map is uncovered as you walk, in meters. 100 is the vanilla value.", (AcceptableValueBase)(object)new AcceptableValueRange(20f, 500f), Array.Empty())); iconScale = ConfigSync("Map", "Icon Scale", 1.25f, new ConfigDescription("Size of every pin on the map, as a multiple of its normal size. 1 leaves the game's own size, 32 pixels on the minimap and 48 on the map.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 3f), Array.Empty())); BindPinRules(); debugMode = ConfigSync("Debug", "Debug Mode", value: false, new ConfigDescription("Log what is being pinned and tracked.", (AcceptableValueBase)null, Array.Empty()), synchronizedSetting: false); forgetPinned = ConfigSync("Debug", "Forget Pinned Places", value: false, new ConfigDescription("Once, on the next world you load, throw away this character's record of where it has already pinned, so everything is pinned again. Turn it back off afterwards. This also undoes every automatic pin you deleted on purpose.", (AcceptableValueBase)null, Array.Empty()), synchronizedSetting: false); ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; ((BaseUnityPlugin)this).Config.Save(); } private void BindPinRules() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown foreach (PinRules.Rule item in PinRules.All) { item.Enabled = ConfigSync($"Auto Pins - {item.Biome}", item.Name, item.DefaultOn, new ConfigDescription(item.Description, (AcceptableValueBase)null, Array.Empty())); } } private static void InitializeHarmonyPatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) new Harmony("xtav1m.BetterMap").PatchAll(); } } internal static class PluginInfo { public const string PLUGIN_NAME = "BetterMap"; public const string PLUGIN_GUID = "xtav1m.BetterMap"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace BetterMap.Scripts { public static class Icons { private static readonly Dictionary _sprites = new Dictionary(); private static readonly MethodInfo LoadImageMethod = FindLoadImage(); public static Sprite Boat => Get("boat.png"); public static Sprite Cart => Get("cart.png"); private static MethodInfo FindLoadImage() { Type type = AccessTools.TypeByName("UnityEngine.ImageConversion"); if (type == null) { return null; } return AccessTools.Method(type, "LoadImage", new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }, (Type[])null) ?? AccessTools.Method(type, "LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }, (Type[])null); } public static Sprite For(PinCategory category) { return (Sprite)(category switch { PinCategory.Ore => Get("ore.png"), PinCategory.Forage => Get("forage.png"), PinCategory.Dungeon => Get("dungeon.png"), PinCategory.Loot => Get("loot.png"), PinCategory.Spawner => Get("spawner.png"), PinCategory.Vegvisir => Get("vegvisir.png"), PinCategory.Beehive => Get("beehive.png"), PinCategory.Tar => Get("tar.png"), PinCategory.Sap => Get("sap.png"), _ => null, }); } private static Sprite Get(string file) { if (_sprites.TryGetValue(file, out Sprite value)) { return value; } Sprite val = Load(file); _sprites[file] = val; return val; } private static Sprite Load(string file) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) try { byte[] array = Read(file); if (array == null) { Plugin.Logger.LogWarning((object)("Icons: " + file + " is not in the assembly")); return null; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; if (!Decode(val, array)) { Plugin.Logger.LogWarning((object)("Icons: " + file + " could not be decoded")); return null; } return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Icons: {file} failed to load: {arg}"); return null; } } private static bool Decode(Texture2D texture, byte[] bytes) { if (LoadImageMethod == null) { Plugin.Logger.LogWarning((object)"Icons: the game's image decoder was not found"); return false; } object[] parameters = ((LoadImageMethod.GetParameters().Length != 3) ? new object[2] { texture, bytes } : new object[3] { texture, bytes, false }); return (bool)LoadImageMethod.Invoke(null, parameters); } private static byte[] Read(string file) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string value = "." + file; string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { if (!text.EndsWith(value, StringComparison.OrdinalIgnoreCase)) { continue; } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { return null; } byte[] array = new byte[stream.Length]; int num; for (int j = 0; j < array.Length; j += num) { num = stream.Read(array, j, array.Length - j); if (num <= 0) { break; } } return array; } return null; } } public static class MapPins { private static readonly FieldRef PinUpdateRequired = AccessTools.FieldRefAccess("m_pinUpdateRequired"); private static readonly FieldRef> Pins = AccessTools.FieldRefAccess>("m_pins"); public static void RequestRedraw() { if ((Object)(object)Minimap.instance != (Object)null) { PinUpdateRequired.Invoke(Minimap.instance) = true; } } public static List Of(Minimap map) { return Pins.Invoke(map); } public static void ApplyScale() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null) { return; } float value = Plugin.iconScale.Value; if (Mathf.Approximately(value, 1f)) { return; } float num = (((int)instance.m_mode == 2) ? instance.m_pinSizeLarge : instance.m_pinSizeSmall); foreach (PinData item in Pins.Invoke(instance)) { if (!((Object)(object)item?.m_uiElement == (Object)null) && !(item.m_worldSize > 0f)) { float num2; Rect rect; if (!item.m_animate) { num2 = (item.m_doubleSize ? (num * 2f) : num) * value; } else { rect = item.m_uiElement.rect; num2 = ((Rect)(ref rect)).width * value; } float num3 = num2; rect = item.m_uiElement.rect; if (!Mathf.Approximately(((Rect)(ref rect)).width, num3)) { item.m_uiElement.SetSizeWithCurrentAnchors((Axis)0, num3); item.m_uiElement.SetSizeWithCurrentAnchors((Axis)1, num3); } } } } } } namespace BetterMap.Scripts.Map { public static class DeathMarkers { private struct Marker { public long World; public Vector3 Pos; public string Label; } private const string CustomDataKey = "BetterMap.deaths"; private static readonly FieldRef> MapPins = AccessTools.FieldRefAccess>("m_pins"); private static bool _rebuilt; public static void Tick() { if ((Object)(object)Player.m_localPlayer == (Object)null) { _rebuilt = false; } else if (!_rebuilt && !((Object)(object)Minimap.instance == (Object)null)) { _rebuilt = true; Rebuild(); } } public static void Invalidate() { _rebuilt = false; } public static void Record(Vector3 pos) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)ZNet.instance == (Object)null)) { List list = Load(); list.Add(new Marker { World = ZNet.instance.GetWorldUID(), Pos = pos, Label = DayLabel() }); Store(list); Rebuild(); } } private static string DayLabel() { if ((Object)(object)EnvMan.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null) { return ""; } return $"$hud_mapday {EnvMan.instance.GetDay(ZNet.instance.GetTimeSeconds())}"; } private static void Rebuild() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null) { return; } List list = MapPins.Invoke(instance); for (int num = list.Count - 1; num >= 0; num--) { if ((int)list[num].m_type == 4) { instance.RemovePin(list[num]); } } long worldUID = ZNet.instance.GetWorldUID(); foreach (Marker item in Trim(Load())) { if (item.World == worldUID) { instance.AddPin(item.Pos, (PinType)4, item.Label, false, false, 0L, default(PlatformUserID)); } } } private static List Trim(List markers) { int value = Plugin.deathMarkersKept.Value; Dictionary dictionary = new Dictionary(); List list = new List(); for (int num = markers.Count - 1; num >= 0; num--) { Marker item = markers[num]; dictionary.TryGetValue(item.World, out var value2); if (value2 < value) { dictionary[item.World] = value2 + 1; list.Add(item); } } list.Reverse(); return list; } private static List Load() { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if ((Object)(object)Player.m_localPlayer == (Object)null) { return list; } if (!Player.m_localPlayer.m_customData.TryGetValue("BetterMap.deaths", out var value)) { return list; } if (string.IsNullOrEmpty(value)) { return list; } string[] array = value.Split(new char[1] { '|' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ';' }, 5); if (array2.Length >= 5 && long.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && TryFloat(array2[1], out var value2) && TryFloat(array2[2], out var value3) && TryFloat(array2[3], out var value4)) { list.Add(new Marker { World = result, Pos = new Vector3(value2, value3, value4), Label = array2[4] }); } } return list; } private static void Store(List markers) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } List list = new List(); foreach (Marker item in Trim(markers)) { string[] array = new string[5]; long world = item.World; array[0] = world.ToString(CultureInfo.InvariantCulture); array[1] = Float(item.Pos.x); array[2] = Float(item.Pos.y); array[3] = Float(item.Pos.z); array[4] = item.Label; list.Add(string.Join(";", array)); } Player.m_localPlayer.m_customData["BetterMap.deaths"] = string.Join("|", list.ToArray()); } private static string Float(float value) { return value.ToString("R", CultureInfo.InvariantCulture); } private static bool TryFloat(string text, out float value) { return float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out value); } } [HarmonyPatch] public static class MapPatches { [HarmonyPrefix] [HarmonyPatch(typeof(Minimap), "UpdateExplore")] private static void Minimap_UpdateExplore_Prefix(Minimap __instance) { __instance.m_exploreRadius = Plugin.explorationRadius.Value; } [HarmonyPostfix] [HarmonyPatch(typeof(Minimap), "Start")] private static void Minimap_Start_Postfix() { PinLegend.Install(); } [HarmonyPostfix] [HarmonyPatch(typeof(Minimap), "UpdatePins")] private static void Minimap_UpdatePins_Postfix() { MapPins.ApplyScale(); } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "OnDeath")] private static void Player_OnDeath_Postfix(Player __instance) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { DeathMarkers.Record(((Component)__instance).transform.position); } } [HarmonyPostfix] [HarmonyPatch(typeof(Minimap), "SetMapData")] private static void Minimap_SetMapData_Postfix() { DeathMarkers.Invalidate(); AutoPins.Restore(); } } } namespace BetterMap.Scripts.Vehicles { public static class VehicleKinds { public class Kind { public string Prefab; public int Hash; public bool IsBoat; public string Label; } private static List _all; private static Dictionary _byHash; private static readonly List Empty = new List(); public static bool Ready => Discover() != null; public static List All => Discover() ?? Empty; public static Kind Get(int hash) { if (Discover() == null) { return null; } if (!_byHash.TryGetValue(hash, out Kind value)) { return null; } return value; } private static List Discover() { if (_all != null) { return _all; } ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || instance.m_prefabs == null) { return null; } List list = new List(); Dictionary dictionary = new Dictionary(); foreach (GameObject prefab in instance.m_prefabs) { if (!((Object)(object)prefab == (Object)null)) { bool flag = (Object)(object)prefab.GetComponent() != (Object)null; if (flag || !((Object)(object)prefab.GetComponent() == (Object)null)) { Piece component = prefab.GetComponent(); string label = (((Object)(object)component != (Object)null && !string.IsNullOrEmpty(component.m_name) && Localization.instance != null) ? Localization.instance.Localize(component.m_name) : null); Kind kind = new Kind { Prefab = ((Object)prefab).name, Hash = StringExtensionMethods.GetStableHashCode(((Object)prefab).name), IsBoat = flag, Label = label }; list.Add(kind); dictionary[kind.Hash] = kind; } } } if (list.Count == 0) { return null; } _all = list; _byHash = dictionary; if (Plugin.debugMode.Value) { foreach (Kind item in list) { Plugin.Logger.LogInfo((object)("VehicleKinds: " + item.Prefab + " (" + (item.IsBoat ? "boat" : "cart") + ", " + (item.Label ?? "unnamed") + ")")); } } return _all; } } public static class VehicleMemory { private const string CustomDataKey = "BetterMap.vehicles"; private static readonly HashSet _used = new HashSet(); private static long _world; private static bool _loaded; public static void Remember(ZDOID id) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (id == ZDOID.None) { return; } Load(); if (_loaded && _used.Add(id)) { Store(); if (Plugin.debugMode.Value) { Plugin.Logger.LogInfo((object)$"VehicleMemory: remembered {id}"); } } } public static HashSet Used() { Load(); return _used; } public static void Forget() { _used.Clear(); _loaded = false; _world = 0L; } private static void Load() { //IL_011b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null) { return; } long worldUID = ZNet.instance.GetWorldUID(); if (_loaded && _world == worldUID) { return; } _used.Clear(); _world = worldUID; _loaded = true; if (!Player.m_localPlayer.m_customData.TryGetValue("BetterMap.vehicles", out var value) || string.IsNullOrEmpty(value)) { return; } string[] array = value.Split(new char[1] { '|' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ';' }); if (array2.Length == 3 && long.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result == worldUID && long.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && uint.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3)) { _used.Add(new ZDOID(result2, result3)); } } } private static void Store() { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } List list = new List(); if (Player.m_localPlayer.m_customData.TryGetValue("BetterMap.vehicles", out var value) && !string.IsNullOrEmpty(value)) { string[] array = value.Split(new char[1] { '|' }); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ';' }); if (array2.Length == 3 && long.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result != _world) { list.Add(text); } } } foreach (ZDOID item in _used) { ZDOID current = item; list.Add(string.Join(";", _world.ToString(CultureInfo.InvariantCulture), ((ZDOID)(ref current)).UserID.ToString(CultureInfo.InvariantCulture), ((ZDOID)(ref current)).ID.ToString(CultureInfo.InvariantCulture))); } Player.m_localPlayer.m_customData["BetterMap.vehicles"] = string.Join("|", list.ToArray()); } } public static class VehicleIndex { public struct Record { public ZDOID Id; public int Prefab; public Vector3 Pos; public float Heading; public long Creator; } private class Request { public long Peer; public long Player; public HashSet Used; } private static readonly List _records = new List(); private static readonly List _pending = new List(); private static readonly List _found = new List(); private static readonly List _matched = new List(); private static int _kindIndex; private static int _sectorIndex; private static bool _scanning; private static float _scannedAt = float.NegativeInfinity; public static void Ask(long peer, long player, HashSet used) { if (!_scanning && Time.time - _scannedAt < Plugin.vehicleRefreshInterval.Value) { Answer(new Request { Peer = peer, Player = player, Used = used }); } else { _pending.Add(new Request { Peer = peer, Player = player, Used = used }); } } public static void Tick() { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZDOMan.instance == null || !VehicleKinds.Ready) { return; } if (!_scanning) { if (_pending.Count == 0) { return; } _scanning = true; _kindIndex = 0; _sectorIndex = 0; _found.Clear(); } Scan(); } private static void Scan() { List all = VehicleKinds.All; if (_kindIndex < all.Count) { if (ZDOMan.instance.GetAllZDOsWithPrefabIterative(all[_kindIndex].Prefab, _found, ref _sectorIndex)) { _kindIndex++; _sectorIndex = 0; } return; } Collect(); _scanning = false; _scannedAt = Time.time; foreach (Request item in _pending) { Answer(item); } _pending.Clear(); } private static void Collect() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) _records.Clear(); foreach (ZDO item2 in _found) { if (item2 != null && item2.IsValid()) { List records = _records; Record item = new Record { Id = item2.m_uid, Prefab = item2.GetPrefab(), Pos = item2.GetPosition() }; Quaternion rotation = item2.GetRotation(); item.Heading = ((Quaternion)(ref rotation)).eulerAngles.y; item.Creator = item2.GetLong(ZDOVars.s_creator, 0L); records.Add(item); } } _found.Clear(); } private static void Answer(Request request) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) _matched.Clear(); foreach (Record record in _records) { if ((record.Creator != 0L && record.Creator == request.Player) || (request.Used != null && request.Used.Contains(record.Id))) { _matched.Add(record); } } ZPackage val = new ZPackage(); val.Write(_matched.Count); foreach (Record item in _matched) { val.Write(item.Id); val.Write(item.Prefab); val.Write(item.Pos); val.Write(item.Heading); } VehicleRpc.Reply(request.Peer, val); } } public static class VehicleRpc { private const string RequestName = "BetterMap_VehiclesRequest"; private const string ResponseName = "BetterMap_VehiclesResponse"; public static readonly List Remote = new List(); private static bool _registered; private static float _nextRequest; public static void Register() { if (!_registered && ZRoutedRpc.instance != null) { _registered = true; ZRoutedRpc.instance.Register("BetterMap_VehiclesRequest", (Action)OnRequest); ZRoutedRpc.instance.Register("BetterMap_VehiclesResponse", (Action)OnResponse); } } public static void Reset() { _registered = false; _nextRequest = 0f; Remote.Clear(); } public static void Tick() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) if (ZRoutedRpc.instance == null || (Object)(object)Player.m_localPlayer == (Object)null || Time.time < _nextRequest) { return; } _nextRequest = Time.time + Plugin.vehicleRefreshInterval.Value; ZPackage val = new ZPackage(); val.Write(Player.m_localPlayer.GetPlayerID()); HashSet hashSet = VehicleMemory.Used(); val.Write(hashSet.Count); foreach (ZDOID item in hashSet) { val.Write(item); } ZRoutedRpc.instance.InvokeRoutedRPC("BetterMap_VehiclesRequest", new object[1] { val }); } private static void OnRequest(long sender, ZPackage package) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && package != null) { long player = package.ReadLong(); int num = package.ReadInt(); HashSet hashSet = new HashSet(); for (int i = 0; i < num; i++) { hashSet.Add(package.ReadZDOID()); } VehicleIndex.Ask(sender, player, hashSet); } } public static void Reply(long peer, ZPackage package) { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(peer, "BetterMap_VehiclesResponse", new object[1] { package }); } } private static void OnResponse(long sender, ZPackage package) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (package != null) { Remote.Clear(); int num = package.ReadInt(); for (int i = 0; i < num; i++) { Remote.Add(new VehicleIndex.Record { Id = package.ReadZDOID(), Prefab = package.ReadInt(), Pos = package.ReadVector3(), Heading = package.ReadSingle() }); } if (Plugin.debugMode.Value) { Plugin.Logger.LogInfo((object)$"VehicleRpc: {num} of my vehicles"); } } } } public static class VehicleTracker { private class Tracked { public PinData Pin; public Transform Instance; public float Heading; } private struct Vehicle { public Transform Instance; public Vector3 Pos; public float Heading; public VehicleKinds.Kind Kind; } private static readonly FieldRef> Carts = AccessTools.StaticFieldRefAccess>(AccessTools.Field(typeof(Vagon), "m_instances")); private static readonly Dictionary _tracked = new Dictionary(); private static readonly Dictionary _wanted = new Dictionary(); private static readonly List _gone = new List(); private static bool _named; public static void Tick() { bool value = Plugin.showBoats.Value; bool value2 = Plugin.showCarts.Value; if (!value && !value2) { if (_tracked.Count > 0) { Clear(); } } else if (!((Object)(object)Minimap.instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && VehicleKinds.Ready) { if (_named != Plugin.showVehicleNames.Value) { _named = Plugin.showVehicleNames.Value; Clear(); } VehicleRpc.Tick(); Gather(value, value2); Reconcile(); UpdatePositions(); } } private static void Gather(bool wantBoats, bool wantCarts) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) _wanted.Clear(); Vector3 position = ((Component)Player.m_localPlayer).transform.position; float value = Plugin.explorationRadius.Value; float rangeSqr = value * value; foreach (IMonoUpdater instance in Ship.Instances) { Ship val = (Ship)(object)((instance is Ship) ? instance : null); if (!((Object)(object)val == (Object)null)) { Consider(((Component)val).gameObject, wantBoats, wantCarts, position, rangeSqr); } } List list = Carts.Invoke(); if (list != null) { foreach (Vagon item in list) { if (!((Object)(object)item == (Object)null)) { Consider(((Component)item).gameObject, wantBoats, wantCarts, position, rangeSqr); } } } foreach (VehicleIndex.Record item2 in VehicleRpc.Remote) { if (!_wanted.ContainsKey(item2.Id)) { VehicleKinds.Kind kind = VehicleKinds.Get(item2.Prefab); if (kind != null && !(kind.IsBoat ? (!wantBoats) : (!wantCarts))) { _wanted[item2.Id] = new Vehicle { Instance = null, Pos = item2.Pos, Heading = item2.Heading, Kind = kind }; } } } } private static void Consider(GameObject go, bool wantBoats, bool wantCarts, Vector3 origin, float rangeSqr) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) ZNetView component = go.GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } Vector3 position = go.transform.position; Vector3 val = position - origin; if (!(((Vector3)(ref val)).sqrMagnitude > rangeSqr)) { ZDO zDO = component.GetZDO(); VehicleKinds.Kind kind = VehicleKinds.Get(zDO.GetPrefab()); if (kind != null && !(kind.IsBoat ? (!wantBoats) : (!wantCarts))) { Dictionary wanted = _wanted; ZDOID uid = zDO.m_uid; Vehicle value = new Vehicle { Instance = go.transform, Pos = position }; Quaternion rotation = go.transform.rotation; value.Heading = ((Quaternion)(ref rotation)).eulerAngles.y; value.Kind = kind; wanted[uid] = value; } } } private static void Reconcile() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Expected O, but got Unknown Minimap instance = Minimap.instance; _gone.Clear(); foreach (KeyValuePair item in _tracked) { if (!_wanted.ContainsKey(item.Key)) { _gone.Add(item.Key); } } foreach (ZDOID item2 in _gone) { instance.RemovePin(_tracked[item2].Pin); _tracked.Remove(item2); } foreach (KeyValuePair item3 in _wanted) { Vehicle value = item3.Value; if (_tracked.TryGetValue(item3.Key, out Tracked value2)) { value2.Instance = value.Instance; if ((Object)(object)value.Instance == (Object)null) { value2.Pin.m_pos = value.Pos; value2.Heading = value.Heading; } continue; } bool flag = _named && !string.IsNullOrEmpty(value.Kind.Label); PinData val = instance.AddPin(value.Pos, PinLegend.VehicleType, flag ? value.Kind.Label : "", false, false, 0L, default(PlatformUserID)); Sprite val2 = (value.Kind.IsBoat ? Icons.Boat : Icons.Cart); if ((Object)(object)val2 != (Object)null) { val.m_icon = val2; } if (flag) { val.m_NamePinData = new PinNameData(val); } _tracked[item3.Key] = new Tracked { Pin = val, Instance = value.Instance, Heading = value.Heading }; } } private static void UpdatePositions() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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) bool flag = false; foreach (KeyValuePair item in _tracked) { Tracked value = item.Value; if (!((Object)(object)value.Instance == (Object)null)) { Vector3 position = value.Instance.position; if (value.Pin.m_pos != position) { value.Pin.m_pos = position; flag = true; } Quaternion rotation = value.Instance.rotation; value.Heading = ((Quaternion)(ref rotation)).eulerAngles.y; } } if (flag) { MapPins.RequestRedraw(); } } public static void RestylePins() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (_tracked.Count == 0 || !Plugin.rotateBoatIcons.Value) { return; } foreach (KeyValuePair item in _tracked) { Tracked value = item.Value; if (value.Pin != null && !((Object)(object)value.Pin.m_uiElement == (Object)null)) { ((Transform)value.Pin.m_uiElement).localRotation = Quaternion.Euler(0f, 0f, 0f - value.Heading); } } } public static void Clear() { if ((Object)(object)Minimap.instance != (Object)null) { foreach (KeyValuePair item in _tracked) { if (item.Value.Pin != null) { Minimap.instance.RemovePin(item.Value.Pin); } } } _tracked.Clear(); _wanted.Clear(); } } [HarmonyPatch] public static class VehiclePatches { [HarmonyPostfix] [HarmonyPatch(typeof(Minimap), "UpdatePins")] private static void Minimap_UpdatePins_Postfix() { VehicleTracker.RestylePins(); } [HarmonyPostfix] [HarmonyPatch(typeof(Minimap), "UpdatePlayerMarker")] private static void Minimap_UpdatePlayerMarker_Postfix(Minimap __instance) { if (Plugin.showBoats.Value) { if ((Object)(object)__instance.m_smallShipMarker != (Object)null) { ((Component)__instance.m_smallShipMarker).gameObject.SetActive(false); } if ((Object)(object)__instance.m_largeShipMarker != (Object)null) { ((Component)__instance.m_largeShipMarker).gameObject.SetActive(false); } } } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "StartDoodadControl")] private static void Player_StartDoodadControl_Postfix(Player __instance, IDoodadController shipControl) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && shipControl != null) { Remember(shipControl.GetControlledComponent()); } } [HarmonyPostfix] [HarmonyPatch(typeof(Vagon), "AttachTo")] private static void Vagon_AttachTo_Postfix(Vagon __instance, GameObject go) { if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)go != (Object)(object)((Component)Player.m_localPlayer).gameObject)) { Remember((Component)(object)__instance); } } private static void Remember(Component component) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)component == (Object)null)) { ZNetView component2 = component.GetComponent(); if (!((Object)(object)component2 == (Object)null) && component2.IsValid() && VehicleKinds.Get(component2.GetZDO().GetPrefab()) != null) { VehicleMemory.Remember(component2.GetZDO().m_uid); } } } [HarmonyPostfix] [HarmonyPatch(typeof(Game), "Start")] private static void Game_Start_Postfix() { VehicleRpc.Register(); } [HarmonyPostfix] [HarmonyPatch(typeof(Game), "Logout")] private static void Game_Logout_Postfix() { VehicleRpc.Reset(); VehicleMemory.Forget(); } } } namespace BetterMap.Scripts.Creatures { public static class CreatureIcons { private static readonly Dictionary _icons = new Dictionary(); public static Sprite Get(Character creature) { if ((Object)(object)creature == (Object)null) { return null; } string text = PrefabName(((Component)creature).gameObject); if (_icons.TryGetValue(text, out Sprite value)) { return value; } Sprite val = Resolve(((Component)creature).gameObject); _icons[text] = val; if (Plugin.debugMode.Value) { Plugin.Logger.LogInfo((object)("CreatureIcons: " + text + " -> " + (((Object)(object)val != (Object)null) ? ((Object)val).name : "no trophy"))); } return val; } private static Sprite Resolve(GameObject prefab) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown CharacterDrop component = prefab.GetComponent(); if (component?.m_drops == null) { return null; } foreach (Drop drop in component.m_drops) { if (!((Object)(object)drop?.m_prefab == (Object)null) && ((Object)drop.m_prefab).name.StartsWith("Trophy", StringComparison.OrdinalIgnoreCase)) { Sprite[] array = drop.m_prefab.GetComponent()?.m_itemData?.m_shared?.m_icons; if (array != null && array.Length != 0) { return array[0]; } } } return null; } public static string PrefabName(GameObject go) { string name = ((Object)go).name; int num = name.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { return name.Substring(0, num); } return name; } public static void Clear() { _icons.Clear(); } } public static class CreatureTracker { private class Tracked { public Character Creature; public PinData Pin; public bool Tamed; public bool Named; public string Label; public bool Hostile; public bool HasIcon; } private struct Style { public Sprite Icon; public bool Tamed; public bool Named; public string Label; public bool Hostile; } private static readonly Dictionary _tracked = new Dictionary(); private static readonly List _leaving = new List(); private static readonly List _characters = new List(); private static float _nextRefresh; private static readonly HashSet Excluded = new HashSet { "piece_TrainingDummy", "FrozenKing_p2", "FrozenKing_p3" }; private static readonly Color TamedTint = new Color(0.45f, 0.95f, 0.45f, 1f); private static readonly Color HostileTint = new Color(0.95f, 0.4f, 0.4f, 1f); public static void Tick() { if (!Plugin.showCreatures.Value) { if (_tracked.Count > 0) { Clear(); } } else if (!((Object)(object)Minimap.instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null)) { if (Time.time >= _nextRefresh) { _nextRefresh = Time.time + Plugin.creatureRefreshInterval.Value; Refresh(); } UpdatePositions(); } } private static void Refresh() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)Player.m_localPlayer).transform.position; float value = Plugin.explorationRadius.Value; float num = value * value; _leaving.Clear(); Vector3 val; foreach (KeyValuePair item in _tracked) { Character key = item.Key; if (!((Object)(object)key == (Object)null) && !key.IsDead()) { val = ((Component)key).transform.position - position; if (!(((Vector3)(ref val)).sqrMagnitude > num)) { continue; } } _leaving.Add(key); } foreach (Character item2 in _leaving) { Remove(item2); } _leaving.Clear(); foreach (KeyValuePair item3 in _tracked) { if (!((Object)(object)item3.Key == (Object)null)) { Style style = Describe(item3.Key); Tracked value2 = item3.Value; value2.Hostile = style.Hostile; if (style.Tamed != value2.Tamed || style.Named != value2.Named || (style.Named && style.Label != value2.Label)) { _leaving.Add(item3.Key); } } } foreach (Character item4 in _leaving) { Remove(item4); Add(item4); } _characters.Clear(); _characters.AddRange(Character.GetAllCharacters()); foreach (Character character in _characters) { if (!_tracked.ContainsKey(character) && ShouldTrack(character)) { val = ((Component)character).transform.position - position; if (!(((Vector3)(ref val)).sqrMagnitude > num)) { Add(character); } } } } private static void UpdatePositions() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) bool flag = false; foreach (KeyValuePair item in _tracked) { if (!((Object)(object)item.Key == (Object)null)) { Vector3 position = ((Component)item.Key).transform.position; if (!(item.Value.Pin.m_pos == position)) { item.Value.Pin.m_pos = position; flag = true; } } } if (flag) { MapPins.RequestRedraw(); } } private static bool ShouldTrack(Character creature) { if ((Object)(object)creature == (Object)null || creature.IsDead()) { return false; } if (creature.IsPlayer()) { return false; } if ((Object)(object)((Component)creature).GetComponent() != (Object)null) { return false; } string text = CreatureIcons.PrefabName(((Component)creature).gameObject); if (text.StartsWith("Aspect_", StringComparison.Ordinal)) { return false; } if (Excluded.Contains(text)) { return false; } return true; } private static Style Describe(Character creature) { Sprite val = CreatureIcons.Get(creature); bool flag = creature.IsTamed(); string text = GivenName(creature); bool flag2 = (Object)(object)val == (Object)null || (flag && !string.IsNullOrEmpty(text)) || Plugin.showEntityNames.Value; return new Style { Icon = val, Tamed = flag, Named = flag2, Hostile = IsHostile(creature, flag), Label = ((!flag2) ? null : ((!string.IsNullOrEmpty(text)) ? text : Localization.instance.Localize(creature.m_name))) }; } private static void Add(Character creature) { //IL_0012: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown Style style = Describe(creature); PinData val = Minimap.instance.AddPin(((Component)creature).transform.position, PinLegend.CreatureType, style.Named ? style.Label : "", false, false, 0L, default(PlatformUserID)); if ((Object)(object)style.Icon != (Object)null) { val.m_icon = style.Icon; } if (style.Named) { val.m_NamePinData = new PinNameData(val); } _tracked[creature] = new Tracked { Creature = creature, Pin = val, Tamed = style.Tamed, Named = style.Named, Label = style.Label, Hostile = style.Hostile, HasIcon = ((Object)(object)style.Icon != (Object)null) }; } private static bool IsHostile(Character creature, bool tamed) { if (tamed) { return false; } BaseAI baseAI = creature.GetBaseAI(); MonsterAI val = (MonsterAI)(object)((baseAI is MonsterAI) ? baseAI : null); if ((Object)(object)val == (Object)null) { return false; } if (((BaseAI)val).m_aggravatable && !((BaseAI)val).IsAggravated()) { return false; } if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)30)) { return false; } return true; } private static void Remove(Character creature) { if (_tracked.TryGetValue(creature, out Tracked value)) { _tracked.Remove(creature); if ((Object)(object)Minimap.instance != (Object)null && value.Pin != null) { Minimap.instance.RemovePin(value.Pin); } } } private static string GivenName(Character creature) { Tameable component = ((Component)creature).GetComponent(); if ((Object)(object)component == (Object)null) { return null; } string text = component.GetText(); if (!string.IsNullOrEmpty(text)) { return text; } return null; } public static void RestylePins() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) if (_tracked.Count == 0 || (Object)(object)Minimap.instance == (Object)null) { return; } bool value = Plugin.tintTamedCreatures.Value; bool value2 = Plugin.tintHostileCreatures.Value; foreach (KeyValuePair item in _tracked) { Tracked value3 = item.Value; PinData pin = value3.Pin; if ((Object)(object)pin?.m_iconElement == (Object)null) { continue; } if (value3.Tamed) { if (value) { ((Graphic)pin.m_iconElement).color = TamedTint; } } else if (value2 && value3.Hostile && !value3.HasIcon) { ((Graphic)pin.m_iconElement).color = HostileTint; } } } public static void Clear() { if ((Object)(object)Minimap.instance != (Object)null) { foreach (KeyValuePair item in _tracked) { if (item.Value.Pin != null) { Minimap.instance.RemovePin(item.Value.Pin); } } } _tracked.Clear(); } } [HarmonyPatch] public static class CreaturePatches { [HarmonyPostfix] [HarmonyPatch(typeof(Minimap), "UpdatePins")] private static void Minimap_UpdatePins_Postfix() { CreatureTracker.RestylePins(); } } } namespace BetterMap.Scripts.Pins { public enum PinCategory { Ore, Forage, Dungeon, Loot, Spawner, Vegvisir, Beehive, Tar, Sap, Boss, Portal } public static class PinRules { public class Rule { public string Name; public string Description; public string NameToken; public string[] Prefabs; public Biome Biome; public PinCategory Category; public bool DefaultOn; public bool IsLocation; public ConfigEntry Enabled; } public static readonly List All = new List { new Rule { Name = "Beehives", Description = "Wild beehives, in and around the abandoned houses. Honey and a queen bee.", NameToken = "$piece_beehive", Prefabs = new string[1] { "Beehive" }, Biome = (Biome)1, Category = PinCategory.Beehive, DefaultOn = true, IsLocation = false }, new Rule { Name = "Vegvisirs", Description = "The runestones that reveal a boss on your map.", NameToken = "$piece_vegvisir", Prefabs = new string[7] { "Vegvisir_Eikthyr", "Vegvisir_GDKing", "Vegvisir_Bonemass", "Vegvisir_DragonQueen", "Vegvisir_GoblinKing", "Vegvisir_Fader", "Vegvisir_DNBoss" }, Biome = (Biome)1, Category = PinCategory.Vegvisir, DefaultOn = true, IsLocation = false }, new Rule { Name = "Raspberry Bushes", Description = "Raspberry bushes.", Prefabs = new string[1] { "RaspberryBush" }, Biome = (Biome)1, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Flint", Description = "Flint along the shoreline.", Prefabs = new string[1] { "Pickable_Flint" }, Biome = (Biome)1, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Mushrooms", Description = "Ordinary mushrooms.", Prefabs = new string[1] { "Pickable_Mushroom" }, Biome = (Biome)1, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Dandelions", Description = "Dandelions.", Prefabs = new string[1] { "Pickable_Dandelion" }, Biome = (Biome)1, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Boar Runestones", Description = "Runestones ringed by boar spawners. A place to farm, not a place to gather.", Prefabs = new string[1] { "Runestone_Boars" }, Biome = (Biome)1, Category = PinCategory.Spawner, DefaultOn = false, IsLocation = true }, new Rule { Name = "Altar of Eikthyr", Description = "Where Eikthyr is summoned. Off by default: use a vegvisir and the game pins it for you.", Prefabs = new string[1] { "Eikthyrnir" }, Biome = (Biome)1, Category = PinCategory.Boss, DefaultOn = false, IsLocation = true }, new Rule { Name = "Vegvisirs", Description = "The runestones that reveal a boss on your map. Pinned wherever they stand, rather than the ruin around them.", NameToken = "$piece_vegvisir", Prefabs = new string[7] { "Vegvisir_Eikthyr", "Vegvisir_GDKing", "Vegvisir_Bonemass", "Vegvisir_DragonQueen", "Vegvisir_GoblinKing", "Vegvisir_Fader", "Vegvisir_DNBoss" }, Biome = (Biome)8, Category = PinCategory.Vegvisir, DefaultOn = true, IsLocation = false }, new Rule { Name = "Copper Deposits", Description = "The large half buried rocks you mine for copper.", Prefabs = new string[1] { "rock4_copper" }, Biome = (Biome)8, Category = PinCategory.Ore, DefaultOn = true, IsLocation = false }, new Rule { Name = "Tin Deposits", Description = "Tin along the water's edge.", Prefabs = new string[1] { "MineRock_Tin" }, Biome = (Biome)8, Category = PinCategory.Ore, DefaultOn = true, IsLocation = false }, new Rule { Name = "Beehives", Description = "Wild beehives in the abandoned houses.", NameToken = "$piece_beehive", Prefabs = new string[1] { "Beehive" }, Biome = (Biome)8, Category = PinCategory.Beehive, DefaultOn = true, IsLocation = false }, new Rule { Name = "Blueberry Bushes", Description = "Blueberry bushes. Common enough that pinning them fills the map quickly.", Prefabs = new string[1] { "BlueberryBush" }, Biome = (Biome)8, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Thistle", Description = "Thistle, which glows at night and is easier to spot than to pin.", Prefabs = new string[1] { "Pickable_Thistle" }, Biome = (Biome)8, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Carrot Seeds", Description = "Wild carrot seeds. Rare, and the only way to start a carrot farm.", Prefabs = new string[1] { "Pickable_SeedCarrot" }, Biome = (Biome)8, Category = PinCategory.Forage, DefaultOn = true, IsLocation = false }, new Rule { Name = "Greydwarf Nests", Description = "The nests that keep sending greydwarfs at you. Break one for an ancient seed.", NameToken = "Greydwarf Nest", Prefabs = new string[1] { "Spawner_GreydwarfNest" }, Biome = (Biome)8, Category = PinCategory.Spawner, DefaultOn = false, IsLocation = false }, new Rule { Name = "Greydwarf Runestones", Description = "Runestones ringed by greydwarf spawners.", Prefabs = new string[1] { "Runestone_Greydwarfs" }, Biome = (Biome)8, Category = PinCategory.Spawner, DefaultOn = false, IsLocation = true }, new Rule { Name = "Burial Chambers", Description = "The entrances to burial chambers, where the surtling cores are.", Prefabs = new string[3] { "Crypt2", "Crypt3", "Crypt4" }, Biome = (Biome)8, Category = PinCategory.Dungeon, DefaultOn = true, IsLocation = true }, new Rule { Name = "Troll Caves", Description = "Troll cave entrances.", Prefabs = new string[1] { "TrollCave02" }, Biome = (Biome)8, Category = PinCategory.Dungeon, DefaultOn = true, IsLocation = true }, new Rule { Name = "Bear Caves", Description = "Bear cave entrances.", Prefabs = new string[1] { "BearCave" }, Biome = (Biome)8, Category = PinCategory.Dungeon, DefaultOn = true, IsLocation = true }, new Rule { Name = "Mushrooms", Description = "Ordinary mushrooms.", Prefabs = new string[1] { "Pickable_Mushroom" }, Biome = (Biome)8, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Altar of the Elder", Description = "Where the Elder is summoned. Off by default: use a vegvisir and the game pins it for you.", Prefabs = new string[1] { "GDKing" }, Biome = (Biome)8, Category = PinCategory.Boss, DefaultOn = false, IsLocation = true }, new Rule { Name = "Vegvisirs", Description = "The runestones that reveal a boss on your map.", NameToken = "$piece_vegvisir", Prefabs = new string[7] { "Vegvisir_Eikthyr", "Vegvisir_GDKing", "Vegvisir_Bonemass", "Vegvisir_DragonQueen", "Vegvisir_GoblinKing", "Vegvisir_Fader", "Vegvisir_DNBoss" }, Biome = (Biome)2, Category = PinCategory.Vegvisir, DefaultOn = true, IsLocation = false }, new Rule { Name = "Turnip Seeds", Description = "Wild turnip seeds. Rare, and the only way to start a turnip farm.", Prefabs = new string[1] { "Pickable_SeedTurnip" }, Biome = (Biome)2, Category = PinCategory.Forage, DefaultOn = true, IsLocation = false }, new Rule { Name = "Thistle", Description = "Thistle.", Prefabs = new string[1] { "Pickable_Thistle" }, Biome = (Biome)2, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Sunken Crypts", Description = "The iron doors into the sunken crypts, where the iron scrap is.", Prefabs = new string[1] { "SunkenCrypt4" }, Biome = (Biome)2, Category = PinCategory.Dungeon, DefaultOn = true, IsLocation = true }, new Rule { Name = "Muddy Scrap Piles", Description = "The mud piles you dig for iron scrap. Only inside the crypts, so rarely worth a pin.", Prefabs = new string[1] { "mudpile_beacon" }, Biome = (Biome)2, Category = PinCategory.Ore, DefaultOn = false, IsLocation = false }, new Rule { Name = "Surtling Fire Holes", Description = "The burning holes that keep producing surtlings.", Prefabs = new string[1] { "FireHole" }, Biome = (Biome)2, Category = PinCategory.Spawner, DefaultOn = false, IsLocation = true }, new Rule { Name = "Draugr Runestones", Description = "Runestones ringed by draugr spawners.", Prefabs = new string[1] { "Runestone_Draugr" }, Biome = (Biome)2, Category = PinCategory.Spawner, DefaultOn = false, IsLocation = true }, new Rule { Name = "Mushrooms", Description = "Ordinary mushrooms.", Prefabs = new string[1] { "Pickable_Mushroom" }, Biome = (Biome)2, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Altar of Bonemass", Description = "Where Bonemass is summoned. Off by default: use a vegvisir and the game pins it for you.", Prefabs = new string[1] { "Bonemass" }, Biome = (Biome)2, Category = PinCategory.Boss, DefaultOn = false, IsLocation = true }, new Rule { Name = "Vegvisirs", Description = "The runestones that reveal a boss on your map.", NameToken = "$piece_vegvisir", Prefabs = new string[7] { "Vegvisir_Eikthyr", "Vegvisir_GDKing", "Vegvisir_Bonemass", "Vegvisir_DragonQueen", "Vegvisir_GoblinKing", "Vegvisir_Fader", "Vegvisir_DNBoss" }, Biome = (Biome)4, Category = PinCategory.Vegvisir, DefaultOn = true, IsLocation = false }, new Rule { Name = "Silver Deposits", Description = "Silver under the snow. Buried, so a pin is worth more here than anywhere else.", Prefabs = new string[1] { "silvervein" }, Biome = (Biome)4, Category = PinCategory.Ore, DefaultOn = true, IsLocation = false }, new Rule { Name = "Obsidian Deposits", Description = "The black spires you mine for obsidian.", Prefabs = new string[1] { "MineRock_Obsidian" }, Biome = (Biome)4, Category = PinCategory.Ore, DefaultOn = true, IsLocation = false }, new Rule { Name = "Drake Nests", Description = "The nests on the peaks, each holding a dragon egg.", Prefabs = new string[1] { "DrakeNest01" }, Biome = (Biome)4, Category = PinCategory.Forage, DefaultOn = true, IsLocation = true }, new Rule { Name = "Altar of Moder", Description = "Where Moder is summoned. Off by default: use a vegvisir and the game pins it for you.", Prefabs = new string[1] { "Dragonqueen" }, Biome = (Biome)4, Category = PinCategory.Boss, DefaultOn = false, IsLocation = true }, new Rule { Name = "Vegvisirs", Description = "The runestones that reveal a boss on your map.", NameToken = "$piece_vegvisir", Prefabs = new string[7] { "Vegvisir_Eikthyr", "Vegvisir_GDKing", "Vegvisir_Bonemass", "Vegvisir_DragonQueen", "Vegvisir_GoblinKing", "Vegvisir_Fader", "Vegvisir_DNBoss" }, Biome = (Biome)16, Category = PinCategory.Vegvisir, DefaultOn = true, IsLocation = false }, new Rule { Name = "Tar Pits", Description = "The black pools, with growths to pick and a nest of tar blobs guarding them.", Prefabs = new string[6] { "TarPit1", "TarPit1_1", "TarPit2", "TarPit2_1", "TarPit3", "TarPit3_1" }, Biome = (Biome)16, Category = PinCategory.Tar, DefaultOn = true, IsLocation = true }, new Rule { Name = "Fuling Totems", Description = "The totem in a fuling village, and the only way to summon Yagluth. Pinned instead of the village around it.", Prefabs = new string[1] { "goblin_totempole" }, Biome = (Biome)16, Category = PinCategory.Loot, DefaultOn = true, IsLocation = false }, new Rule { Name = "Cloudberry Bushes", Description = "Cloudberry bushes.", Prefabs = new string[1] { "CloudberryBush" }, Biome = (Biome)16, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Altar of Yagluth", Description = "Where Yagluth is summoned. Off by default: use a vegvisir and the game pins it for you.", Prefabs = new string[1] { "GoblinKing" }, Biome = (Biome)16, Category = PinCategory.Boss, DefaultOn = false, IsLocation = true }, new Rule { Name = "Yggdrasil Roots", Description = "The hanging roots you tap for sap.", Prefabs = new string[1] { "YggdrasilRoot" }, Biome = (Biome)512, Category = PinCategory.Sap, DefaultOn = true, IsLocation = false }, new Rule { Name = "Giant Remains", Description = "The bones and armour of the fallen giants. Black marble, and iron and copper scrap.", NameToken = "Giant Remains", Prefabs = new string[5] { "giant_ribs", "giant_helmet1", "giant_helmet2", "giant_sword1", "giant_sword2" }, Biome = (Biome)512, Category = PinCategory.Ore, DefaultOn = true, IsLocation = false }, new Rule { Name = "Magecap", Description = "The blue glowing mushrooms, for eitr.", Prefabs = new string[1] { "Pickable_Mushroom_Magecap" }, Biome = (Biome)512, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Jotun Puffs", Description = "The pale puffball mushrooms, for eitr.", Prefabs = new string[1] { "Pickable_Mushroom_JotunPuffs" }, Biome = (Biome)512, Category = PinCategory.Forage, DefaultOn = true, IsLocation = false }, new Rule { Name = "Entrance to the Queen", Description = "The way into the infested mine where the Queen waits.", Prefabs = new string[1] { "Mistlands_DvergrBossEntrance1" }, Biome = (Biome)512, Category = PinCategory.Dungeon, DefaultOn = true, IsLocation = true }, new Rule { Name = "Dvergr Needle Crates", Description = "The long crate holding a dvergr needle, which is what a sap extractor is built from. One stands in each guard tower, excavation, harbour and lighthouse.", Prefabs = new string[1] { "dvergrprops_crate_long" }, Biome = (Biome)512, Category = PinCategory.Loot, DefaultOn = true, IsLocation = false }, new Rule { Name = "Dvergr Excavations", Description = "Dvergr dig sites, with crates to break and dvergr who mind you breaking them.", Prefabs = new string[3] { "Mistlands_Excavation1", "Mistlands_Excavation2", "Mistlands_Excavation3" }, Biome = (Biome)512, Category = PinCategory.Loot, DefaultOn = true, IsLocation = true }, new Rule { Name = "Vegvisirs", Description = "The runestones that reveal a boss on your map.", NameToken = "$piece_vegvisir", Prefabs = new string[7] { "Vegvisir_Eikthyr", "Vegvisir_GDKing", "Vegvisir_Bonemass", "Vegvisir_DragonQueen", "Vegvisir_GoblinKing", "Vegvisir_Fader", "Vegvisir_DNBoss" }, Biome = (Biome)32, Category = PinCategory.Vegvisir, DefaultOn = true, IsLocation = false }, new Rule { Name = "Flametal", Description = "The flametal in the lava lakes.", Prefabs = new string[1] { "LeviathanLava" }, Biome = (Biome)32, Category = PinCategory.Ore, DefaultOn = true, IsLocation = false }, new Rule { Name = "Sulfur Arches", Description = "The yellow arches you pick for sulfur stone.", Prefabs = new string[1] { "SulfurArch" }, Biome = (Biome)32, Category = PinCategory.Ore, DefaultOn = true, IsLocation = true }, new Rule { Name = "Unstable Lava Rock", Description = "The cracked rocks holding proustite powder.", Prefabs = new string[1] { "UnstableLavaRock" }, Biome = (Biome)32, Category = PinCategory.Ore, DefaultOn = true, IsLocation = false }, new Rule { Name = "Vineberries", Description = "The vines in the charred ruins. Vineberries, which can be replanted.", Prefabs = new string[1] { "VineAsh" }, Biome = (Biome)32, Category = PinCategory.Forage, DefaultOn = true, IsLocation = false }, new Rule { Name = "Smoke Puffs", Description = "The smoking mushrooms.", Prefabs = new string[1] { "Pickable_SmokePuff" }, Biome = (Biome)32, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Ash Pots", Description = "The red clay pots, which break open for bronze and iron.", NameToken = "Ash Pot", Prefabs = new string[1] { "ashland_pot2_red" }, Biome = (Biome)32, Category = PinCategory.Loot, DefaultOn = true, IsLocation = false }, new Rule { Name = "Places of Mystery", Description = "Where the pieces of Dyrnwyn are. Three in the world, and no way to finish the sword without them.", Prefabs = new string[3] { "PlaceofMystery1", "PlaceofMystery2", "PlaceofMystery3" }, Biome = (Biome)32, Category = PinCategory.Loot, DefaultOn = true, IsLocation = true }, new Rule { Name = "Charred Fortresses", Description = "The fortresses, holding a molten core, a bell fragment and a great many charred.", Prefabs = new string[1] { "CharredFortress" }, Biome = (Biome)32, Category = PinCategory.Dungeon, DefaultOn = true, IsLocation = true }, new Rule { Name = "Charred Skulls", Description = "Skulls on the ground, picked for charred skull.", Prefabs = new string[1] { "Pickable_Charredskull" }, Biome = (Biome)32, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Volture Nests", Description = "Volture nests, built on asksvin carrion worth picking over.", Prefabs = new string[1] { "VoltureNest" }, Biome = (Biome)32, Category = PinCategory.Loot, DefaultOn = false, IsLocation = true }, new Rule { Name = "Charred Tower Ruins", Description = "Ruined towers with pots and fiddlehead.", Prefabs = new string[1] { "CharredTowerRuins1" }, Biome = (Biome)32, Category = PinCategory.Loot, DefaultOn = false, IsLocation = true }, new Rule { Name = "Charred Spawner Towers", Description = "Ruined towers built around a charred spawner.", Prefabs = new string[1] { "CharredTowerRuins3" }, Biome = (Biome)32, Category = PinCategory.Spawner, DefaultOn = false, IsLocation = true }, new Rule { Name = "Dvergr Town", Description = "The dvergr settlements out on the ash sea.", Prefabs = new string[1] { "CharredTowerRuins1_dvergr" }, Biome = (Biome)32, Category = PinCategory.Loot, DefaultOn = false, IsLocation = true }, new Rule { Name = "Altar of Fader", Description = "Where Fader is summoned. Off by default: use a vegvisir and the game pins it for you.", Prefabs = new string[1] { "FaderLocation" }, Biome = (Biome)32, Category = PinCategory.Boss, DefaultOn = false, IsLocation = true }, new Rule { Name = "Vegvisirs", Description = "The runestones that reveal a boss on your map.", NameToken = "$piece_vegvisir", Prefabs = new string[7] { "Vegvisir_Eikthyr", "Vegvisir_GDKing", "Vegvisir_Bonemass", "Vegvisir_DragonQueen", "Vegvisir_GoblinKing", "Vegvisir_Fader", "Vegvisir_DNBoss" }, Biome = (Biome)64, Category = PinCategory.Vegvisir, DefaultOn = true, IsLocation = false }, new Rule { Name = "Frozen Trolls", Description = "The trolls frozen into the ice, mined for gold ore. Needs a black metal pickaxe.", Prefabs = new string[2] { "DN_gammeltrollFrac01", "DN_gammeltrollFrac02" }, Biome = (Biome)64, Category = PinCategory.Ore, DefaultOn = true, IsLocation = true }, new Rule { Name = "Morkhalla", Description = "The black keeps, holding the ancient gemstones.", Prefabs = new string[1] { "MorkBorg" }, Biome = (Biome)64, Category = PinCategory.Dungeon, DefaultOn = true, IsLocation = true }, new Rule { Name = "Memorial Places", Description = "Eleven chests around a runestone and an offering bowl.", Prefabs = new string[1] { "NorthMemorialPlace" }, Biome = (Biome)64, Category = PinCategory.Loot, DefaultOn = true, IsLocation = true }, new Rule { Name = "Kale Seeds", Description = "Wild kale seeds. Rare, and the only way to start a kale farm.", Prefabs = new string[1] { "Pickable_SeedKale" }, Biome = (Biome)64, Category = PinCategory.Forage, DefaultOn = true, IsLocation = false }, new Rule { Name = "Lingonberry Bushes", Description = "Lingonberry bushes.", Prefabs = new string[1] { "LingonberryBush" }, Biome = (Biome)64, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "Snowballs", Description = "Snowballs.", Prefabs = new string[1] { "Pickable_Snowball" }, Biome = (Biome)64, Category = PinCategory.Forage, DefaultOn = false, IsLocation = false }, new Rule { Name = "The Hole", Description = "A camp built around a hole in the ice, with real goods in it.", Prefabs = new string[1] { "TheHole01" }, Biome = (Biome)64, Category = PinCategory.Loot, DefaultOn = false, IsLocation = true }, new Rule { Name = "Leviathans", Description = "The sleeping leviathans, mined for chitin. They dive once you start.", NameToken = "Leviathan", Prefabs = new string[1] { "Leviathan" }, Biome = (Biome)256, Category = PinCategory.Ore, DefaultOn = true, IsLocation = false } }; } public static class PinRecord { private struct Entry { public PinCategory Category; public float X; public float Z; } private const string CustomDataKey = "BetterMap.pinned"; private const float CellSize = 32f; private static readonly Dictionary> _cells = new Dictionary>(); private static long _world; private static bool _loaded; private static bool _dirty; public static int Count { get; private set; } public static bool Has(PinCategory category, Vector3 position, float within) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) Load(); if (!_loaded) { return false; } float num = within * within; int num2 = Mathf.FloorToInt(position.x / 32f); int num3 = Mathf.FloorToInt(position.z / 32f); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (!_cells.TryGetValue(Key(num2 + i, num3 + j), out List value)) { continue; } foreach (Entry item in value) { if (item.Category == category) { float num4 = item.X - position.x; float num5 = item.Z - position.z; if (num4 * num4 + num5 * num5 <= num) { return true; } } } } } return false; } public static void Add(PinCategory category, Vector3 position) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) Load(); if (_loaded) { Put(new Entry { Category = category, X = position.x, Z = position.z }); Count++; _dirty = true; } } public static void Flush() { if (!_dirty || !_loaded || (Object)(object)Player.m_localPlayer == (Object)null) { return; } _dirty = false; List list = new List(); if (Player.m_localPlayer.m_customData.TryGetValue("BetterMap.pinned", out var value) && !string.IsNullOrEmpty(value)) { string[] array = value.Split(new char[1] { '|' }); foreach (string text in array) { int num = text.IndexOf(';'); if (num > 0 && long.TryParse(text.Substring(0, num), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result != _world) { list.Add(text); } } } foreach (List value2 in _cells.Values) { foreach (Entry item in value2) { string[] obj = new string[4] { _world.ToString(CultureInfo.InvariantCulture), null, null, null }; int i = (int)item.Category; obj[1] = i.ToString(CultureInfo.InvariantCulture); float x = item.X; obj[2] = x.ToString("0.#", CultureInfo.InvariantCulture); x = item.Z; obj[3] = x.ToString("0.#", CultureInfo.InvariantCulture); list.Add(string.Join(";", obj)); } } Player.m_localPlayer.m_customData["BetterMap.pinned"] = string.Join("|", list.ToArray()); } public static void Wipe() { Load(); if (_loaded) { _cells.Clear(); Count = 0; _dirty = true; Flush(); Plugin.Logger.LogInfo((object)"PinRecord: wiped"); } } public static void Forget() { _cells.Clear(); _loaded = false; _dirty = false; _world = 0L; Count = 0; } private static void Load() { if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null) { return; } long worldUID = ZNet.instance.GetWorldUID(); if (_loaded && _world == worldUID) { return; } _cells.Clear(); _world = worldUID; _loaded = true; _dirty = false; Count = 0; if (!Player.m_localPlayer.m_customData.TryGetValue("BetterMap.pinned", out var value) || string.IsNullOrEmpty(value)) { return; } string[] array = value.Split(new char[1] { '|' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ';' }); if (array2.Length == 4 && long.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result == worldUID && int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) && float.TryParse(array2[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4)) { Put(new Entry { Category = (PinCategory)result2, X = result3, Z = result4 }); Count++; } } if (Plugin.debugMode.Value) { Plugin.Logger.LogInfo((object)$"PinRecord: {Count} places already pinned"); } } private static void Put(Entry entry) { long key = Key(Mathf.FloorToInt(entry.X / 32f), Mathf.FloorToInt(entry.Z / 32f)); if (!_cells.TryGetValue(key, out List value)) { value = new List(); _cells[key] = value; } value.Add(entry); } private static long Key(int x, int z) { return ((long)x << 32) ^ (uint)z; } } public static class PinNames { private static Dictionary _categories; private static readonly HashSet Filler = new HashSet { "Stone", "Wood", "RoundLog", "FineWood", "ElderBark", "YggdrasilWood", "Grausten" }; public static string For(PinRules.Rule rule, GameObject prefab) { if (!string.IsNullOrEmpty(rule.NameToken)) { return rule.NameToken; } return For(prefab) ?? rule.Name; } public static string For(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return null; } Piece component = prefab.GetComponent(); if ((Object)(object)component != (Object)null && !string.IsNullOrEmpty(component.m_name)) { return component.m_name; } Pickable component2 = prefab.GetComponent(); if ((Object)(object)component2?.m_itemPrefab != (Object)null) { string text = ItemName(component2.m_itemPrefab); if (text != null) { return text; } } MineRock component3 = prefab.GetComponent(); if ((Object)(object)component3 != (Object)null) { string text2 = DropName(component3.m_dropItems); if (text2 != null) { return text2; } } MineRock5 component4 = prefab.GetComponent(); if ((Object)(object)component4 != (Object)null) { string text3 = DropName(component4.m_dropItems); if (text3 != null) { return text3; } } DropOnDestroyed component5 = prefab.GetComponent(); if (component5?.m_dropWhenDestroyed != null) { string text4 = DropName(component5.m_dropWhenDestroyed); if (text4 != null) { return text4; } } Destructible component6 = prefab.GetComponent(); if ((Object)(object)component6?.m_spawnWhenDestroyed != (Object)null) { return For(component6.m_spawnWhenDestroyed); } HoverText component7 = prefab.GetComponent(); if ((Object)(object)component7 != (Object)null && !string.IsNullOrEmpty(component7.m_text)) { return component7.m_text; } return null; } public static bool Category(string name, out PinCategory category) { Build(); category = PinCategory.Ore; if (!string.IsNullOrEmpty(name) && _categories != null) { return _categories.TryGetValue(name, out category); } return false; } public static void Build() { if (_categories != null) { return; } ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { return; } Dictionary dictionary = new Dictionary(); foreach (PinRules.Rule item in PinRules.All) { string[] prefabs = item.Prefabs; foreach (string text in prefabs) { GameObject val = (item.IsLocation ? null : instance.GetPrefab(text)); if (!((Object)(object)val == (Object)null) || item.IsLocation) { string key = For(item, val); dictionary[key] = item.Category; } } } _categories = dictionary; if (Plugin.debugMode.Value) { Plugin.Logger.LogInfo((object)$"PinNames: {dictionary.Count} names known"); } } private static string ItemName(GameObject item) { SharedData val = item.GetComponent()?.m_itemData?.m_shared; if (!string.IsNullOrEmpty(val?.m_name)) { return val.m_name; } return null; } private static string DropName(DropTable table) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (table?.m_drops == null) { return null; } string text = null; foreach (DropData drop in table.m_drops) { if ((Object)(object)drop.m_item == (Object)null) { continue; } string text2 = ItemName(drop.m_item); if (text2 != null) { if (!Filler.Contains(((Object)drop.m_item).name)) { return text2; } if (text == null) { text = text2; } } } return text; } } public static class AutoPins { private class Watch { public readonly List Rules = new List(); public PinCategory? Shared; public bool IsLocation; } private static readonly FieldRef> Instances = AccessTools.FieldRefAccess>("m_instances"); private static Dictionary _byPrefab; private static Dictionary _byLocation; private static int _proxyHash; private static float _nextSweep; private static bool _forgotten; public static void Tick() { if (!Plugin.autoPin.Value || (Object)(object)Minimap.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || Time.time < _nextSweep) { return; } _nextSweep = Time.time + Plugin.autoPinInterval.Value; Build(); if (_byPrefab.Count != 0 || _byLocation.Count != 0) { if (_proxyHash == 0 && (Object)(object)ZoneSystem.instance != (Object)null && (Object)(object)ZoneSystem.instance.m_locationProxyPrefab != (Object)null) { _proxyHash = StringExtensionMethods.GetStableHashCode(((Object)ZoneSystem.instance.m_locationProxyPrefab).name); } if (Plugin.forgetPinned.Value && !_forgotten) { _forgotten = true; PinRecord.Wipe(); } Sweep(); PinRecord.Flush(); } } private static void Sweep() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)Player.m_localPlayer).transform.position; float value = Plugin.explorationRadius.Value; float num = value * value; float value2 = Plugin.autoPinMergeDistance.Value; foreach (KeyValuePair item in Instances.Invoke(ZNetScene.instance)) { ZDO key = item.Key; if (key == null || !key.IsValid()) { continue; } int prefab = key.GetPrefab(); if (PortalPins.IsPortal(prefab)) { Portal(key, position, num, value2); continue; } Watch value3; if (prefab == _proxyHash) { if (!_byLocation.TryGetValue(key.GetInt(ZDOVars.s_location, 0), out value3)) { continue; } } else if (!_byPrefab.TryGetValue(prefab, out value3)) { continue; } Vector3 position2 = key.GetPosition(); Vector3 val = position2 - position; if (((Vector3)(ref val)).sqrMagnitude > num || (value3.Shared.HasValue && PinRecord.Has(value3.Shared.Value, position2, value2))) { continue; } Biome val2 = Heightmap.FindBiome(position2); foreach (PinRules.Rule rule in value3.Rules) { if (rule.Biome == val2 && rule.Enabled != null && rule.Enabled.Value) { if (!PinRecord.Has(rule.Category, position2, value2)) { Place(rule, value3.IsLocation ? null : item.Value, position2); } break; } } } } private unsafe static void Portal(ZDO zdo, Vector3 origin, float rangeSqr, float merge) { //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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.autoPinPortals.Value) { return; } Vector3 position = zdo.GetPosition(); Vector3 val = position - origin; if (!(((Vector3)(ref val)).sqrMagnitude > rangeSqr) && !PinRecord.Has(PinCategory.Portal, position, merge)) { PinData val2 = Minimap.instance.AddPin(position, PortalPins.PinType, PortalPins.Label(PortalPins.TagOf(zdo)), true, false, 0L, default(PlatformUserID)); val2.m_NamePinData = new PinNameData(val2); PinRecord.Add(PinCategory.Portal, position); if (Plugin.debugMode.Value) { ManualLogSource logger = Plugin.Logger; val = position; logger.LogInfo((object)("AutoPins: portal at " + ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString() + " as " + val2.m_name)); } } } private static void Place(PinRules.Rule rule, ZNetView nview, Vector3 position) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_00c3: Unknown result type (might be due to invalid IL or missing references) string text = PinNames.For(rule, ((Object)(object)nview != (Object)null) ? ((Component)nview).gameObject : null); PinData val = Minimap.instance.AddPin(position, PinLegend.TypeOf(rule.Category), text, true, false, 0L, default(PlatformUserID)); Sprite val2 = Icons.For(rule.Category); if ((Object)(object)val2 != (Object)null) { val.m_icon = val2; } if (!string.IsNullOrEmpty(val.m_name)) { val.m_NamePinData = new PinNameData(val); } PinRecord.Add(rule.Category, position); if (Plugin.debugMode.Value) { Plugin.Logger.LogInfo((object)$"AutoPins: {rule.Name} ({rule.Category}) at {position} as \"{val.m_name}\""); } } public static void Restore() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Invalid comparison between Unknown and I4 if ((Object)(object)Minimap.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { return; } PinNames.Build(); int num = 0; foreach (PinData item in MapPins.Of(Minimap.instance)) { if (PinLegend.CategoryOf(item.m_type, out var category) || ((int)item.m_type == 3 && PinNames.Category(item.m_name, out category))) { Sprite val = Icons.For(category); if (!((Object)(object)val == (Object)null) && !((Object)(object)item.m_icon == (Object)(object)val)) { item.m_icon = val; num++; } } } if (num > 0 && Plugin.debugMode.Value) { Plugin.Logger.LogInfo((object)$"AutoPins: {num} icons put back"); } } private static void Build() { if (_byPrefab != null) { return; } _byPrefab = new Dictionary(); _byLocation = new Dictionary(); foreach (PinRules.Rule item in PinRules.All) { Dictionary dictionary = (item.IsLocation ? _byLocation : _byPrefab); string[] prefabs = item.Prefabs; for (int i = 0; i < prefabs.Length; i++) { int stableHashCode = StringExtensionMethods.GetStableHashCode(prefabs[i]); if (!dictionary.TryGetValue(stableHashCode, out var value)) { value = (dictionary[stableHashCode] = new Watch { IsLocation = item.IsLocation }); } value.Rules.Add(item); } } foreach (Watch value2 in _byPrefab.Values) { value2.Shared = value2.Rules[0].Category; foreach (PinRules.Rule rule in value2.Rules) { if (rule.Category != value2.Shared) { value2.Shared = null; } } } foreach (Watch value3 in _byLocation.Values) { value3.Shared = value3.Rules[0].Category; foreach (PinRules.Rule rule2 in value3.Rules) { if (rule2.Category != value3.Shared) { value3.Shared = null; } } } Verify(); if (Plugin.debugMode.Value) { Plugin.Logger.LogInfo((object)$"AutoPins: watching {_byPrefab.Count} prefabs and {_byLocation.Count} places"); } } private static void Verify() { ZNetScene instance = ZNetScene.instance; ZoneSystem instance2 = ZoneSystem.instance; foreach (PinRules.Rule item in PinRules.All) { string[] prefabs = item.Prefabs; foreach (string text in prefabs) { if (item.IsLocation) { if ((Object)(object)instance2 == (Object)null || instance2.m_locations == null) { continue; } bool flag = false; foreach (ZoneLocation location in instance2.m_locations) { if (location != null && location.m_prefabName == text) { flag = true; break; } } if (!flag) { Plugin.Logger.LogWarning((object)("AutoPins: \"" + item.Name + "\" watches a place named " + text + ", which this game has none of. Nothing will ever be pinned for it.")); } } else if ((Object)(object)instance != (Object)null && (Object)(object)instance.GetPrefab(text) == (Object)null) { Plugin.Logger.LogWarning((object)("AutoPins: \"" + item.Name + "\" watches a prefab named " + text + ", which this game has none of. Nothing will ever be pinned for it.")); } } } } } public static class PortalPins { private static readonly FieldRef> Icons = AccessTools.FieldRefAccess>("m_icons"); private static PinType _type = (PinType)6; private static bool _typeFound; private static HashSet _prefabs; public static PinType PinType => _type; public static string Label(string tag) { if (!string.IsNullOrEmpty(tag)) { return tag; } return "$piece_portal"; } public static bool IsPortal(int prefab) { if (_prefabs == null) { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || instance.m_prefabs == null) { return false; } _prefabs = new HashSet(); foreach (GameObject prefab2 in instance.m_prefabs) { if (!((Object)(object)prefab2 == (Object)null) && !((Object)(object)prefab2.GetComponent() == (Object)null)) { _prefabs.Add(StringExtensionMethods.GetStableHashCode(((Object)prefab2).name)); } } FindPinType(); } return _prefabs.Contains(prefab); } private static void FindPinType() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (_typeFound || (Object)(object)Minimap.instance == (Object)null) { return; } _typeFound = true; foreach (SpriteData item in Icons.Invoke(Minimap.instance)) { if (!((Object)(object)item.m_icon == (Object)null) && ((Object)item.m_icon).name.IndexOf("portal", StringComparison.OrdinalIgnoreCase) >= 0) { _type = item.m_name; if (Plugin.debugMode.Value) { Plugin.Logger.LogInfo((object)$"PortalPins: portals go on {_type}, drawn as {((Object)item.m_icon).name}"); } return; } } Plugin.Logger.LogWarning((object)$"PortalPins: no pin type is drawn with a portal, so portals will use {_type}. Their icon will be whatever that type carries."); } public static string TagOf(ZDO zdo) { return zdo.GetString(ZDOVars.s_tag, ""); } } public static class PinLegend { private static readonly PinCategory[] Ours = new PinCategory[9] { PinCategory.Ore, PinCategory.Forage, PinCategory.Dungeon, PinCategory.Loot, PinCategory.Spawner, PinCategory.Vegvisir, PinCategory.Beehive, PinCategory.Tar, PinCategory.Sap }; private const float Margin = 10f; private const float Gap = 6f; private static readonly FieldRef VisibleIconTypes = AccessTools.FieldRefAccess("m_visibleIconTypes"); private static readonly FieldRef> SelectedIcons = AccessTools.FieldRefAccess>("m_selectedIcons"); private static readonly Dictionary _types = new Dictionary(); private static readonly Dictionary _categories = new Dictionary(); private static Minimap _builtInto; private static readonly Action IconPressed = AccessTools.MethodDelegate>(AccessTools.Method(typeof(Minimap), "IconPressed", (Type[])null, (Type[])null), (object)null, false); private static readonly Action ToggleIconFilter = AccessTools.MethodDelegate>(AccessTools.Method(typeof(Minimap), "ToggleIconFilter", (Type[])null, (Type[])null), (object)null, false); public static PinType CreatureType { get; private set; } = (PinType)3; public static PinType VehicleType { get; private set; } = (PinType)0; public static PinType TypeOf(PinCategory category) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!_types.TryGetValue(category, out var value)) { return (PinType)3; } return value; } public static bool CategoryOf(PinType type, out PinCategory category) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return _categories.TryGetValue(type, out category); } public static void Install() { Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null || (Object)(object)_builtInto == (Object)(object)instance) { return; } _builtInto = instance; _types.Clear(); _categories.Clear(); CreatureType = (PinType)3; VehicleType = (PinType)0; try { Build(instance); } catch (Exception arg) { Plugin.Logger.LogError((object)$"PinLegend: could not add our pins to the legend, they will share a plain pin instead: {arg}"); _types.Clear(); _categories.Clear(); } } private static void Build(Minimap map) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Parent(map.m_selectedIcon4); RectTransform val2 = Parent(map.m_selectedIcon0); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)((Transform)val).parent == (Object)null) { Plugin.Logger.LogWarning((object)"PinLegend: the map legend does not look the way it used to, leaving it alone"); return; } Transform parent = ((Transform)val).parent; RectTransform val3 = (RectTransform)(object)((parent is RectTransform) ? parent : null); RectTransform val4 = Parent(map.m_selectedIconDeath); RectTransform extras = (RectTransform)(((Object)(object)val4 != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); int length = Enum.GetValues(typeof(PinType)).Length; Grow(map, length + Ours.Length + 2); Vector2 val5 = Step(map); Stretch(val3, val5, 5 + Ours.Length); for (int i = 0; i < Ours.Length; i++) { PinCategory pinCategory = Ours[i]; PinType val6 = (PinType)(length + i); Sprite val7 = Icons.For(pinCategory); if (!((Object)(object)val7 == (Object)null)) { map.m_icons.Add(new SpriteData { m_name = val6, m_icon = val7 }); RectTransform val8 = Clone(map, (Transform)(object)val, (Transform)(object)val3, val6, val7, pinCategory); if (!((Object)(object)val8 == (Object)null)) { val8.anchoredPosition = val2.anchoredPosition + val5 * (float)(5 + i); _types[pinCategory] = val6; _categories[val6] = pinCategory; } } } Unlisted(map, length + Ours.Length); Arrange(map, val3, extras); Plugin.Logger.LogInfo((object)$"PinLegend: {_types.Count} of our pins added to the legend"); } private static void Arrange(Minimap map, RectTransform vanilla, RectTransform extras) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)vanilla == (Object)null)) { Anchor(vanilla, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f)); vanilla.anchoredPosition = new Vector2(-10f, 0f); if ((Object)(object)extras != (Object)null) { Anchor(extras, new Vector2(1f, 0.5f), new Vector2(1f, 1f)); Rect rect = vanilla.rect; float num = -10f - ((Rect)(ref rect)).width - 6f; rect = vanilla.rect; extras.anchoredPosition = new Vector2(num, ((Rect)(ref rect)).height / 2f); } RectTransform val = (RectTransform)(((Object)(object)map.m_publicPosition != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val != (Object)null) { Anchor(val, new Vector2(1f, 0f), new Vector2(1f, 0f)); val.anchoredPosition = new Vector2(-10f, 10f); } RectTransform val2 = (((Object)(object)map.m_biomeNameLarge != (Object)null) ? map.m_biomeNameLarge.rectTransform : null); if ((Object)(object)val2 != (Object)null) { val2.anchorMin = new Vector2(0.5f, 1f); val2.anchorMax = new Vector2(0.5f, 1f); val2.pivot = new Vector2(0.5f, 1f); val2.anchoredPosition = new Vector2(0f, -10f); map.m_biomeNameLarge.alignment = (TextAlignmentOptions)258; } } } private static void Anchor(RectTransform rect, Vector2 anchor, Vector2 pivot) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) rect.anchorMin = anchor; rect.anchorMax = anchor; rect.pivot = pivot; } private static void Unlisted(Minimap map, int first) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) Sprite icon = map.m_icons.Find((SpriteData x) => (int)x.m_name == 3).m_icon; CreatureType = (PinType)first; VehicleType = (PinType)(first + 1); map.m_icons.Add(new SpriteData { m_name = CreatureType, m_icon = icon }); map.m_icons.Add(new SpriteData { m_name = VehicleType, m_icon = icon }); } private static void Stretch(RectTransform panel, Vector2 step, int slots) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)panel == (Object)null)) { float num = Mathf.Abs(step.y); if (!(num <= 0f)) { Rect rect = panel.rect; float num2 = ((Rect)(ref rect)).height - num * 5f; panel.sizeDelta = new Vector2(panel.sizeDelta.x, num * (float)slots + num2); } } } private static void Grow(Minimap map, int length) { bool[] array = VisibleIconTypes.Invoke(map); if (array == null || array.Length < length) { bool[] array2 = new bool[length]; for (int i = 0; i < array2.Length; i++) { array2[i] = array == null || i >= array.Length || array[i]; } VisibleIconTypes.Invoke(map) = array2; } } private static Vector2 Step(Minimap map) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Parent(map.m_selectedIcon3); RectTransform val2 = Parent(map.m_selectedIcon4); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return new Vector2(0f, -56f); } return val2.anchoredPosition - val.anchoredPosition; } private static RectTransform Clone(Minimap map, Transform template, Transform panel, PinType type, Sprite sprite, PinCategory category) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)panel == (Object)null) { return null; } GameObject obj = Object.Instantiate(((Component)template).gameObject, panel); ((Object)obj).name = "BetterMap_" + category; Image component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { component.sprite = sprite; } Button component2 = obj.GetComponent