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 HexRareScanner v1.3.1
Plugins/HexRareScanner.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Splatform; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("HexRareScanner")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("HexRareScanner")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3c9bc10-9d16-4f15-b8bd-d4fe1c71af33")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace HexRareScanner { internal static class PinManager { private static readonly Dictionary<ZDOID, PinData> PinsByZdoid = new Dictionary<ZDOID, PinData>(); private static readonly FieldInfo CharacterNViewField = AccessTools.Field(typeof(Character), "m_nview"); private static readonly MethodInfo RemovePinMethod = AccessTools.Method(typeof(Minimap), "RemovePin", new Type[1] { typeof(PinData) }, (Type[])null); internal static void AddCreaturePin(Character character, Vector3 position, string pinName) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Minimap.instance == (Object)null || (Object)(object)character == (Object)null) { return; } ZDOID zdoId = GetZdoId(character); if (zdoId == ZDOID.None || PinsByZdoid.ContainsKey(zdoId)) { return; } PinData val = Minimap.instance.AddPin(position, (PinType)12, pinName, false, false, 0L, default(PlatformUserID)); if (val == null) { return; } TrackedCreatureDefinition creatureDefinition = GetCreatureDefinition(PrefabNameHelper.GetPrefabNameFromClone(((Object)((Component)character).gameObject).name)); if (creatureDefinition != null && Plugin.IsCreatureIconsEnabled) { Sprite creatureIcon = GetCreatureIcon(creatureDefinition.TrophyPrefabName); if ((Object)(object)creatureIcon != (Object)null) { SetPinIcon(val, creatureIcon); } } PinsByZdoid[zdoId] = val; } internal static void RemoveCreaturePin(Character character) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_0028: 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) if (!((Object)(object)Minimap.instance == (Object)null)) { ZDOID zdoId = GetZdoId(character); if (!(zdoId == ZDOID.None) && PinsByZdoid.TryGetValue(zdoId, out var value)) { RemovePinMethod?.Invoke(Minimap.instance, new object[1] { value }); PinsByZdoid.Remove(zdoId); } } } internal static PinData GetClosestCreaturePin(Vector3 position, float radius) { //IL_0045: 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) PinData result = null; float num = float.MaxValue; foreach (PinData value in PinsByZdoid.Values) { if (value != null && !((Object)(object)value.m_uiElement == (Object)null) && ((Component)value.m_uiElement).gameObject.activeInHierarchy) { float num2 = Utils.DistanceXZ(position, value.m_pos); if (!(num2 >= radius) && !(num2 >= num)) { result = value; num = num2; } } } return result; } internal static bool RemoveCreaturePin(PinData pin) { //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_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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if (pin == null || (Object)(object)Minimap.instance == (Object)null) { return false; } ZDOID val = ZDOID.None; foreach (KeyValuePair<ZDOID, PinData> item in PinsByZdoid) { if (item.Value == pin) { val = item.Key; break; } } if (val == ZDOID.None) { return false; } RemovePinMethod?.Invoke(Minimap.instance, new object[1] { pin }); PinsByZdoid.Remove(val); return true; } internal static ZDOID GetZdoId(Character character) { //IL_0016: 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_004a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || CharacterNViewField == null) { return ZDOID.None; } object? value = CharacterNViewField.GetValue(character); ZNetView val = (ZNetView)((value is ZNetView) ? value : null); if ((Object)(object)val == (Object)null || val.GetZDO() == null) { return ZDOID.None; } return val.GetZDO().m_uid; } internal static bool HasCreaturePin(Character character) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //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_001b: Unknown result type (might be due to invalid IL or missing references) ZDOID zdoId = GetZdoId(character); if (zdoId == ZDOID.None) { return false; } return PinsByZdoid.ContainsKey(zdoId); } internal static void Clear() { PinsByZdoid.Clear(); } private static TrackedCreatureDefinition GetCreatureDefinition(string prefabName) { foreach (TrackedCreatureDefinition creature in TrackedCreatureDefinition.Creatures) { if (creature.PrefabName == prefabName) { return creature; } } return null; } private static Sprite GetCreatureIcon(string trophyPrefabName) { if (string.IsNullOrEmpty(trophyPrefabName) || (Object)(object)ObjectDB.instance == (Object)null) { return null; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(trophyPrefabName); if ((Object)(object)itemPrefab == (Object)null) { return null; } ItemDrop component = itemPrefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null) { return null; } return component.m_itemData.GetIcon(); } private static void SetPinIcon(PinData pin, Sprite icon) { if (pin != null && !((Object)(object)icon == (Object)null)) { pin.m_icon = icon; if ((Object)(object)pin.m_iconElement != (Object)null) { pin.m_iconElement.sprite = icon; } } } } [BepInPlugin("com.hex.rarescanner", "HexRareScanner", "1.3.1")] public class Plugin : BaseUnityPlugin { internal sealed class TrackedCreatureSetting { internal ConfigEntry<bool> Enabled { get; } internal string DisplayName { get; } internal string SoundEffectName { get; } internal int RarityLevel { get; } internal TrackedCreatureSetting(ConfigEntry<bool> enabled, string displayName, string soundEffectName, int rarityLevel) { Enabled = enabled; DisplayName = displayName; SoundEffectName = soundEffectName; RarityLevel = rarityLevel; } } private const string PluginGuid = "com.hex.rarescanner"; private const string PluginName = "HexRareScanner"; private const string PluginVersion = "1.3.1"; private Harmony _harmonyInstance; private static ConfigEntry<bool> _isModEnabled; private static ConfigEntry<bool> _playTrackedCreatureSound; private static ConfigEntry<bool> _isManualPinRemovalEnabled; private static ConfigEntry<bool> _isCreatureIconsEnabled; private static readonly Dictionary<string, TrackedCreatureSetting> TrackedCreatures = new Dictionary<string, TrackedCreatureSetting>(); internal static Plugin Instance; internal static ManualLogSource Log; internal static readonly FieldInfo CharacterMLevelField = AccessTools.Field(typeof(Character), "m_level"); internal static bool IsModEnabled => _isModEnabled?.Value ?? false; internal static bool PlayTrackedCreatureSound => _playTrackedCreatureSound?.Value ?? false; internal static bool IsManualPinRemovalEnabled => _isManualPinRemovalEnabled?.Value ?? true; internal static bool IsCreatureIconsEnabled => _isCreatureIconsEnabled?.Value ?? true; private void Awake() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; InitializeConfig(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmonyInstance = new Harmony("com.hex.rarescanner"); _harmonyInstance.PatchAll(executingAssembly); Log.LogInfo((object)"HexRareScanner v1.3.1 loaded."); } private void OnDestroy() { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"HexRareScanner v1.3.1 unloaded."); } Harmony harmonyInstance = _harmonyInstance; if (harmonyInstance != null) { harmonyInstance.UnpatchSelf(); } _harmonyInstance = null; Instance = null; Log = null; } private void InitializeConfig() { TrackedCreatures.Clear(); _isModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IsModEnabled", true, "Enable or disable the mod."); _playTrackedCreatureSound = ((BaseUnityPlugin)this).Config.Bind<bool>("Sounds", "PlayTrackedCreatureSound", true, "Enable or disable the tracked creature spawn sound."); _isManualPinRemovalEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Map Pins", "Enable Manual Pin Removal", true, "Allow tracked creature pins to be removed by right-clicking them on the map."); _isCreatureIconsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Map Pins", "Enable Creature Icons", true, "Use creature icons for tracked creature map pins. When disabled, the default Valheim blue ping icon is used. Requires a game restart."); foreach (TrackedCreatureDefinition creature in TrackedCreatureDefinition.Creatures) { AddTrackedCreature(creature.ConfigSection, creature.PrefabName, creature.ConfigName, creature.DisplayName, creature.SoundEffectName, creature.MinimumLevel); } } private void AddTrackedCreature(string configSection, string prefabName, string configName, string displayName, string soundEffectName, int rarityLevel = 1) { TrackedCreatures[prefabName] = new TrackedCreatureSetting(((BaseUnityPlugin)this).Config.Bind<bool>(configSection, configName, true, "Enable or disable tracking of " + displayName + "."), displayName, soundEffectName, rarityLevel); } internal static TrackedCreatureSetting GetTrackedCreature(string prefabName) { if (!TrackedCreatures.TryGetValue(prefabName, out var value)) { return null; } if (!value.Enabled.Value) { return null; } return value; } } internal static class PrefabNameHelper { internal static string GetPrefabNameFromClone(string objectName) { if (string.IsNullOrEmpty(objectName)) { return string.Empty; } if (objectName.EndsWith("(Clone)")) { return objectName.Substring(0, objectName.Length - "(Clone)".Length); } return objectName; } } internal sealed class TrackedCreatureDefinition { internal static class Biomes { internal const string Ocean = "Tracked Creatures - Ocean"; internal const string Meadows = "Tracked Creatures - Meadows"; internal const string BlackForest = "Tracked Creatures - Black Forest"; internal const string Swamp = "Tracked Creatures - Swamp"; internal const string Mountains = "Tracked Creatures - Mountains"; internal const string Plains = "Tracked Creatures - Plains"; internal const string Mistlands = "Tracked Creatures - Mistlands"; internal const string Ashlands = "Tracked Creatures - Ashlands"; internal const string DeepNorth = "Tracked Creatures - Deep North"; } internal static readonly List<TrackedCreatureDefinition> Creatures = new List<TrackedCreatureDefinition> { new TrackedCreatureDefinition("Tracked Creatures - Ocean", "Serpent", "Track Sea Serpents", "Sea Serpent", "sfx_serpent_taunt", "TrophySerpent"), new TrackedCreatureDefinition("Tracked Creatures - Ocean", "BonemawSerpent", "Track Bonemaw Serpents", "Bonemaw Serpent", "sfx_bonemaw_serpent_alert", "TrophyBonemawSerpent"), new TrackedCreatureDefinition("Tracked Creatures - Meadows", "Deer", "Track 2-star Deer", "Deer", "sfx_deer_idle", "TrophyDeer", 3), new TrackedCreatureDefinition("Tracked Creatures - Meadows", "Deer_White", "Track White Deer", "White Deer", "sfx_deer_idle", "TrophyDeerWhite"), new TrackedCreatureDefinition("Tracked Creatures - Meadows", "Boar", "Track 2-star Boars", "Boar", "sfx_boar_idle", "TrophyBoar", 3), new TrackedCreatureDefinition("Tracked Creatures - Black Forest", "Troll", "Track Trolls", "Troll", "sfx_troll_idle", "TrophyForestTroll"), new TrackedCreatureDefinition("Tracked Creatures - Black Forest", "Bjorn", "Track Black Forest Bears", "Black Forest Bear", "sfx_bear_bite_attack", "TrophyBjorn"), new TrackedCreatureDefinition("Tracked Creatures - Swamp", "Abomination", "Track Abominations", "Abomination", "sfx_abomination_arise_end", "TrophyAbomination"), new TrackedCreatureDefinition("Tracked Creatures - Swamp", "Writhan", "Track Writhan", "Writhan", "sfx_writhan_verse_attack", "TrophyWrithan"), new TrackedCreatureDefinition("Tracked Creatures - Mountains", "StoneGolem", "Track Stone Golems", "Stone Golem", "sfx_stonegolem_idle", "TrophySGolem"), new TrackedCreatureDefinition("Tracked Creatures - Mountains", "Wolf", "Track 2-star Wolves", "Wolf", "sfx_wolf_alerted", "TrophyWolf", 3), new TrackedCreatureDefinition("Tracked Creatures - Plains", "Unbjorn", "Track Vile Bears", "Vile Bear", "sfx_bear_bite_attack", "TrophyBjorn"), new TrackedCreatureDefinition("Tracked Creatures - Mistlands", "SeekerBrute", "Track Seeker Soldiers", "Seeker Soldier", null, "TrophySeekerBrute"), new TrackedCreatureDefinition("Tracked Creatures - Mistlands", "Seeker", "Track 1-star or higher Seekers", "Seeker", null, "TrophySeeker", 2), new TrackedCreatureDefinition("Tracked Creatures - Mistlands", "Gjall", "Track Gjalls", "Gjall", null, "TrophyGjall"), new TrackedCreatureDefinition("Tracked Creatures - Ashlands", "Asksvin", "Track 2-star Asksvin", "Asksvin", "sfx_asksvin_idle", "TrophyAsksvin", 3), new TrackedCreatureDefinition("Tracked Creatures - Ashlands", "FallenValkyrie", "Track Fallen Valkyrie", "FallenValkyrie", "sfx_fallenvalkyrie_alert", "TrophyFallenValkyrie"), new TrackedCreatureDefinition("Tracked Creatures - Ashlands", "Morgen", "Track Morgens", "Morgen", "sfx_morgen_idle", "TrophyMorgen"), new TrackedCreatureDefinition("Tracked Creatures - Deep North", "Barka", "Track Barkas", "Barka", "Enemy_Barka_Footstep", "TrophyBarka"), new TrackedCreatureDefinition("Tracked Creatures - Deep North", "ShadowPerson", "Track Shadow Persons", "Shadow Person", null), new TrackedCreatureDefinition("Tracked Creatures - Deep North", "Skeleton_DeepNorth", "Track Deep North Skeletons", "Deep North Skeleton", null, "TrophySkeleton"), new TrackedCreatureDefinition("Tracked Creatures - Deep North", "Greydwarf_Frozen", "Track 2-star Frozen Greydwarfs", "Frozen Greydwarf", null, "TrophyGreydwarf", 3), new TrackedCreatureDefinition("Tracked Creatures - Deep North", "TrollFrost", "Track Gammeltrolls", "Gammeltroll", "sfx_gameltroll_melee_attack", "TrophyFrostTroll"), new TrackedCreatureDefinition("Tracked Creatures - Deep North", "Moose", "Track Moose", "Moose", "sfx_moose_alert", "TrophyMoose"), new TrackedCreatureDefinition("Tracked Creatures - Deep North", "FallenWarrior", "Track Fallen Warriors", "Fallen Warrior", "sfx_fallenwarrior_attack"), new TrackedCreatureDefinition("Tracked Creatures - Deep North", "ElakingMole", "Track Eyeless One", "Eyeless One", "ElakingMole_AttackClaw", "TrophyElaking"), new TrackedCreatureDefinition("Tracked Creatures - Deep North", "Elaking", "Track Elaking", "Elaking", "ElakingMole_AttackClaw", "TrophyElaking") }; internal string ConfigSection { get; } internal string PrefabName { get; } internal string ConfigName { get; } internal string DisplayName { get; } internal string SoundEffectName { get; } internal string TrophyPrefabName { get; } internal int MinimumLevel { get; } internal TrackedCreatureDefinition(string configSection, string prefabName, string configName, string displayName, string soundEffectName, string trophyPrefabName = null, int minimumLevel = 1) { ConfigSection = configSection; PrefabName = prefabName; ConfigName = configName; DisplayName = displayName; SoundEffectName = soundEffectName; TrophyPrefabName = trophyPrefabName; MinimumLevel = minimumLevel; } } } namespace HexRareScanner.Patches { [HarmonyPatch(typeof(Character), "OnDeath")] internal static class PatchCharacterOnDeath { private static void Prefix(Character __instance) { if (!Plugin.IsModEnabled || (Object)(object)__instance == (Object)null) { return; } string prefabNameFromClone = PrefabNameHelper.GetPrefabNameFromClone(((Object)((Component)__instance).gameObject).name); if (!string.IsNullOrWhiteSpace(prefabNameFromClone)) { Plugin.TrackedCreatureSetting trackedCreature = Plugin.GetTrackedCreature(prefabNameFromClone); if (trackedCreature != null && (int)Plugin.CharacterMLevelField.GetValue(__instance) >= trackedCreature.RarityLevel) { PinManager.RemoveCreaturePin(__instance); } } } } [HarmonyPatch(typeof(Character), "Awake")] internal static class PatchCharacterAwake { private static void Postfix(Character __instance) { //IL_007e: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.IsModEnabled || (Object)(object)__instance == (Object)null) { return; } string prefabNameFromClone = PrefabNameHelper.GetPrefabNameFromClone(((Object)((Component)__instance).gameObject).name); if (string.IsNullOrWhiteSpace(prefabNameFromClone)) { return; } Plugin.TrackedCreatureSetting trackedCreature = Plugin.GetTrackedCreature(prefabNameFromClone); if (trackedCreature == null) { return; } int num = (int)Plugin.CharacterMLevelField.GetValue(__instance); if (num >= trackedCreature.RarityLevel && !PinManager.HasCreaturePin(__instance)) { string text = trackedCreature.DisplayName; if (num > 1) { text = $"{num - 1}-star {text}"; } Vector3 position = ((Component)__instance).transform.position; if (Plugin.PlayTrackedCreatureSound) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(PlayTrackedCreatureSound(trackedCreature.SoundEffectName, position)); } Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "A " + text + " spawned!", 0, (Sprite)null, false); } PinManager.AddCreaturePin(__instance, position, text); } } private static IEnumerator PlayTrackedCreatureSound(string soundEffectName, Vector3 position) { //IL_000e: 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) yield return null; if (!string.IsNullOrEmpty(soundEffectName) && !((Object)(object)ZNetScene.instance == (Object)null)) { GameObject prefab = ZNetScene.instance.GetPrefab(soundEffectName); if (!((Object)(object)prefab == (Object)null)) { Object.Instantiate<GameObject>(prefab, position, Quaternion.identity); } } } } [HarmonyPatch(typeof(Minimap), "RemovePinUnderPointer")] internal static class PatchMinimapRemovePinUnderPointer { private static readonly MethodInfo ScreenToWorldPointMethod = AccessTools.Method(typeof(Minimap), "ScreenToWorldPoint", new Type[1] { typeof(Vector3) }, (Type[])null); private static readonly MethodInfo GetClosestPinMethod = AccessTools.Method(typeof(Minimap), "GetClosestPin", new Type[3] { typeof(Vector3), typeof(float), typeof(bool) }, (Type[])null); private static readonly MethodInfo HidePinTextInputMethod = AccessTools.Method(typeof(Minimap), "HidePinTextInput", new Type[1] { typeof(bool) }, (Type[])null); private static readonly PropertyInfo PinInteractRadiusProperty = AccessTools.Property(typeof(Minimap), "PinInteractRadius"); private static readonly FieldInfo NamePinField = AccessTools.Field(typeof(Minimap), "m_namePin"); private static bool Prefix(Minimap __instance) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_0092: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.IsModEnabled || !Plugin.IsManualPinRemovalEnabled || (Object)(object)__instance == (Object)null) { return true; } if (ScreenToWorldPointMethod == null || GetClosestPinMethod == null || PinInteractRadiusProperty == null) { return true; } Vector3 val = (Vector3)ScreenToWorldPointMethod.Invoke(__instance, new object[1] { ZInput.pointerPosition }); float num = (float)PinInteractRadiusProperty.GetValue(__instance); PinData closestCreaturePin = PinManager.GetClosestCreaturePin(val, num); if (closestCreaturePin == null) { return true; } object? obj = GetClosestPinMethod.Invoke(__instance, new object[3] { val, num, true }); PinData val2 = (PinData)((obj is PinData) ? obj : null); if (val2 != null) { float num2 = Utils.DistanceXZ(val, closestCreaturePin.m_pos); if (Utils.DistanceXZ(val, val2.m_pos) < num2) { return true; } } HidePinTextInputMethod?.Invoke(__instance, new object[1] { false }); PinManager.RemoveCreaturePin(closestCreaturePin); NamePinField?.SetValue(__instance, null); return false; } } }