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.0.0
Plugins/HexRareScanner.dll
Decompiled 3 days 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 HexRareScanner; 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")] [HarmonyPatch(typeof(Character), "OnDeath")] internal static class PatchCharacterOnDeath { internal static void Prefix(Character __instance) { if (Plugin.IsModEnabled && !((Object)(object)__instance == (Object)null)) { string prefabNameFromClone = PrefabNameHelper.GetPrefabNameFromClone(((Object)((Component)__instance).gameObject).name); int creatureLevel = Plugin.GetCreatureLevel(__instance); if (Plugin.IsTrackedPrefab(prefabNameFromClone, creatureLevel)) { PinManager.RemoveCreaturePin(__instance); } } } } namespace HexRareScanner { internal static class PinManager { private static readonly Dictionary<ZDOID, PinData> PinsByZdoid = new Dictionary<ZDOID, PinData>(); private static readonly FieldInfo CharacterNViewField = typeof(Character).GetField("m_nview", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo RemovePinMethod = typeof(Minimap).GetMethod("RemovePin", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(PinData) }, null); internal static void AddCreaturePin(Character character, Vector3 position, string pinName) { //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_0031: 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_005e: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Minimap.instance == (Object)null) { return; } ZDOID zdoId = GetZdoId(character); string text = (((Object)(object)character != (Object)null) ? ((Object)((Component)character).gameObject).name : "null"); if (zdoId == ZDOID.None) { Plugin.Log.LogWarning((object)("Could not get ZDOID for character " + text + ". Pin will not be added.")); } else if (!PinsByZdoid.ContainsKey(zdoId)) { PinData val = Minimap.instance.AddPin(position, (PinType)12, pinName, false, false, 0L, default(PlatformUserID)); if (val != null) { 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_0031: 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_005e: 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_008d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Minimap.instance == (Object)null)) { ZDOID zdoId = GetZdoId(character); string text = (((Object)(object)character != (Object)null) ? ((Object)((Component)character).gameObject).name : "null"); PinData value; if (zdoId == ZDOID.None) { Plugin.Log.LogWarning((object)("Could not get ZDOID for character " + text + ". Pin will not be removed.")); } else if (PinsByZdoid.TryGetValue(zdoId, out value)) { RemovePinMethod?.Invoke(Minimap.instance, new object[1] { value }); PinsByZdoid.Remove(zdoId); } else { Plugin.Log.LogWarning((object)$"No pin found for {text}. ZDOID: {zdoId}"); } } } 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(); } } [BepInPlugin("com.hex.rarescanner", "HexRareScanner", "1.0.0")] public class Plugin : BaseUnityPlugin { private 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.0.0"; private Harmony _harmonyInstance; private static ConfigEntry<bool> _isModEnabled; private static ConfigEntry<bool> _playTrackedCreatureSound; private static readonly Dictionary<string, TrackedCreatureSetting> TrackedCreatures = new Dictionary<string, TrackedCreatureSetting>(); internal static readonly FieldInfo CharacterMLevelField = typeof(Character).GetField("m_level", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static Plugin Instance; internal static ManualLogSource Log; internal static bool IsModEnabled => _isModEnabled?.Value ?? false; internal static bool PlayTrackedCreatureSound => _playTrackedCreatureSound?.Value ?? false; private void Awake() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; InitializeConfig(); _harmonyInstance = new Harmony("com.hex.rarescanner"); _harmonyInstance.PatchAll(); Log.LogInfo((object)"HexRareScanner v1.0.0 loaded."); } private void OnDestroy() { Log.LogInfo((object)"HexRareScanner v1.0.0 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>("General", "PlayTrackedCreatureSound", true, "Enable or disable the tracked creature spawn sound."); AddTrackedCreature("Serpent", "Track Sea Serpents", "Sea Serpent", "sfx_serpent_taunt"); AddTrackedCreature("BonemawSerpent", "Track Bonemaw Serpents", "Bonemaw Serpent", "sfx_bonemaw_serpent_alert"); AddTrackedCreature("Troll", "Track Trolls", "Troll", "sfx_troll_idle"); AddTrackedCreature("Bjorn", "Track Black Forest Bears", "Black Forest Bear", "sfx_bear_bite_attack"); AddTrackedCreature("Unbjorn", "Track Vile Bears", "Vile Bear", "sfx_bear_bite_attack"); AddTrackedCreature("Abomination", "Track Abominations", "Abomination", "sfx_abomination_arise_end"); AddTrackedCreature("StoneGolem", "Track Stone Golems", "Stone Golem", "sfx_stonegolem_idle"); AddTrackedCreature("Morgen", "Track Morgens", "Morgen", "sfx_morgen_idle"); AddTrackedCreature("Wolf", "Track 2-star Wolves", "Wolf", "sfx_wolf_alerted", 3); AddTrackedCreature("Boar", "Track 2-star Boars", "Boar", "sfx_boar_idle", 3); AddTrackedCreature("Deer", "Track 2-star Deer", "Deer", "sfx_deer_idle", 3); AddTrackedCreature("Asksvin", "Track 2-star Asksvin", "Asksvin", "sfx_asksvin_idle", 3); AddTrackedCreature("FallenValkyrie", "Track Fallen Valkyrie", "FallenValkyrie", "sfx_valkyrie_flapwing"); } private void AddTrackedCreature(string prefabName, string configName, string displayName, string soundEffectName, int rarityLevel = 1) { TrackedCreatures[prefabName] = new TrackedCreatureSetting(((BaseUnityPlugin)this).Config.Bind<bool>("Tracking", configName, true, "Enable or disable tracking of " + displayName + "."), displayName, soundEffectName, rarityLevel); } internal static bool IsTrackedPrefab(string prefabName, int creatureLevel) { if (!IsModEnabled) { return false; } if (TryGetTrackedCreature(prefabName, out var trackedCreature) && trackedCreature.Enabled != null && trackedCreature.Enabled.Value) { return creatureLevel >= trackedCreature.RarityLevel; } return false; } internal static string GetDisplayName(string prefabName) { if (!TryGetTrackedCreature(prefabName, out var trackedCreature)) { return prefabName; } return trackedCreature.DisplayName; } internal static string GetSoundEffectName(string prefabName) { if (!TryGetTrackedCreature(prefabName, out var trackedCreature)) { return null; } return trackedCreature.SoundEffectName; } internal static int GetCreatureLevel(Character character) { if ((Object)(object)character == (Object)null || CharacterMLevelField == null) { return 1; } object value = CharacterMLevelField.GetValue(character); if (value is int) { return (int)value; } return 1; } private static bool TryGetTrackedCreature(string prefabName, out TrackedCreatureSetting trackedCreature) { trackedCreature = null; if (string.IsNullOrEmpty(prefabName)) { return false; } if (TrackedCreatures.TryGetValue(prefabName, out trackedCreature)) { return trackedCreature != null; } return false; } } 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; } } } namespace HexRareScanner.Patches { [HarmonyPatch(typeof(Character), "Awake")] internal static class PatchCharacterAwake { private static void Postfix(Character __instance) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(DelayedScan(__instance)); } private static void PlayTrackedCreatureSound(string soundEffectName, Vector3 position) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(soundEffectName)) { return; } if ((Object)(object)ZNetScene.instance == (Object)null) { Plugin.Log.LogWarning((object)"ZNetScene.instance is null. Could not play tracked creature sound."); return; } GameObject prefab = ZNetScene.instance.GetPrefab(soundEffectName); if ((Object)(object)prefab == (Object)null) { Plugin.Log.LogWarning((object)("Could not find sound effect prefab: " + soundEffectName)); } else { Object.Instantiate<GameObject>(prefab, position, Quaternion.identity); } } private static IEnumerator DelayedScan(Character character) { yield return null; yield return null; if (!Plugin.IsModEnabled || (Object)(object)character == (Object)null) { yield break; } string prefabNameFromClone = PrefabNameHelper.GetPrefabNameFromClone(((Object)((Component)character).gameObject).name); int creatureLevel = Plugin.GetCreatureLevel(character); if (Plugin.IsTrackedPrefab(prefabNameFromClone, creatureLevel) && !PinManager.HasCreaturePin(character)) { string text = Plugin.GetDisplayName(prefabNameFromClone); if (creatureLevel > 1) { text = $"{creatureLevel - 1}-star {text}"; } Vector3 position = ((Component)character).transform.position; if (Plugin.PlayTrackedCreatureSound) { PlayTrackedCreatureSound(Plugin.GetSoundEffectName(prefabNameFromClone), position); } Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "A " + text + " spawned!", 0, (Sprite)null); } PinManager.AddCreaturePin(character, position, text); } } } }