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 SpawnTracker v0.1.2
plugins/SpawnTracker.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("0.0.0.0")] [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 SpawnTracker { [BepInPlugin("nnikoloo.SpawnTracker", "SpawnTracker", "0.1.2")] public class SpawnTrackerPlugin : BaseUnityPlugin { private class Entry { public Vector3 Position; public string Title; public string Status; public Color Color; public float Distance; } public const string Guid = "nnikoloo.SpawnTracker"; public const string ModName = "SpawnTracker"; public const string Version = "0.1.2"; private static readonly FieldRef<CreatureSpawner, ZNetView> CreatureSpawnerView = AccessTools.FieldRefAccess<CreatureSpawner, ZNetView>("m_nview"); private static readonly FieldRef<SpawnArea, ZNetView> SpawnAreaView = AccessTools.FieldRefAccess<SpawnArea, ZNetView>("m_nview"); private static readonly FieldRef<SpawnArea, float> SpawnAreaTimer = AccessTools.FieldRefAccess<SpawnArea, float>("m_spawnTimer"); private static readonly List<CreatureSpawner> AllCreatureSpawners = (List<CreatureSpawner>)AccessTools.Field(typeof(CreatureSpawner), "m_creatureSpawners").GetValue(null); private static readonly Color Alive = new Color(0.45f, 0.9f, 0.45f); private static readonly Color Waiting = new Color(1f, 0.82f, 0.3f); private static readonly Color Ready = new Color(1f, 0.45f, 0.35f); private static readonly Color Inactive = new Color(0.7f, 0.7f, 0.7f); private ConfigEntry<KeyboardShortcut> _toggleKey; private ConfigEntry<float> _range; private ConfigEntry<bool> _showLabels; private ConfigEntry<bool> _showList; private ConfigEntry<int> _listSize; private bool _visible = true; private float _nextScan; private readonly List<Entry> _entries = new List<Entry>(); private GUIStyle _labelStyle; private GUIStyle _listStyle; private void Awake() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) _toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Key to show or hide spawn information."); _range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range", 80f, "Maximum distance (metres) at which spawners are shown."); _showLabels = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowLabels", true, "Show floating labels above each spawner."); _showList = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowList", true, "Show the on-screen list of nearby spawners."); _listSize = ((BaseUnityPlugin)this).Config.Bind<int>("Display", "ListSize", 8, "How many spawners to show in the list."); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded. Press {2} to toggle.", "SpawnTracker", "0.1.2", _toggleKey.Value)); } private void Update() { //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) KeyboardShortcut value = _toggleKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { _visible = !_visible; } if (_visible && !(Time.time < _nextScan)) { _nextScan = Time.time + 0.5f; Scan(); } } private void Scan() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_006f: 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) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) _entries.Clear(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null) { return; } Vector3 position = ((Component)localPlayer).transform.position; float value = _range.Value; foreach (CreatureSpawner allCreatureSpawner in AllCreatureSpawners) { if ((Object)(object)allCreatureSpawner == (Object)null) { continue; } float num = Vector3.Distance(position, ((Component)allCreatureSpawner).transform.position); if (!(num > value)) { Entry entry = DescribeCreatureSpawner(allCreatureSpawner, num); if (entry != null) { _entries.Add(entry); } } } SpawnArea[] array = Object.FindObjectsOfType<SpawnArea>(); foreach (SpawnArea val in array) { float num2 = Vector3.Distance(position, ((Component)val).transform.position); if (!(num2 > value)) { Entry entry2 = DescribeSpawnArea(val, num2); if (entry2 != null) { _entries.Add(entry2); } } } _entries.Sort((Entry a, Entry b) => a.Distance.CompareTo(b.Distance)); } private static Entry DescribeCreatureSpawner(CreatureSpawner spawner, float distance) { //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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Invalid comparison between Unknown and I4 //IL_0074: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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_016b: 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_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) ZNetView obj = CreatureSpawnerView.Invoke(spawner); ZDO val = ((obj != null) ? obj.GetZDO() : null); if (val == null || (Object)(object)spawner.m_creaturePrefab == (Object)null) { return null; } Entry entry = new Entry { Position = ((Component)spawner).transform.position, Title = CreatureName(spawner.m_creaturePrefab), Distance = distance }; ZDOConnection connection = val.GetConnection(); bool flag = connection != null && (int)connection.m_type == 3; ZDOID connectionZDOID = val.GetConnectionZDOID((ConnectionType)3); if (!((ZDOID)(ref connectionZDOID)).IsNone() && ZDOMan.instance.GetZDO(connectionZDOID) != null) { entry.Status = Texts.Get("alive"); entry.Color = Alive; return entry; } if (spawner.m_respawnTimeMinuts <= 0f && flag) { entry.Status = Texts.Get("dead_no_respawn"); entry.Color = Inactive; return entry; } if (spawner.m_respawnTimeMinuts > 0f && flag) { DateTime dateTime = new DateTime(val.GetLong(ZDOVars.s_aliveTime, 0L)); double num = (double)spawner.m_respawnTimeMinuts * 60.0 - (ZNet.instance.GetTime() - dateTime).TotalSeconds; if (num > 0.0) { entry.Status = Texts.Get("respawns_in", FormatTime(num)); entry.Color = Waiting; return entry; } } List<string> list = CreatureSpawnerBlockers(spawner, distance); entry.Status = ((list.Count == 0) ? Texts.Get("ready") : Texts.Get("ready_blocked", string.Join(", ", list.ToArray()))); entry.Color = ((list.Count == 0) ? Ready : Waiting); return entry; } private static List<string> CreatureSpawnerBlockers(CreatureSpawner spawner, float distance) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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) List<string> list = new List<string>(); Vector3 position = ((Component)spawner).transform.position; if (!spawner.m_spawnAtDay && EnvMan.IsDay()) { list.Add(Texts.Get("wait_night")); } if (!spawner.m_spawnAtNight && EnvMan.IsNight()) { list.Add(Texts.Get("wait_day")); } if (!spawner.m_spawnInPlayerBase && (Object)(object)EffectArea.IsPointInsideArea(position, (Type)4, 0f) != (Object)null) { list.Add(Texts.Get("player_base")); } if (distance > spawner.m_triggerDistance) { list.Add(Texts.Get("get_within", spawner.m_triggerDistance.ToString("0"))); } else if (spawner.m_triggerNoise > 0f) { list.Add(Texts.Get("needs_noise")); } List<string> list2 = (((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.GetGlobalKeys() : null); if (list2 != null) { if (spawner.m_requiredGlobalKey != "" && !list2.Contains(spawner.m_requiredGlobalKey)) { list.Add(Texts.Get("needs_progress")); } if (spawner.m_blockingGlobalKey != "" && list2.Contains(spawner.m_blockingGlobalKey)) { list.Add(Texts.Get("disabled_progress")); } } return list; } private static Entry DescribeSpawnArea(SpawnArea area, float distance) { //IL_0088: 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) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) ZNetView val = SpawnAreaView.Invoke(area); if ((Object)(object)val == (Object)null || !val.IsValid()) { return null; } string[] array = (from p in area.m_prefabs where (Object)(object)p.m_prefab != (Object)null select CreatureName(p.m_prefab)).Distinct().ToArray(); Entry entry = new Entry(); entry.Position = ((Component)area).transform.position; entry.Title = Texts.Get("spawner", (array.Length != 0) ? string.Join(", ", array) : "?"); entry.Distance = distance; Entry entry2 = entry; CountInstances(area, out var near, out var total); string text = Texts.Get("counts", near, area.m_maxNear, total, area.m_maxTotal); if (near >= area.m_maxNear || total >= area.m_maxTotal) { entry2.Status = Texts.Get("full", text); entry2.Color = Alive; } else if (!val.IsOwner()) { entry2.Status = Texts.Get("other_owner", text); entry2.Color = Inactive; } else if (!Player.IsPlayerInRange(((Component)area).transform.position, area.m_triggerDistance)) { entry2.Status = Texts.Get("too_far", text); entry2.Color = Inactive; } else { float num = Mathf.Max(0f, area.m_spawnIntervalSec - SpawnAreaTimer.Invoke(area)); entry2.Status = Texts.Get("next_in", FormatTime(num), text); entry2.Color = ((num <= 4f) ? Ready : Waiting); } return entry2; } private static void CountInstances(SpawnArea area, out int near, out int total) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_0049: Unknown result type (might be due to invalid IL or missing references) near = 0; total = 0; Vector3 position = ((Component)area).transform.position; foreach (BaseAI baseAIInstance in BaseAI.BaseAIInstances) { if (!((Object)(object)baseAIInstance == (Object)null) && IsFromArea(area, ((Component)baseAIInstance).gameObject)) { float num = Utils.DistanceXZ(((Component)baseAIInstance).transform.position, position); if (num < area.m_nearRadius) { near++; } if (num < area.m_farRadius) { total++; } } } } private static bool IsFromArea(SpawnArea area, GameObject go) { Character component = go.GetComponent<Character>(); if ((Object)(object)component != (Object)null && component.IsTamed()) { return false; } foreach (SpawnData prefab in area.m_prefabs) { if ((Object)(object)prefab.m_prefab != (Object)null && ((Object)go).name.StartsWith(((Object)prefab.m_prefab).name, StringComparison.Ordinal)) { return true; } } return false; } private static string CreatureName(GameObject prefab) { Character component = prefab.GetComponent<Character>(); if ((Object)(object)component != (Object)null && Localization.instance != null) { return Localization.instance.Localize(component.m_name); } return ((Object)prefab).name; } private static string FormatTime(double seconds) { TimeSpan timeSpan = TimeSpan.FromSeconds(Math.Ceiling(seconds)); if (!(timeSpan.TotalHours >= 1.0)) { return $"{timeSpan.Minutes}:{timeSpan.Seconds:00}"; } return $"{(int)timeSpan.TotalHours}:{timeSpan.Minutes:00}:{timeSpan.Seconds:00}"; } private void OnGUI() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_004a: 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_005d: Expected O, but got Unknown //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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown if (_visible && _entries.Count != 0 && !((Object)(object)Player.m_localPlayer == (Object)null)) { if (_labelStyle == null) { _labelStyle = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontSize = 14, fontStyle = (FontStyle)1, richText = true }; _listStyle = new GUIStyle(GUI.skin.label) { fontSize = 14, richText = true }; } if (_showLabels.Value) { DrawLabels(); } if (_showList.Value) { DrawList(); } } } private void DrawLabels() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0044: 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_004a: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) Camera mainCamera = Utils.GetMainCamera(); if ((Object)(object)mainCamera == (Object)null) { return; } foreach (Entry entry in _entries) { Vector3 val = mainCamera.WorldToScreenPoint(entry.Position + Vector3.up * 2f); if (!(val.z <= 0f)) { string text = $"{entry.Title} <size=12>({entry.Distance:0} m)</size>\n<color=#{ColorUtility.ToHtmlStringRGB(entry.Color)}>{entry.Status}</color>"; DrawShadowed(new Rect(val.x - 160f, (float)Screen.height - val.y - 22f, 320f, 44f), text, _labelStyle); } } } private void DrawList() { //IL_0041: 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_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Min(_listSize.Value, _entries.Count); float num2 = (float)Screen.width - 460f - 20f; float num3 = 220f; DrawShadowed(new Rect(num2, num3, 460f, 20f), "<b>" + Texts.Get("list_title") + "</b> <size=11>(" + Texts.Get("list_hint", _toggleKey.Value) + ")</size>", _listStyle); for (int i = 0; i < num; i++) { Entry entry = _entries[i]; num3 += 20f; string text = $"{entry.Distance,4:0} m {entry.Title}: <color=#{ColorUtility.ToHtmlStringRGB(entry.Color)}>{entry.Status}</color>"; DrawShadowed(new Rect(num2, num3, 460f, 20f), text, _listStyle); } } private static void DrawShadowed(Rect rect, string text, GUIStyle style) { //IL_0000: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; GUI.color = new Color(0f, 0f, 0f, 0.85f); GUI.Label(new Rect(((Rect)(ref rect)).x + 1f, ((Rect)(ref rect)).y + 1f, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height), StripColors(text), style); GUI.color = color; GUI.Label(rect, text, style); } private static string StripColors(string text) { return Regex.Replace(text, "</?color[^>]*>", ""); } } internal static class Texts { private static readonly Dictionary<string, string> English = new Dictionary<string, string> { ["alive"] = "Alive", ["dead_no_respawn"] = "Dead · does not respawn", ["respawns_in"] = "Respawns in {0}", ["ready"] = "Ready to spawn", ["ready_blocked"] = "Ready · {0}", ["wait_night"] = "waiting for night", ["wait_day"] = "waiting for day", ["player_base"] = "blocked by a player base", ["get_within"] = "get within {0} m", ["needs_noise"] = "needs noise nearby", ["needs_progress"] = "needs more world progress", ["disabled_progress"] = "disabled by world progress", ["counts"] = "{0}/{1} near, {2}/{3} total", ["full"] = "Full ({0})", ["other_owner"] = "Timer owned by another player ({0})", ["too_far"] = "Inactive, too far ({0})", ["next_in"] = "Next in ~{0} ({1})", ["spawner"] = "Spawner: {0}", ["list_title"] = "Nearby spawners", ["list_hint"] = "{0} to hide" }; private static readonly Dictionary<string, string> Spanish = new Dictionary<string, string> { ["alive"] = "Vivo", ["dead_no_respawn"] = "Muerto · no reaparece", ["respawns_in"] = "Reaparece en {0}", ["ready"] = "Listo para aparecer", ["ready_blocked"] = "Listo · {0}", ["wait_night"] = "espera la noche", ["wait_day"] = "espera el día", ["player_base"] = "bloqueado por una base", ["get_within"] = "acércate a {0} m", ["needs_noise"] = "necesita ruido cerca", ["needs_progress"] = "requiere más progreso", ["disabled_progress"] = "desactivado por el progreso", ["counts"] = "{0}/{1} cerca, {2}/{3} total", ["full"] = "Lleno ({0})", ["other_owner"] = "Temporizador en otro jugador ({0})", ["too_far"] = "Inactivo, muy lejos ({0})", ["next_in"] = "Próximo en ~{0} ({1})", ["spawner"] = "Spawner: {0}", ["list_title"] = "Spawners cercanos", ["list_hint"] = "{0} para ocultar" }; private static readonly Dictionary<string, Dictionary<string, string>> Languages = new Dictionary<string, Dictionary<string, string>> { ["English"] = English, ["Spanish"] = Spanish }; public static string Get(string key, params object[] args) { string text = ((Localization.instance != null) ? Localization.instance.GetSelectedLanguage() : null); if (text == null || !Languages.TryGetValue(text, out var value) || !value.TryGetValue(key, out var value2)) { value2 = English[key]; } if (args.Length != 0) { return string.Format(value2, args); } return value2; } } }