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 SurveyorMap v1.0.1
plugins/HiarlyScripter-SurveyorMap/SurveyorMap.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; 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: AssemblyCompany("SurveyorMap")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+d12fde975d684e0319e1c39792c315ea8a8a57fd")] [assembly: AssemblyProduct("SurveyorMap")] [assembly: AssemblyTitle("SurveyorMap")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 SurveyorMap { [BepInPlugin("com.hiarlyscripter.surveyormap", "SurveyorMap", "1.0.0")] public sealed class SurveyorMapPlugin : BaseUnityPlugin { public const string PluginGuid = "com.hiarlyscripter.surveyormap"; public const string PluginName = "SurveyorMap"; public const string PluginVersion = "1.0.0"; private Harmony _harmony; private NativeMapMirror _mirror; private bool _hudVisible = true; private float _toggleCooldown; private float _nextDiagWrite; private float _nextEnemySweep; private int _updateCount; private int _onGuiCount; private bool _editMode; private bool _editDragActive; private bool _editResizeActive; private Vector2 _editDragOrigin; private float _editStartPosX; private float _editStartPosY; private float _editStartW; private float _editStartH; private bool _savedCursorVisible; private CursorLockMode _savedCursorLockState; private const float ToggleCooldown = 0.25f; private const float DiagWriteInterval = 5f; private const float EnemySweepInterval = 2f; internal static ManualLogSource Log { get; private set; } internal static SurveyorMapConfig Settings { get; private set; } internal static SurveyorMapPlugin Instance { get; private set; } internal static bool EditModeActive { get; private set; } internal static void LogDbg(string msg) { SurveyorMapConfig settings = Settings; if (settings != null && (settings.DebugLogging?.Value).GetValueOrDefault()) { Log.LogDebug((object)msg); } } private void Awake() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown Instance = this; if ((Object)(object)((Component)this).transform.parent != (Object)null) { ((Component)this).transform.parent = null; } ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); Log = ((BaseUnityPlugin)this).Logger; Settings = new SurveyorMapConfig(((BaseUnityPlugin)this).Config); _mirror = new NativeMapMirror(); _harmony = new Harmony("com.hiarlyscripter.surveyormap"); _harmony.PatchAll(typeof(SurveyorMapPlugin).Assembly); TryPatchDeathMethods(_harmony); string text = (SurveyorMapDiagnostics.AssemblyPath = Assembly.GetExecutingAssembly().Location); SurveyorMapDiagnostics.BuildTimestamp = File.GetLastWriteTimeUtc(text).ToString("yyyy-MM-ddTHH:mm:ssZ"); SurveyorMapDiagnostics.DiagnosticsDir = Path.Combine(Path.GetDirectoryName(text), "diagnostics"); SurveyorMapDiagnostics.RevealRoomsMode = Settings.RevealRoomsMode.Value; try { using MD5 mD = MD5.Create(); using FileStream inputStream = File.OpenRead(text); SurveyorMapDiagnostics.BuildMd5Short = BitConverter.ToString(mD.ComputeHash(inputStream)).Replace("-", "").ToLower() .Substring(0, 8); Log.LogInfo((object)("[SurveyorMap] v1.0.0 loaded. BuildTag md5=" + SurveyorMapDiagnostics.BuildMd5Short)); } catch (Exception ex) { Log.LogInfo((object)"[SurveyorMap] v1.0.0 loaded."); Log.LogWarning((object)("[SurveyorMap] MD5 compute failed: " + ex.Message)); } LogDbg("[SurveyorMap] asm=" + text); LogDbg($"[SurveyorMap] EnableMinimap={Settings.EnableMinimap.Value}" + " RevealRoomsMode=" + Settings.RevealRoomsMode.Value + $" ShowEnemies={Settings.ShowEnemies.Value}" + $" EnemyMarkerSize={Settings.EnemyMarkerSize.Value}" + $" EditModeEnabled={Settings.EditModeEnabled.Value}" + $" UnlockCursor={Settings.UnlockCursorInEditMode.Value}" + $" FreezeCamera={Settings.FreezeCameraInEditMode.Value}" + $" ZoomHotkeys={Settings.EnableZoomHotkeysOutsideEdit.Value}" + $" DebugLogging={Settings.DebugLogging.Value}"); } private static void TryPatchDeathMethods(Harmony harmony) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; MethodInfo method = typeof(EnemyDeathHelper).GetMethod("OnDeathRPC", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return; } HarmonyMethod val = new HarmonyMethod(method); string[] array = new string[2] { "DeathRPC", "DeathImpulseRPC" }; foreach (string text in array) { MethodInfo method2 = typeof(EnemyHealth).GetMethod(text, bindingAttr); if (!(method2 == null)) { try { harmony.Patch((MethodBase)method2, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); LogDbg("[SurveyorMap] Patched EnemyHealth." + text); } catch (Exception ex) { LogDbg("[SurveyorMap] Could not patch EnemyHealth." + text + ": " + ex.Message); } } } } private void Update() { //IL_0055: 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_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) _updateCount++; if (_toggleCooldown > 0f) { _toggleCooldown -= Time.unscaledDeltaTime; } if (_toggleCooldown <= 0f && Settings.EnableMinimap.Value && Input.GetKeyDown(Settings.ToggleKey.Value)) { _hudVisible = !_hudVisible; _toggleCooldown = 0.25f; SurveyorMapDiagnostics.ToggleKeyDetectedCount++; LogDbg($"[SurveyorMap] M toggle -> HUD={_hudVisible} count={SurveyorMapDiagnostics.ToggleKeyDetectedCount}"); } if (Settings.EditModeEnabled.Value && !_mirror.IsNativeTabActive && Input.GetKeyDown(Settings.EditModeKey.Value)) { _editMode = !_editMode; EditModeActive = _editMode; if (!_editMode) { if (Settings.UnlockCursorInEditMode.Value) { Cursor.lockState = _savedCursorLockState; Cursor.visible = _savedCursorVisible; } Input.ResetInputAxes(); ((BaseUnityPlugin)this).Config.Save(); LogDbg("[SurveyorMap] Edit mode OFF — config saved."); } else { if (Settings.UnlockCursorInEditMode.Value) { _savedCursorLockState = Cursor.lockState; _savedCursorVisible = Cursor.visible; } LogDbg("[SurveyorMap] Edit mode ON."); } } if (_editMode && Settings.UnlockCursorInEditMode.Value) { Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } if (_editMode && Settings.FreezeCameraInEditMode.Value) { try { if ((Object)(object)InputManager.instance != (Object)null) { InputManager.instance.DisableAiming(0.1f); } } catch (Exception ex) { LogDbg("[SurveyorMap] DisableAiming failed: " + ex.Message); } } if (!_editMode && Settings.EnableMinimap.Value && _hudVisible && !_mirror.IsNativeTabActive && Settings.EnableZoomHotkeysOutsideEdit.Value) { bool num = Input.GetKeyDown((KeyCode)43) || Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270); bool flag = Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269); if (num) { Settings.Zoom.Value = Mathf.Clamp(Settings.Zoom.Value - 0.1f, 0.5f, 10f); ((BaseUnityPlugin)this).Config.Save(); LogDbg($"[SurveyorMap] Zoom-in (outside edit): {Settings.Zoom.Value:0.00}"); } else if (flag) { Settings.Zoom.Value = Mathf.Clamp(Settings.Zoom.Value + 0.1f, 0.5f, 10f); ((BaseUnityPlugin)this).Config.Save(); LogDbg($"[SurveyorMap] Zoom-out (outside edit): {Settings.Zoom.Value:0.00}"); } } if (_mirror.IsNativeTabActive) { _editDragActive = false; _editResizeActive = false; } _mirror.Update(_hudVisible && Settings.EnableMinimap.Value); if (Time.unscaledTime >= _nextEnemySweep) { _nextEnemySweep = Time.unscaledTime + 2f; EnemyMapMarkerService.SweepDeadMarkers(); } if (Time.unscaledTime >= _nextDiagWrite) { _nextDiagWrite = Time.unscaledTime + 5f; SurveyorMapDiagnostics.HudVisible = _hudVisible; SurveyorMapDiagnostics.TabActive = _mirror.IsNativeTabActive; SurveyorMapDiagnostics.GameplayActive = _mirror.IsGameplayActive; SurveyorMapDiagnostics.TabOpenCount = _mirror.TabOpenCount; SurveyorMapDiagnostics.TabCloseCount = _mirror.TabCloseCount; SurveyorMapDiagnostics.UpdateCount = _updateCount; SurveyorMapDiagnostics.OnGuiCount = _onGuiCount; SurveyorMapDiagnostics.EnemyMarkerCount = EnemyMapMarkerService.ActiveMarkerCount; SurveyorMapDiagnostics.RevealRoomsMode = Settings.RevealRoomsMode.Value; SurveyorMapDiagnostics.WriteDiagJson(); } } private void OnGUI() { //IL_00a4: 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_00d6: Unknown result type (might be due to invalid IL or missing references) _onGuiCount++; if (!Settings.EnableMinimap.Value || !_hudVisible || !_mirror.IsGameplayActive || _mirror.IsNativeTabActive) { return; } Texture nativeTexture = _mirror.NativeTexture; if (!((Object)(object)nativeTexture == (Object)null)) { float value = Settings.Width.Value; float value2 = Settings.Height.Value; float value3 = Settings.PosX.Value; float num = (float)Screen.height - Settings.PosY.Value - value2; Color color = GUI.color; GUI.color = new Color(1f, 1f, 1f, Settings.Opacity.Value); GUI.DrawTexture(new Rect(value3, num, value, value2), nativeTexture, (ScaleMode)0, false); GUI.color = color; if (_editMode) { DrawEditOverlay(value3, num, value, value2); } } } private void DrawEditOverlay(float x, float y, float w, float h) { //IL_0051: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Expected I4, but got Unknown //IL_042b: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Invalid comparison between Unknown and I4 //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Unknown result type (might be due to invalid IL or missing references) //IL_043c: Invalid comparison between Unknown and I4 //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Unknown result type (might be due to invalid IL or missing references) //IL_0449: Invalid comparison between Unknown and I4 //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Unknown result type (might be due to invalid IL or missing references) //IL_048d: Invalid comparison between Unknown and I4 //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_049a: Invalid comparison between Unknown and I4 //IL_04d7: Unknown result type (might be due to invalid IL or missing references) //IL_04de: Invalid comparison between Unknown and I4 Event current = Event.current; Rect val = default(Rect); ((Rect)(ref val))..ctor(x, y, w, h); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(x + w - 24f, y + h - 24f, 24f, 24f); int controlID = GUIUtility.GetControlID((FocusType)2); GUI.color = new Color(1f, 0.85f, 0f, 0.9f); GUI.Box(val, GUIContent.none); GUI.color = new Color(1f, 0.85f, 0f, 1f); GUI.DrawTexture(val2, (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; string text = $"X:{Settings.PosX.Value:0} Y:{Settings.PosY.Value:0}" + $" W:{Settings.Width.Value:0} H:{Settings.Height.Value:0}" + $" Z:{Settings.Zoom.Value:0.00}" + " [drag=move] [corner=resize] [wheel=size] [+/-=zoom] [R=reset] [F8=exit]"; Rect val3 = new Rect(x, y - 20f, w + 200f, 18f); GUI.color = new Color(1f, 0.85f, 0f, 1f); GUI.Label(val3, text); GUI.color = Color.white; EventType typeForControl = current.GetTypeForControl(controlID); switch ((int)typeForControl) { case 0: if (current.button == 0) { if (((Rect)(ref val2)).Contains(current.mousePosition)) { GUIUtility.hotControl = controlID; _editResizeActive = true; _editDragActive = false; _editDragOrigin = current.mousePosition; _editStartW = Settings.Width.Value; _editStartH = Settings.Height.Value; current.Use(); } else if (((Rect)(ref val)).Contains(current.mousePosition)) { GUIUtility.hotControl = controlID; _editDragActive = true; _editResizeActive = false; _editDragOrigin = current.mousePosition; _editStartPosX = Settings.PosX.Value; _editStartPosY = Settings.PosY.Value; current.Use(); } } break; case 3: if (GUIUtility.hotControl == controlID) { Vector2 val4 = current.mousePosition - _editDragOrigin; if (_editDragActive) { Settings.PosX.Value = Mathf.Clamp(_editStartPosX + val4.x, 0f, (float)Screen.width - Settings.Width.Value); Settings.PosY.Value = Mathf.Clamp(_editStartPosY - val4.y, 0f, (float)Screen.height - Settings.Height.Value); } else if (_editResizeActive) { Settings.Width.Value = Mathf.Clamp(_editStartW + val4.x, 64f, (float)Screen.width); Settings.Height.Value = Mathf.Clamp(_editStartH + val4.y, 64f, (float)Screen.height); } current.Use(); } break; case 1: if (GUIUtility.hotControl == controlID) { GUIUtility.hotControl = 0; _editDragActive = false; _editResizeActive = false; current.Use(); } break; case 6: if (((Rect)(ref val)).Contains(current.mousePosition)) { float num = (0f - current.delta.y) * 8f; Settings.Width.Value = Mathf.Clamp(Settings.Width.Value + num, 64f, (float)Screen.width); Settings.Height.Value = Mathf.Clamp(Settings.Height.Value + num, 64f, (float)Screen.height); current.Use(); } break; case 4: if ((int)current.keyCode == 43 || (int)current.keyCode == 61 || (int)current.keyCode == 270) { Settings.Zoom.Value = Mathf.Clamp(Settings.Zoom.Value - 0.1f, 0.5f, 10f); current.Use(); } else if ((int)current.keyCode == 45 || (int)current.keyCode == 269) { Settings.Zoom.Value = Mathf.Clamp(Settings.Zoom.Value + 0.1f, 0.5f, 10f); current.Use(); } else if ((int)current.keyCode == 114) { Settings.PosX.Value = 24f; Settings.PosY.Value = 120f; Settings.Width.Value = 260f; Settings.Height.Value = 260f; Settings.Zoom.Value = 2.25f; Settings.Opacity.Value = 0.85f; LogDbg("[SurveyorMap] Edit mode: reset to defaults."); current.Use(); } break; case 2: case 5: break; } } private void OnDestroy() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) EditModeActive = false; _editMode = false; SurveyorMapConfig settings = Settings; if (settings != null && (settings.UnlockCursorInEditMode?.Value).GetValueOrDefault()) { try { Cursor.lockState = _savedCursorLockState; Cursor.visible = _savedCursorVisible; } catch { } } try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } _mirror = null; } } [HarmonyPatch(typeof(CameraAim), "Update")] internal static class CameraAimEditModePatch { [HarmonyPrefix] private static bool Prefix() { if (SurveyorMapPlugin.EditModeActive) { SurveyorMapConfig settings = SurveyorMapPlugin.Settings; if (settings != null && (settings.FreezeCameraInEditMode?.Value).GetValueOrDefault()) { return false; } } return true; } } [HarmonyPatch(typeof(EnemyParent), "SpawnRPC")] internal static class EnemySpawnPatch { [HarmonyPostfix] private static void Postfix(EnemyParent __instance) { if (SurveyorMapPlugin.Settings.ShowEnemies.Value) { EnemyMapMarkerService.AddMarker(__instance); } } } [HarmonyPatch(typeof(EnemyParent), "DespawnRPC")] internal static class EnemyDespawnPatch { [HarmonyPostfix] private static void Postfix(EnemyParent __instance) { EnemyMapMarkerService.RemoveMarker(__instance); } } [HarmonyPatch(typeof(RoomVolume), "SetExplored")] internal static class RoomVolumeExploredPatch { [HarmonyPostfix] private static void Postfix(RoomVolume __instance) { EnemyMapMarkerService.OnRoomExplored(__instance); } } internal static class EnemyDeathHelper { internal static void OnDeathRPC(EnemyHealth __instance) { try { EnemyParent componentInParent = ((Component)__instance).GetComponentInParent<EnemyParent>(true); if ((Object)(object)componentInParent != (Object)null) { EnemyMapMarkerService.RemoveMarker(componentInParent); } } catch { } } } internal enum ThreatTier { Low, Medium, High, Elite } internal enum MarkerShape { Circle, Square, Triangle, Star } internal struct MarkerEntry { public EnemyParent Parent; public Enemy Enemy; public GameObject Host; public MapCustom Mc; public EnemyHealth Health; public ThreatTier Tier; public MarkerShape Shape; } internal static class EnemyMapMarkerService { private static readonly Dictionary<int, MarkerEntry> _registry = new Dictionary<int, MarkerEntry>(); private static readonly Sprite[] _sprites = (Sprite[])(object)new Sprite[4]; private static readonly HashSet<int> _exploredRoomIds = new HashSet<int>(); private static bool _anyRoomExplored; private static int _exploredLevelRoomCount; private static readonly Color[] _colors = (Color[])(object)new Color[4] { new Color(0.875f, 1f, 0.91f, 1f), new Color(0.118f, 0.42f, 1f, 1f), new Color(0.753f, 0.518f, 0.988f, 1f), new Color(1f, 0.231f, 0.188f, 1f) }; private static readonly string[] _colorHex = new string[4] { "#DFFFE8", "#1E6BFF", "#C084FC", "#FF3B30" }; private static bool _reflected; private static FieldInfo _enemyField; private static PropertyInfo _enemyProp; private static FieldInfo _rbField; private static FieldInfo _hasRbField; private static FieldInfo _mceField; private static FieldInfo _diffField; private static FieldInfo _spawnedField; private static FieldInfo _deadField; private static FieldInfo _hpField; private static FieldInfo _autoAddField; private static FieldInfo _currentStateField; private static PropertyInfo _currentStateProp; private static FieldInfo _enemyTypeField; private static PropertyInfo _enemyTypeProp; private static FieldInfo _enemyNameField; private static PropertyInfo _enemyNameProp; public static int ActiveMarkerCount => _registry.Count; private static void EnsureReflection() { if (!_reflected) { _reflected = true; BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; Type typeFromHandle = typeof(EnemyParent); _enemyField = typeFromHandle.GetField("Enemy", bindingAttr); if (_enemyField == null) { _enemyProp = typeFromHandle.GetProperty("Enemy", bindingAttr); } _diffField = typeFromHandle.GetField("difficulty", bindingAttr) ?? typeFromHandle.GetField("Difficulty", bindingAttr); _spawnedField = typeFromHandle.GetField("Spawned", bindingAttr) ?? typeFromHandle.GetField("spawned", bindingAttr); _enemyNameField = typeFromHandle.GetField("enemyName", bindingAttr) ?? typeFromHandle.GetField("EnemyName", bindingAttr); if (_enemyNameField == null) { _enemyNameProp = typeFromHandle.GetProperty("enemyName", bindingAttr) ?? typeFromHandle.GetProperty("EnemyName", bindingAttr); } Type typeFromHandle2 = typeof(Enemy); _rbField = typeFromHandle2.GetField("Rigidbody", bindingAttr); _hasRbField = typeFromHandle2.GetField("HasRigidbody", bindingAttr); _currentStateField = typeFromHandle2.GetField("CurrentState", bindingAttr) ?? typeFromHandle2.GetField("currentState", bindingAttr); if (_currentStateField == null) { _currentStateProp = typeFromHandle2.GetProperty("CurrentState", bindingAttr) ?? typeFromHandle2.GetProperty("currentState", bindingAttr); } _enemyTypeField = typeFromHandle2.GetField("Type", bindingAttr) ?? typeFromHandle2.GetField("type", bindingAttr) ?? typeFromHandle2.GetField("EnemyType", bindingAttr); if (_enemyTypeField == null) { _enemyTypeProp = typeFromHandle2.GetProperty("Type", bindingAttr) ?? typeFromHandle2.GetProperty("EnemyType", bindingAttr); } _mceField = typeof(MapCustom).GetField("mapCustomEntity", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _autoAddField = typeof(MapCustom).GetField("autoAdd", bindingAttr) ?? typeof(MapCustom).GetField("AutoAdd", bindingAttr); Type typeFromHandle3 = typeof(EnemyHealth); _deadField = typeFromHandle3.GetField("dead", bindingAttr) ?? typeFromHandle3.GetField("Dead", bindingAttr); _hpField = typeFromHandle3.GetField("healthCurrent", bindingAttr) ?? typeFromHandle3.GetField("HealthCurrent", bindingAttr) ?? typeFromHandle3.GetField("HP", bindingAttr) ?? typeFromHandle3.GetField("hp", bindingAttr); } } private static Enemy GetEnemy(EnemyParent parent) { try { if (_enemyField != null) { object? value = _enemyField.GetValue(parent); return (Enemy)((value is Enemy) ? value : null); } if (_enemyProp != null) { object? value2 = _enemyProp.GetValue(parent); return (Enemy)((value2 is Enemy) ? value2 : null); } } catch { } return null; } private static string CollectNames(EnemyParent parent, Enemy enemy) { string text = ""; try { if (_enemyTypeField != null || _enemyTypeProp != null) { object obj = ((_enemyTypeField != null) ? _enemyTypeField.GetValue(enemy) : _enemyTypeProp.GetValue(enemy)); if (obj != null) { text = text + " " + obj.ToString(); } } if (_enemyNameField != null || _enemyNameProp != null) { object obj2 = ((_enemyNameField != null) ? _enemyNameField.GetValue(parent) : _enemyNameProp.GetValue(parent)); if (obj2 != null) { text = text + " " + obj2.ToString(); } } if ((Object)(object)enemy != (Object)null) { string name = ((object)enemy).GetType().Name; if (!string.IsNullOrEmpty(name) && name != "Enemy") { text = text + " " + name; } } if ((Object)(object)enemy != (Object)null && (Object)(object)((Component)enemy).gameObject != (Object)null) { string name2 = ((Object)((Component)enemy).gameObject).name; if (!string.IsNullOrEmpty(name2) && !string.Equals(name2, "Controller", StringComparison.OrdinalIgnoreCase)) { text = text + " " + name2; } } if ((Object)(object)parent != (Object)null && (Object)(object)((Component)parent).gameObject != (Object)null) { text = text + " " + ((Object)((Component)parent).gameObject).name; } } catch { } return text.ToLower(); } private static ThreatTier GetThreatTier(EnemyParent parent, string names, out ThreatTier baseTier, out string elevatedBy) { baseTier = ThreatTier.Elite; elevatedBy = "none"; try { if (_diffField != null) { object value = _diffField.GetValue(parent); if (value != null) { baseTier = Convert.ToInt32(value) switch { 3 => ThreatTier.High, 2 => ThreatTier.Medium, 1 => ThreatTier.Low, _ => ThreatTier.Elite, }; } } } catch { } ThreatTier threatTier = baseTier; if (names.Contains("veryheavy") && threatTier < ThreatTier.High) { threatTier = ThreatTier.High; elevatedBy = "veryheavy"; } if (threatTier < ThreatTier.Elite && ContainsAny(names, "trudge", "slow walker", "boss", "elite", "apex", "king", "titan", "giant", "mega", "master")) { threatTier = ThreatTier.Elite; elevatedBy = FirstMatch(names, "trudge", "slow walker", "boss", "elite", "apex", "king", "titan", "giant", "mega", "master"); } if (threatTier < ThreatTier.High && ContainsAny(names, "hunt", "huntsman", "hunter", "bang", "rush", "charge", "attack", "screamer", "smasher", "bowtie", "robe")) { threatTier = ThreatTier.High; if (elevatedBy == "none") { elevatedBy = FirstMatch(names, "hunt", "huntsman", "hunter", "bang", "rush", "charge", "attack", "screamer", "smasher", "bowtie", "robe"); } } return threatTier; } private static MarkerShape TierToShape(ThreatTier tier) { return tier switch { ThreatTier.Low => MarkerShape.Circle, ThreatTier.Medium => MarkerShape.Square, ThreatTier.High => MarkerShape.Triangle, ThreatTier.Elite => MarkerShape.Star, _ => MarkerShape.Circle, }; } private static bool ContainsAny(string haystack, params string[] needles) { foreach (string value in needles) { if (haystack.Contains(value)) { return true; } } return false; } private static string FirstMatch(string haystack, params string[] needles) { foreach (string text in needles) { if (haystack.Contains(text)) { return text; } } return "?"; } private static Sprite GetOrCreateSprite(MarkerShape shape) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_004e: 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) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_026c: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_sprites[(int)shape] != (Object)null && Object.op_Implicit((Object)(object)_sprites[(int)shape])) { return _sprites[(int)shape]; } Texture2D val = new Texture2D(16, 16, (TextureFormat)4, false); ((Object)val).hideFlags = (HideFlags)61; Color[] array = (Color[])(object)new Color[256]; for (int i = 0; i < 256; i++) { array[i] = Color.clear; } switch (shape) { case MarkerShape.Circle: { for (int num5 = 0; num5 < 16; num5++) { for (int num6 = 0; num6 < 16; num6++) { if (Vector2.Distance(new Vector2((float)num6, (float)num5), new Vector2(7.5f, 7.5f)) <= 6.5f) { array[num5 * 16 + num6] = Color.white; } } } break; } case MarkerShape.Square: { for (int num7 = 2; num7 <= 13; num7++) { for (int num8 = 2; num8 <= 13; num8++) { array[num7 * 16 + num8] = Color.white; } } break; } case MarkerShape.Triangle: { for (int n = 2; n <= 14; n++) { float num3 = ((float)n - 2f) / 12f * 6.5f; for (int num4 = 0; num4 < 16; num4++) { if (Mathf.Abs((float)num4 - 7.5f) <= num3) { array[n * 16 + num4] = Color.white; } } } break; } case MarkerShape.Star: { for (int j = 2; j <= 12; j++) { float num = ((float)j - 2f) / 10f * 5.5f; for (int k = 0; k < 16; k++) { if (Mathf.Abs((float)k - 7.5f) <= num) { array[j * 16 + k] = Color.white; } } } for (int l = 4; l <= 14; l++) { float num2 = (14f - (float)l) / 10f * 5.5f; for (int m = 0; m < 16; m++) { if (Mathf.Abs((float)m - 7.5f) <= num2) { array[l * 16 + m] = Color.white; } } } break; } } val.SetPixels(array); val.Apply(); Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, 16f, 16f), new Vector2(0.5f, 0.5f)); ((Object)val2).hideFlags = (HideFlags)61; _sprites[(int)shape] = val2; return val2; } private static void ApplyScale(MapCustom mc) { //IL_0067: 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) try { if (!((Object)(object)mc == (Object)null) && !(_mceField == null)) { object? value = _mceField.GetValue(mc); MapCustomEntity val = (MapCustomEntity)((value is MapCustomEntity) ? value : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { float num = Mathf.Clamp(SurveyorMapPlugin.Settings.EnemyMarkerSize.Value, 0.3f, 2f); ((Component)val).transform.localScale = Vector3.one * num; } } } catch { } } private static bool IsAddAllowed(EnemyParent parent, Enemy enemy) { try { if ((Object)(object)parent == (Object)null || (Object)(object)enemy == (Object)null) { return false; } if (!((Component)parent).gameObject.activeInHierarchy) { return false; } if (!((Component)enemy).gameObject.activeInHierarchy) { return false; } if (_spawnedField != null) { object value = _spawnedField.GetValue(parent); if (value is bool && !(bool)value) { SurveyorMapPlugin.LogDbg("[SurveyorMap] AddMarker skipped: Spawned=false"); return false; } } if (_currentStateField != null || _currentStateProp != null) { object obj = ((_currentStateField != null) ? _currentStateField.GetValue(enemy) : _currentStateProp.GetValue(enemy)); if (obj != null && obj.ToString() == "Despawn") { SurveyorMapPlugin.LogDbg("[SurveyorMap] AddMarker skipped: CurrentState=Despawn"); return false; } } EnemyHealth componentInChildren = ((Component)enemy).GetComponentInChildren<EnemyHealth>(true); if ((Object)(object)componentInChildren != (Object)null) { if (_deadField != null) { object value2 = _deadField.GetValue(componentInChildren); bool flag = default(bool); int num; if (value2 is bool) { flag = (bool)value2; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0) { SurveyorMapPlugin.LogDbg("[SurveyorMap] AddMarker skipped: dead=true"); return false; } } if (_hpField != null) { object value3 = _hpField.GetValue(componentInChildren); if (value3 != null && Convert.ToSingle(value3) <= 0f) { SurveyorMapPlugin.LogDbg("[SurveyorMap] AddMarker skipped: healthCurrent<=0"); return false; } } } } catch { return true; } return true; } private static bool IsEnemyRoomExplored(Enemy enemy) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)enemy == (Object)null || !Object.op_Implicit((Object)(object)((Component)enemy).gameObject)) { return true; } if (!_anyRoomExplored || _exploredLevelRoomCount == 0) { return true; } try { Collider[] array = Physics.OverlapSphere(((Component)enemy).transform.position, 2f, -1, (QueryTriggerInteraction)2); for (int i = 0; i < array.Length; i++) { RoomVolume component = ((Component)array[i]).GetComponent<RoomVolume>(); if (!((Object)(object)component == (Object)null)) { return _exploredRoomIds.Contains(((Object)component).GetInstanceID()); } } } catch { } return true; } public static void OnRoomExplored(RoomVolume room) { if ((Object)(object)room == (Object)null) { return; } bool num = _exploredRoomIds.Add(((Object)room).GetInstanceID()); if (!_anyRoomExplored) { _anyRoomExplored = true; } if (num) { bool flag = ((Object)((Component)room).gameObject).name.IndexOf("Truck", StringComparison.OrdinalIgnoreCase) >= 0; if (!flag) { _exploredLevelRoomCount++; } SurveyorMapPlugin.LogDbg("[SurveyorMap] Room explored (new): " + ((Object)((Component)room).gameObject).name + $" isTruck={flag} levelRooms={_exploredLevelRoomCount} total={_exploredRoomIds.Count}"); } } private static void SetMarkerEntityActive(MapCustom mc, bool active) { try { if (!((Object)(object)mc == (Object)null) && !(_mceField == null)) { object? value = _mceField.GetValue(mc); MapCustomEntity val = (MapCustomEntity)((value is MapCustomEntity) ? value : null); if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)null) { ((Component)val).gameObject.SetActive(active); } } } catch { } } public static void AddMarker(EnemyParent parent) { //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0120: 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_013d: Unknown result type (might be due to invalid IL or missing references) try { EnsureReflection(); int instanceID = ((Object)parent).GetInstanceID(); if (_registry.ContainsKey(instanceID)) { return; } Enemy enemy = GetEnemy(parent); if ((Object)(object)enemy == (Object)null || !Object.op_Implicit((Object)(object)((Component)enemy).gameObject) || !IsAddAllowed(parent, enemy)) { return; } GameObject gameObject = ((Component)enemy).gameObject; try { if (_hasRbField != null && _rbField != null && (bool)_hasRbField.GetValue(enemy)) { object? value = _rbField.GetValue(enemy); Rigidbody val = (Rigidbody)((value is Rigidbody) ? value : null); if ((Object)(object)val != (Object)null) { gameObject = ((Component)val).gameObject; } } } catch { } string text = CollectNames(parent, enemy); ThreatTier baseTier; string elevatedBy; ThreatTier threatTier = GetThreatTier(parent, text, out baseTier, out elevatedBy); MarkerShape markerShape = TierToShape(threatTier); Color val2 = _colors[(int)threatTier]; Sprite orCreateSprite = GetOrCreateSprite(markerShape); MapCustom val3 = gameObject.GetComponent<MapCustom>() ?? gameObject.AddComponent<MapCustom>(); if (_autoAddField != null) { try { _autoAddField.SetValue(val3, false); } catch { } } val3.sprite = orCreateSprite; val3.color = val2; try { if ((Object)(object)Map.Instance != (Object)null) { Map.Instance.AddCustom(val3, orCreateSprite, val2); SurveyorMapPlugin.LogDbg("[SurveyorMap] Map.AddCustom OK: host=" + ((Object)gameObject).name); } else { SurveyorMapPlugin.Log.LogWarning((object)"[SurveyorMap] Map.AddCustom skipped: Map.Instance is null"); } } catch (Exception ex) { SurveyorMapPlugin.Log.LogWarning((object)("[SurveyorMap] Map.AddCustom FAILED: " + ex.Message)); } ApplyScale(val3); if (_mceField != null && _mceField.GetValue(val3) == null) { SurveyorMapPlugin.Log.LogWarning((object)("[SurveyorMap] mapCustomEntity null after AddCustom — marker may be invisible. host=" + ((Object)gameObject).name)); } EnemyHealth health = ((Component)enemy).GetComponentInChildren<EnemyHealth>(true) ?? gameObject.GetComponentInChildren<EnemyHealth>(true); _registry[instanceID] = new MarkerEntry { Parent = parent, Enemy = enemy, Host = gameObject, Mc = val3, Health = health, Tier = threatTier, Shape = markerShape }; SurveyorMapPlugin.LogDbg($"[SurveyorMap] Enemy marker: id={instanceID}" + $" diff={baseTier} threat={threatTier} shape={markerShape}" + " color=" + _colorHex[(int)threatTier] + $" elevated={elevatedBy} names=[{text.Trim()}] total={_registry.Count}"); } catch (Exception ex2) { SurveyorMapPlugin.Log.LogWarning((object)("[SurveyorMap] AddMarker failed: " + ex2.Message)); } } public static void RemoveMarker(EnemyParent parent) { int instanceID = ((Object)parent).GetInstanceID(); if (_registry.TryGetValue(instanceID, out var value)) { CleanupEntry(instanceID, value); } } public static void SweepDeadMarkers() { if (_registry.Count == 0) { return; } List<int> list = new List<int>(); foreach (KeyValuePair<int, MarkerEntry> item in _registry) { if (IsEntryStale(item.Value)) { list.Add(item.Key); } } foreach (int item2 in list) { if (_registry.TryGetValue(item2, out var value)) { CleanupEntry(item2, value); } } if (list.Count > 0) { SurveyorMapPlugin.LogDbg($"[SurveyorMap] Sweep removed {list.Count} stale markers. Active={_registry.Count}"); } foreach (KeyValuePair<int, MarkerEntry> item3 in _registry) { SetMarkerEntityActive(item3.Value.Mc, active: true); ApplyScale(item3.Value.Mc); } SurveyorMapPlugin.LogDbg($"[SurveyorMap] Sweep: active={_registry.Count}"); } public static void ClearAll() { foreach (int item in new List<int>(_registry.Keys)) { if (_registry.TryGetValue(item, out var value)) { CleanupEntry(item, value); } } _exploredRoomIds.Clear(); _anyRoomExplored = false; _exploredLevelRoomCount = 0; } private static bool IsEntryStale(MarkerEntry e) { try { if ((Object)(object)e.Parent == (Object)null) { return true; } if ((Object)(object)e.Enemy == (Object)null) { return true; } if ((Object)(object)e.Host == (Object)null) { return true; } if (!e.Host.activeInHierarchy) { return true; } if ((Object)(object)e.Mc == (Object)null) { return true; } if (_spawnedField != null) { object value = _spawnedField.GetValue(e.Parent); if (value is bool && !(bool)value) { return true; } } if (_currentStateField != null || _currentStateProp != null) { try { object obj = ((_currentStateField != null) ? _currentStateField.GetValue(e.Enemy) : _currentStateProp.GetValue(e.Enemy)); if (obj != null && obj.ToString() == "Despawn") { return true; } } catch { } } EnemyHealth health = e.Health; if ((Object)(object)health != (Object)null) { if (_deadField != null) { object value2 = _deadField.GetValue(health); bool flag = default(bool); int num; if (value2 is bool) { flag = (bool)value2; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0) { return true; } } if (_hpField != null) { object value3 = _hpField.GetValue(health); if (value3 != null && Convert.ToSingle(value3) <= 0f) { return true; } } } } catch { return true; } return false; } private static void CleanupEntry(int id, MarkerEntry e) { try { if ((Object)(object)e.Mc != (Object)null) { if (_mceField != null) { object? value = _mceField.GetValue(e.Mc); MapCustomEntity val = (MapCustomEntity)((value is MapCustomEntity) ? value : null); if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } Object.Destroy((Object)(object)e.Mc); } } catch { } _registry.Remove(id); } } public class NativeMapMirror { private const string MapCameraName = "Dirt Finder Map Camera"; private Camera _mapCamera; private float _nextCameraSearch; private float _nextNullTexLog; private float _capturedDefaultSize = -1f; private bool _zoomApplied; private static bool _tabReflected; private static FieldInfo _tabInstField; private static PropertyInfo _tabInstProp; private static FieldInfo _tabActiveField; private static PropertyInfo _tabActiveProp; private bool _lastTabActive; public bool IsGameplayActive { get; private set; } public bool IsNativeTabActive { get; private set; } public Texture NativeTexture { get; private set; } public int TabOpenCount { get; private set; } public int TabCloseCount { get; private set; } public void Update(bool hudActive) { IsGameplayActive = CheckGameplay(); IsNativeTabActive = CheckTabActive(); if (IsNativeTabActive != _lastTabActive) { _lastTabActive = IsNativeTabActive; if (IsNativeTabActive) { TabOpenCount++; SurveyorMapPlugin.LogDbg($"[SurveyorMap] nativeMapTabOpen=True tabOpenCount={TabOpenCount}"); } else { TabCloseCount++; SurveyorMapPlugin.LogDbg($"[SurveyorMap] nativeMapTabOpen=False tabCloseCount={TabCloseCount}"); } SurveyorMapDiagnostics.TabOpenCount = TabOpenCount; SurveyorMapDiagnostics.TabCloseCount = TabCloseCount; } if (!IsGameplayActive) { NativeTexture = null; return; } if (hudActive && (Object)(object)Map.Instance != (Object)null && !Map.Instance.Active) { Map.Instance.ActiveSet(true); } RefreshCamera(); if ((Object)(object)_mapCamera == (Object)null) { NativeTexture = null; return; } if (hudActive && !IsNativeTabActive) { float value = SurveyorMapPlugin.Settings.Zoom.Value; if (_mapCamera.orthographic) { if (_capturedDefaultSize < 0f) { _capturedDefaultSize = _mapCamera.orthographicSize; } if (Mathf.Abs(_mapCamera.orthographicSize - value) > 0.01f) { _mapCamera.orthographicSize = value; } _zoomApplied = true; } } else if (_zoomApplied && _capturedDefaultSize > 0f && _mapCamera.orthographic) { _mapCamera.orthographicSize = _capturedDefaultSize; _zoomApplied = false; } RenderTexture activeTexture = _mapCamera.activeTexture; if ((Object)(object)activeTexture == (Object)null) { if (Time.unscaledTime >= _nextNullTexLog) { _nextNullTexLog = Time.unscaledTime + 5f; SurveyorMapPlugin.LogDbg("[SurveyorMap] Map camera activeTexture null — waiting for native render."); } NativeTexture = null; } else { NativeTexture = (Texture)(object)activeTexture; SurveyorMapDiagnostics.NativeTextureReady = true; } } private static bool CheckGameplay() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) try { if (!SemiFunc.RunIsLevel()) { return false; } if ((Object)(object)GameDirector.instance == (Object)null) { return false; } if (Convert.ToInt32(GameDirector.instance.currentState) != 2) { return false; } return true; } catch { return false; } } private static void EnsureTabReflection() { if (!_tabReflected) { _tabReflected = true; Type typeFromHandle = typeof(MapToolController); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; _tabInstField = typeFromHandle.GetField("instance", bindingAttr); _tabInstProp = typeFromHandle.GetProperty("instance", bindingAttr); _tabActiveField = typeFromHandle.GetField("Active", bindingAttr); _tabActiveProp = typeFromHandle.GetProperty("Active", bindingAttr); } } private static bool CheckTabActive() { try { EnsureTabReflection(); object obj = null; if (_tabInstField != null) { obj = _tabInstField.GetValue(null); } if (obj == null && _tabInstProp != null) { obj = _tabInstProp.GetValue(null); } if (obj == null) { return false; } object obj2 = null; if (_tabActiveField != null) { obj2 = _tabActiveField.GetValue(obj); } if (obj2 == null && _tabActiveProp != null) { obj2 = _tabActiveProp.GetValue(obj); } bool flag = default(bool); int num; if (obj2 is bool) { flag = (bool)obj2; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch { return false; } } private void RefreshCamera() { if ((Object)(object)_mapCamera != (Object)null && (Object)(object)((Component)_mapCamera).gameObject != (Object)null) { return; } _mapCamera = null; if (Time.unscaledTime < _nextCameraSearch) { return; } _nextCameraSearch = Time.unscaledTime + 2f; Camera[] array = Resources.FindObjectsOfTypeAll<Camera>(); foreach (Camera val in array) { if ((Object)(object)val != (Object)null && ((Object)val).name == "Dirt Finder Map Camera") { _mapCamera = val; _capturedDefaultSize = -1f; SurveyorMapPlugin.LogDbg($"[SurveyorMap] Map camera found: {((Object)val).name} orthoSize={val.orthographicSize}"); break; } } } } [HarmonyPatch(typeof(LevelGenerator), "GenerateDone")] internal static class RevealRoomsPatch { [HarmonyPostfix] private static void Postfix() { EnemyMapMarkerService.ClearAll(); if (string.Equals(SurveyorMapPlugin.Settings.RevealRoomsMode.Value, "NativeGlobal", StringComparison.OrdinalIgnoreCase)) { ((MonoBehaviour)SurveyorMapPlugin.Instance).StartCoroutine(RevealDelayed()); } } private static IEnumerator RevealDelayed() { yield return (object)new WaitForSeconds(0.5f); ApplyRevealRooms(); } private static void ApplyRevealRooms() { try { RoomVolume[] array = Object.FindObjectsOfType<RoomVolume>(); int num = array.Length; int num2 = 0; int num3 = 0; RoomVolume[] array2 = array; foreach (RoomVolume val in array2) { if ((Object)(object)val == (Object)null) { num3++; continue; } try { if (val.SetExplored()) { num2++; } } catch (Exception ex) { num3++; SurveyorMapPlugin.Log.LogWarning((object)("[SurveyorMap] SetExplored failed: " + ex.Message)); } } SurveyorMapDiagnostics.RevealRoomsTotal = num; SurveyorMapDiagnostics.RevealRoomsExplored = num2; SurveyorMapPlugin.Log.LogInfo((object)$"[SurveyorMap] RevealRooms NativeGlobal: explored={num2}/{num} skipped={num3}"); } catch (Exception arg) { SurveyorMapPlugin.Log.LogError((object)$"[SurveyorMap] RevealRooms exception: {arg}"); } } } public class SurveyorMapConfig { public readonly ConfigEntry<bool> EnableMinimap; public readonly ConfigEntry<KeyCode> ToggleKey; public readonly ConfigEntry<float> Width; public readonly ConfigEntry<float> Height; public readonly ConfigEntry<float> PosX; public readonly ConfigEntry<float> PosY; public readonly ConfigEntry<float> Opacity; public readonly ConfigEntry<float> Zoom; public readonly ConfigEntry<string> RevealRoomsMode; public readonly ConfigEntry<bool> ShowEnemies; public readonly ConfigEntry<float> EnemyMarkerSize; public readonly ConfigEntry<bool> EditModeEnabled; public readonly ConfigEntry<KeyCode> EditModeKey; public readonly ConfigEntry<bool> UnlockCursorInEditMode; public readonly ConfigEntry<bool> FreezeCameraInEditMode; public readonly ConfigEntry<bool> EnableZoomHotkeysOutsideEdit; public readonly ConfigEntry<bool> DebugLogging; public SurveyorMapConfig(ConfigFile cfg) { EnableMinimap = cfg.Bind<bool>("Minimap", "EnableMinimap", true, "Show persistent minimap HUD during gameplay."); ToggleKey = cfg.Bind<KeyCode>("Minimap", "ToggleKey", (KeyCode)109, "Key to toggle the minimap HUD on/off."); Width = cfg.Bind<float>("Minimap", "Width", 260f, "Minimap width in pixels."); Height = cfg.Bind<float>("Minimap", "Height", 260f, "Minimap height in pixels."); PosX = cfg.Bind<float>("Minimap", "PosX", 24f, "Minimap X offset from the left edge of the screen."); PosY = cfg.Bind<float>("Minimap", "PosY", 120f, "Minimap Y offset from the bottom edge of the screen."); Opacity = cfg.Bind<float>("Minimap", "Opacity", 0.85f, "Minimap opacity (0 = invisible, 1 = fully opaque)."); Zoom = cfg.Bind<float>("Minimap", "Zoom", 2.25f, "Orthographic size of the native map camera while minimap is visible."); RevealRoomsMode = cfg.Bind<string>("Features", "RevealRoomsMode", "Vanilla", "Vanilla = default, no SetExplored calls, TAB stays original. NativeGlobal = reveals rooms via RoomVolume.SetExplored() — also affects the native TAB map."); ShowEnemies = cfg.Bind<bool>("Features", "ShowEnemies", true, "Show enemy positions on the map using native MapCustom markers."); EnemyMarkerSize = cfg.Bind<float>("Features", "EnemyMarkerSize", 0.95f, "Scale multiplier for enemy markers (0.30–2.00). Default 0.95. Changes apply within ~2s without restart."); EditModeEnabled = cfg.Bind<bool>("EditMode", "EditModeEnabled", true, "Enable the in-game minimap edit mode (F8 by default)."); EditModeKey = cfg.Bind<KeyCode>("EditMode", "EditModeKey", (KeyCode)289, "Key to enter/exit minimap edit mode. In edit mode: drag to move, resize from corner, scroll to zoom."); UnlockCursorInEditMode = cfg.Bind<bool>("EditMode", "UnlockCursorInEditMode", true, "When true, the cursor is unlocked and made visible automatically when F8 edit mode is active, so you can drag and resize the minimap without pressing ESC first. The cursor state is restored when you exit edit mode. If the game still captures the cursor, press ESC once to release it manually."); FreezeCameraInEditMode = cfg.Bind<bool>("EditMode", "FreezeCameraInEditMode", true, "When true, mouse-look is suspended while F8 edit mode is active. Calls InputManager.DisableAiming() every frame so the camera ignores mouse delta. Camera control is restored automatically when you exit edit mode."); EnableZoomHotkeysOutsideEdit = cfg.Bind<bool>("EditMode", "EnableZoomHotkeysOutsideEdit", true, "When true, + and - keys (main keyboard and numpad) adjust the minimap zoom level during normal gameplay without entering F8 edit mode. Only active when the minimap is visible, edit mode is off, and the TAB map is not open."); DebugLogging = cfg.Bind<bool>("Debug", "DebugLogging", false, "Enable verbose debug logging to BepInEx/LogOutput.log. Default false (silent in release). Set true only for diagnostics: exposes sweep, AddCustom, enemy classification, and room-exploration logs."); } } internal static class SurveyorMapDiagnostics { public static string AssemblyPath = ""; public static string BuildTimestamp = ""; public static string BuildMd5Short = ""; public static string DiagnosticsDir = ""; public static bool NativeTextureReady = false; public static bool HudVisible = true; public static bool TabActive = false; public static bool GameplayActive = false; public static int TabOpenCount = 0; public static int TabCloseCount = 0; public static int ToggleKeyDetectedCount = 0; public static int UpdateCount = 0; public static int OnGuiCount = 0; public static int RevealRoomsTotal = 0; public static int RevealRoomsExplored = 0; public static int EnemyMarkerCount = 0; public static string RevealRoomsMode = "Off"; public static string LastException = ""; public static void WriteDiagJson() { try { if (!string.IsNullOrEmpty(DiagnosticsDir)) { Directory.CreateDirectory(DiagnosticsDir); string path = Path.Combine(DiagnosticsDir, "surveyormap-runtime-state.json"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("{"); stringBuilder.AppendLine(" \"assemblyPath\": " + J(AssemblyPath) + ","); stringBuilder.AppendLine(" \"buildTimestamp\": " + J(BuildTimestamp) + ","); stringBuilder.AppendLine(" \"buildMd5Short\": " + J(BuildMd5Short) + ","); stringBuilder.AppendLine(" \"buildTag\": " + J(BuildMd5Short) + ","); stringBuilder.AppendLine(" \"hudVisible\": " + B(HudVisible) + ","); stringBuilder.AppendLine(" \"nativeTextureReady\": " + B(NativeTextureReady) + ","); stringBuilder.AppendLine(" \"tabActive\": " + B(TabActive) + ","); stringBuilder.AppendLine(" \"nativeTabOpen\": " + B(TabActive) + ","); stringBuilder.AppendLine(" \"gameplayActive\": " + B(GameplayActive) + ","); stringBuilder.AppendLine(" \"isLevel\": " + B(GameplayActive) + ","); stringBuilder.AppendLine(" \"currentRunState\": " + J(GameplayActive ? "Level" : "None") + ","); stringBuilder.AppendLine($" \"tabOpenCount\": {TabOpenCount},"); stringBuilder.AppendLine($" \"tabCloseCount\": {TabCloseCount},"); stringBuilder.AppendLine($" \"toggleKeyDetectedCount\": {ToggleKeyDetectedCount},"); stringBuilder.AppendLine(" \"revealRoomsMode\": " + J(RevealRoomsMode) + ","); stringBuilder.AppendLine($" \"revealRoomsTotal\": {RevealRoomsTotal},"); stringBuilder.AppendLine($" \"revealRoomsExplored\": {RevealRoomsExplored},"); stringBuilder.AppendLine($" \"enemyMarkerCount\": {EnemyMarkerCount},"); stringBuilder.AppendLine($" \"pluginUpdateCount\": {UpdateCount},"); stringBuilder.AppendLine($" \"pluginOnGuiCount\": {OnGuiCount},"); stringBuilder.AppendLine(" \"pluginAwakeCalled\": true,"); stringBuilder.AppendLine(" \"runtimeProbeCreated\": " + B(UpdateCount > 0) + ","); stringBuilder.AppendLine($" \"runtimeProbeUpdateCount\": {UpdateCount},"); stringBuilder.AppendLine($" \"runtimeProbeOnGuiCount\": {OnGuiCount},"); stringBuilder.AppendLine(" \"forceHudProofOfLife\": false,"); stringBuilder.AppendLine(" \"centerOnPlayer\": false,"); stringBuilder.AppendLine(" \"centerOnPlayerApplied\": false,"); stringBuilder.AppendLine(" \"capturePaused\": " + B(TabActive) + ","); stringBuilder.AppendLine(" \"lastException\": " + J(LastException) + ","); stringBuilder.AppendLine(" \"lastErrorStack\": \"\","); stringBuilder.AppendLine(" \"writeTimeUtc\": " + J(DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"))); stringBuilder.Append("}"); File.WriteAllText(path, stringBuilder.ToString(), Encoding.UTF8); } } catch { } } private static string J(string s) { return "\"" + (s ?? "").Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""; } private static string B(bool v) { if (!v) { return "false"; } return "true"; } } }