Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of AutoPOI v1.0.0
plugins/AutoPOI.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using Splatform; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("AutoPOI")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+90281b069b35b7b6cd4a175e69adb4f239147e05")] [assembly: AssemblyProduct("AutoPOI")] [assembly: AssemblyTitle("AutoPOI")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace AutoPOI { internal enum PinIcon { Fire, House, Hammer, Dot, Portal, Boss } internal static class AutoPOIConfig { public static ConfigEntry<bool> Enabled; public static ConfigEntry<float> DetectionRadius; public static ConfigEntry<bool> ShowMessage; public static ConfigEntry<bool> MarkEntered; public static ConfigEntry<bool> PinDungeons; public static ConfigEntry<PinIcon> DungeonIcon; public static ConfigEntry<bool> PinBosses; public static ConfigEntry<PinIcon> BossIcon; public static ConfigEntry<bool> PinVendors; public static ConfigEntry<PinIcon> VendorIcon; public static ConfigEntry<bool> LogNearbyLocations; public static void Bind(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown Enabled = config.Bind<bool>("General", "Enabled", true, "Automatically pin points of interest you come near."); DetectionRadius = config.Bind<float>("General", "DetectionRadius", 50f, new ConfigDescription("How close you must get to a point of interest, in metres, before it is pinned.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f), Array.Empty<object>())); ShowMessage = config.Bind<bool>("General", "ShowMessage", true, "Show the usual \"Pin added\" message in the corner when a point of interest is pinned."); MarkEntered = config.Bind<bool>("General", "MarkEntered", true, "Cross out a dungeon or boss pin once you have been inside the dungeon or stepped into the boss arena."); PinDungeons = config.Bind<bool>("Dungeons", "Enabled", true, "Pin dungeons and caves: Burial Chambers, Troll Caves, Sunken Crypts, Frost Caves, Infested Mines, Hildir's dungeons, Ashlands and Deep North dungeons."); DungeonIcon = config.Bind<PinIcon>("Dungeons", "Icon", PinIcon.Dot, "Map icon for dungeon pins."); PinBosses = config.Bind<bool>("Bosses", "Enabled", true, "Pin boss altars and arenas."); BossIcon = config.Bind<PinIcon>("Bosses", "Icon", PinIcon.Boss, "Map icon for boss pins."); PinVendors = config.Bind<bool>("Vendors", "Enabled", true, "Pin Haldor, Hildir and the Bog Witch."); VendorIcon = config.Bind<PinIcon>("Vendors", "Icon", PinIcon.House, "Map icon for vendor pins."); LogNearbyLocations = config.Bind<bool>("Debug", "LogNearbyLocations", false, "Write every location inside the detection radius to the BepInEx log, pinned or not. Useful for reporting a point of interest the mod does not recognise."); } public static PinType ToPinType(PinIcon icon) { return (PinType)(icon switch { PinIcon.Fire => 0, PinIcon.House => 1, PinIcon.Hammer => 2, PinIcon.Portal => 6, PinIcon.Boss => 9, _ => 3, }); } } [BepInPlugin("com.noodle.autopoi", "AutoPOI", "1.0.0")] internal class AutoPOIPlugin : BaseUnityPlugin { public const string PluginGuid = "com.noodle.autopoi"; public const string PluginName = "AutoPOI"; public const string PluginVersion = "1.0.0"; private const float ScanInterval = 3f; private const float MatchRadius = 12f; internal static ManualLogSource Log; private readonly Dictionary<int, PoiInfo> m_kinds = new Dictionary<int, PoiInfo>(); private readonly HashSet<int> m_logged = new HashSet<int>(); private PoiMemory m_memory; private float m_nextScan; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; AutoPOIConfig.Bind(((BaseUnityPlugin)this).Config); Log.LogInfo((object)"AutoPOI 1.0.0 loaded."); } private void Update() { if (Time.time < m_nextScan) { return; } m_nextScan = Time.time + 3f; if (AutoPOIConfig.Enabled.Value) { Player localPlayer = Player.m_localPlayer; Minimap instance = Minimap.instance; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)instance == (Object)null) && !((Object)(object)ZNet.instance == (Object)null) && !((Character)localPlayer).IsDead()) { m_memory = PoiMemory.For(m_memory, localPlayer, ZNet.instance.GetWorldUID()); Scan(localPlayer, instance); } } } private void Scan(Player player, Minimap minimap) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_0080: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)player).transform.position; float value = AutoPOIConfig.DetectionRadius.Value; bool flag = ((Character)player).InInterior(); Vector2s zone = ZoneSystem.GetZone(position); if (m_kinds.Count > 4096) { m_kinds.Clear(); m_logged.Clear(); } foreach (Location s_allLocation in Location.s_allLocations) { if ((Object)(object)s_allLocation == (Object)null) { continue; } Vector3 position2 = ((Component)s_allLocation).transform.position; float num = Utils.DistanceXZ(position, position2); bool flag2 = ((!s_allLocation.m_hasInterior) ? (!flag && num < s_allLocation.m_exteriorRadius) : (flag && ZoneSystem.GetZone(position2) == zone)); if (num > value && !flag2) { continue; } PoiInfo poiInfo = Classify(s_allLocation); if (AutoPOIConfig.LogNearbyLocations.Value && m_logged.Add(((Object)s_allLocation).GetInstanceID())) { Log.LogInfo((object)($"Nearby location {PoiCatalog.PrefabName(s_allLocation)} at {position2:F0}: " + $"{poiInfo.Kind} \"{poiInfo.Label}\", interior={s_allLocation.m_hasInterior}, " + $"radius={s_allLocation.m_exteriorRadius:F0}, {num:F0} m away")); } if (poiInfo.Kind != PoiKind.None && PoiCatalog.IsEnabled(poiInfo.Kind)) { PinData val = FindPin(minimap, position2); if (val == null && !m_memory.IsSeen(position2)) { val = AddPin(player, minimap, position2, poiInfo); } m_memory.MarkSeen(position2); if (flag2 && poiInfo.Kind != PoiKind.Vendor && AutoPOIConfig.MarkEntered.Value && val != null && !m_memory.IsEntered(position2)) { val.m_checked = true; minimap.m_pinUpdateRequired = true; m_memory.MarkEntered(position2); } } } } private PoiInfo Classify(Location location) { int instanceID = ((Object)location).GetInstanceID(); if (!m_kinds.TryGetValue(instanceID, out var value)) { value = PoiCatalog.Classify(location); m_kinds[instanceID] = value; } return value; } private static PinData AddPin(Player player, Minimap minimap, Vector3 pos, PoiInfo info) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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) PinType val = PoiCatalog.PinTypeFor(info.Kind); PinData result = minimap.AddPin(pos, val, info.Label, true, false, 0L, default(PlatformUserID)); if (AutoPOIConfig.ShowMessage.Value) { ((Character)player).Message((MessageType)1, "$msg_pin_added: " + info.Label, 0, minimap.GetSprite(val), false); } return result; } private static PinData FindPin(Minimap minimap, Vector3 pos) { //IL_0027: 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_0035: Unknown result type (might be due to invalid IL or missing references) PinData result = null; float num = 12f; foreach (PinData pin in minimap.m_pins) { if (pin.m_save && IsMarkerType(pin.m_type)) { float num2 = Utils.DistanceXZ(pos, pin.m_pos); if (num2 < num) { result = pin; num = num2; } } } return result; } private static bool IsMarkerType(PinType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected I4, but got Unknown switch ((int)type) { case 0: case 1: case 2: case 3: case 6: case 9: case 14: case 15: case 16: return true; default: return false; } } } internal enum PoiKind { None, Dungeon, Boss, Vendor } internal sealed class PoiInfo { public static readonly PoiInfo None = new PoiInfo(PoiKind.None, ""); public readonly PoiKind Kind; public readonly string Label; public PoiInfo(PoiKind kind, string label) { Kind = kind; Label = label; } } internal static class PoiCatalog { private static readonly Dictionary<string, PoiInfo> s_known = new Dictionary<string, PoiInfo> { { "Eikthyrnir", new PoiInfo(PoiKind.Boss, "Eikthyr") }, { "GDKing", new PoiInfo(PoiKind.Boss, "The Elder") }, { "Bonemass", new PoiInfo(PoiKind.Boss, "Bonemass") }, { "Dragonqueen", new PoiInfo(PoiKind.Boss, "Moder") }, { "GoblinKing", new PoiInfo(PoiKind.Boss, "Yagluth") }, { "Mistlands_DvergrBossEntrance1", new PoiInfo(PoiKind.Boss, "The Queen") }, { "FaderLocation", new PoiInfo(PoiKind.Boss, "Fader") }, { "Vendor_BlackForest", new PoiInfo(PoiKind.Vendor, "Haldor") }, { "Hildir_camp", new PoiInfo(PoiKind.Vendor, "Hildir") }, { "BogWitch_Camp", new PoiInfo(PoiKind.Vendor, "Bog Witch") }, { "Crypt2", new PoiInfo(PoiKind.Dungeon, "Burial Chambers") }, { "Crypt3", new PoiInfo(PoiKind.Dungeon, "Burial Chambers") }, { "Crypt4", new PoiInfo(PoiKind.Dungeon, "Burial Chambers") }, { "TrollCave02", new PoiInfo(PoiKind.Dungeon, "Troll Cave") }, { "SunkenCrypt1", new PoiInfo(PoiKind.Dungeon, "Sunken Crypt") }, { "SunkenCrypt2", new PoiInfo(PoiKind.Dungeon, "Sunken Crypt") }, { "SunkenCrypt3", new PoiInfo(PoiKind.Dungeon, "Sunken Crypt") }, { "SunkenCrypt4", new PoiInfo(PoiKind.Dungeon, "Sunken Crypt") }, { "MountainCave02", new PoiInfo(PoiKind.Dungeon, "Frost Cave") }, { "Mistlands_DvergrTownEntrance1", new PoiInfo(PoiKind.Dungeon, "Infested Mine") }, { "Mistlands_DvergrTownEntrance2", new PoiInfo(PoiKind.Dungeon, "Infested Mine") }, { "Hildir_crypt", new PoiInfo(PoiKind.Dungeon, "Smouldering Tomb") }, { "Hildir_cave", new PoiInfo(PoiKind.Dungeon, "Howling Cavern") }, { "Hildir_plainsfortress", new PoiInfo(PoiKind.Dungeon, "Sealed Tower") }, { "CharredFortress", new PoiInfo(PoiKind.Dungeon, "Charred Fortress") }, { "MorgenHole1", new PoiInfo(PoiKind.Dungeon, "Morgen Hole") }, { "MorgenHole2", new PoiInfo(PoiKind.Dungeon, "Morgen Hole") }, { "MorgenHole3", new PoiInfo(PoiKind.Dungeon, "Morgen Hole") } }; public static string PrefabName(Location location) { return Utils.GetPrefabName(((Component)location).gameObject); } public static PoiInfo Classify(Location location) { string text = PrefabName(location); if (s_known.TryGetValue(text, out var value)) { return value; } OfferingBowl componentInChildren = ((Component)location).GetComponentInChildren<OfferingBowl>(true); if ((Object)(object)componentInChildren != (Object)null) { string text2 = ((!((Object)(object)componentInChildren.m_bossPrefab != (Object)null)) ? null : componentInChildren.m_bossPrefab.GetComponent<Character>()?.m_name); return new PoiInfo(PoiKind.Boss, (!string.IsNullOrEmpty(text2)) ? text2 : FallbackLabel(location, text)); } Trader componentInChildren2 = ((Component)location).GetComponentInChildren<Trader>(true); if ((Object)(object)componentInChildren2 != (Object)null) { return new PoiInfo(PoiKind.Vendor, (!string.IsNullOrEmpty(componentInChildren2.m_name)) ? componentInChildren2.m_name : FallbackLabel(location, text)); } if (location.m_hasInterior) { return new PoiInfo(PoiKind.Dungeon, FallbackLabel(location, text)); } return PoiInfo.None; } private static string FallbackLabel(Location location, string prefab) { if (!string.IsNullOrEmpty(location.m_discoverLabel)) { return location.m_discoverLabel; } return Prettify(prefab); } private static string Prettify(string prefab) { string text = prefab.TrimEnd('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_'); StringBuilder stringBuilder = new StringBuilder(text.Length + 8); for (int i = 0; i < text.Length; i++) { char c = text[i]; if (c == '_') { stringBuilder.Append(' '); continue; } if (i > 0 && char.IsUpper(c) && char.IsLower(text[i - 1])) { stringBuilder.Append(' '); } stringBuilder.Append(c); } if (stringBuilder.Length <= 0) { return prefab; } return stringBuilder.ToString(); } public static bool IsEnabled(PoiKind kind) { return kind switch { PoiKind.Dungeon => AutoPOIConfig.PinDungeons.Value, PoiKind.Boss => AutoPOIConfig.PinBosses.Value, PoiKind.Vendor => AutoPOIConfig.PinVendors.Value, _ => false, }; } public static PinType PinTypeFor(PoiKind kind) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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) return (PinType)(kind switch { PoiKind.Boss => AutoPOIConfig.ToPinType(AutoPOIConfig.BossIcon.Value), PoiKind.Vendor => AutoPOIConfig.ToPinType(AutoPOIConfig.VendorIcon.Value), _ => AutoPOIConfig.ToPinType(AutoPOIConfig.DungeonIcon.Value), }); } } internal sealed class PoiMemory { private const string SeenPrefix = "AutoPOI.seen."; private const string EnteredPrefix = "AutoPOI.entered."; private readonly Player m_player; private readonly long m_worldUid; private readonly HashSet<long> m_seen; private readonly HashSet<long> m_entered; private PoiMemory(Player player, long worldUid) { m_player = player; m_worldUid = worldUid; m_seen = Load("AutoPOI.seen."); m_entered = Load("AutoPOI.entered."); } public static PoiMemory For(PoiMemory current, Player player, long worldUid) { if (current != null && (Object)(object)current.m_player == (Object)(object)player && current.m_worldUid == worldUid) { return current; } return new PoiMemory(player, worldUid); } public bool IsSeen(Vector3 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return m_seen.Contains(Key(pos)); } public bool IsEntered(Vector3 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return m_entered.Contains(Key(pos)); } public void MarkSeen(Vector3 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (m_seen.Add(Key(pos))) { Save("AutoPOI.seen.", m_seen); } } public void MarkEntered(Vector3 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (m_entered.Add(Key(pos))) { Save("AutoPOI.entered.", m_entered); } } private static long Key(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) long num = Mathf.RoundToInt(pos.x); long num2 = Mathf.RoundToInt(pos.z); return (num << 32) | (num2 & 0xFFFFFFFFu); } private HashSet<long> Load(string prefix) { HashSet<long> hashSet = new HashSet<long>(); Dictionary<string, string> customData = m_player.m_customData; long worldUid = m_worldUid; if (!customData.TryGetValue(prefix + worldUid, out var value) || string.IsNullOrEmpty(value)) { return hashSet; } string[] array = value.Split(new char[1] { ';' }); for (int i = 0; i < array.Length; i++) { if (long.TryParse(array[i], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { hashSet.Add(result); } } return hashSet; } private void Save(string prefix, HashSet<long> set) { StringBuilder stringBuilder = new StringBuilder(set.Count * 12); foreach (long item in set) { if (stringBuilder.Length > 0) { stringBuilder.Append(';'); } stringBuilder.Append(item.ToString(CultureInfo.InvariantCulture)); } Dictionary<string, string> customData = m_player.m_customData; long worldUid = m_worldUid; customData[prefix + worldUid] = stringBuilder.ToString(); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }