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 TotemSentinel v1.5.2
TotemSentinel.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using TotemSentinel.Commands; using TotemSentinel.HUD; using TotemSentinel.Services; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("TotemSentinel")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.5.2.0")] [assembly: AssemblyInformationalVersion("1.5.2+2eadce900868234131b66f155718dc12e5871f67")] [assembly: AssemblyProduct("TotemSentinel")] [assembly: AssemblyTitle("TotemSentinel")] [assembly: AssemblyVersion("1.5.2.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 TotemSentinel { [BepInPlugin("djcdevelopment.totemsentinel", "TotemSentinel", "1.5.2")] public sealed class TotemSentinelPlugin : BaseUnityPlugin { public const string PluginGuid = "djcdevelopment.totemsentinel"; public const string PluginName = "TotemSentinel"; public const string PluginVersion = "1.5.2"; private const float ScanPulseInterval = 1f; public static ConfigEntry<int> MaxSonarCharges; public static ConfigEntry<int> MaxStoredSonarCharges; public static ConfigEntry<float> ScanRadius; public static ConfigEntry<KeyCode> PingHotkey; public static ConfigEntry<float> StateDuration; public static ConfigEntry<float> FinalSummaryDuration; public static ConfigEntry<float> GreedMultiplier; public static ConfigEntry<float> GreedDuration; public static ConfigEntry<KeyCode> GreedModifierKey; public static int ActiveSonarCharges = 0; public static Vector3 LastScanOrigin = Vector3.zero; private static bool _hasActiveSonarSession; private static bool _showAbilityPreview; private static bool _scanInProgress; private static float _scanStartedAt; private static float _nextScanPulseAt; private static long _scanCpuTicks; private static int _scanPulseCount; private static long _sessionWorldUid; private static bool _deathSuspended; private static bool _isGreedScan; private static float _greedUntil; private Harmony _harmony; private bool _patchesApplied; internal static bool HasActiveSonarSession => _hasActiveSonarSession; internal static bool IsGreedActive => Time.unscaledTime < _greedUntil; internal static int MaximumStoredSonarCharges { get { if (MaxStoredSonarCharges == null) { return 9; } return Math.Max(1, MaxStoredSonarCharges.Value); } } private void Awake() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Expected O, but got Unknown //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Expected O, but got Unknown MaxSonarCharges = ((BaseUnityPlugin)this).Config.Bind<int>("Sonar", "MaxSonarCharges", 3, new ConfigDescription("Number of camp checks granted by each Fuling Totem. Checks are spent only when the hotkey is pressed.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, int.MaxValue), Array.Empty<object>())); MaxStoredSonarCharges = ((BaseUnityPlugin)this).Config.Bind<int>("Sonar", "MaxStoredSonarCharges", 9, new ConfigDescription("Maximum number of camp checks that can be banked across multiple newly discovered Fuling Totems.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, int.MaxValue), Array.Empty<object>())); ScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Sonar", "ScanRadius", 64f, new ConfigDescription("Radius in metres around the picked-up Fuling Totem that is scanned for Fulings.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 128f), Array.Empty<object>())); PingHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "PingHotkey", (KeyCode)118, "Key used to spend another sonar charge while within range of the totem origin."); StateDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Interface", "StateDuration", 10f, new ConfigDescription("Seconds that scanning, result, and warning states remain visible.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>())); FinalSummaryDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Interface", "FinalSummaryDuration", 300f, new ConfigDescription("Seconds after the final scan before the completed camp-check card closes automatically.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 1800f), Array.Empty<object>())); GreedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Greed", "GreedMultiplier", 3f, new ConfigDescription("Multiplier applied to scan radius during Greed's Gambit wide loot searches.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1.5f, 5f), Array.Empty<object>())); GreedDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Greed", "GreedDuration", 35f, new ConfigDescription("Seconds that the Greed's Gambit cursed retribution window lasts after a wide search.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 120f), Array.Empty<object>())); GreedModifierKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "GreedModifierKey", (KeyCode)304, "Modifier key held while pressing PingHotkey to trigger Greed's Gambit wide loot search."); if (!SonarScanner.Initialize()) { ZLog.LogError((object)"[TotemSentinel] Failed to initialize ZDO sector access; gameplay patches were not installed."); return; } try { _harmony = new Harmony("djcdevelopment.totemsentinel"); _harmony.PatchAll(typeof(TotemSentinelPlugin).Assembly); TotemAlertCommands.Register(); _patchesApplied = true; ZLog.Log((object)(string.Format("[{0}] Initialized with {1} charges per totem, ", "TotemSentinel", MaxSonarCharges.Value) + $"a {MaximumStoredSonarCharges}-charge storage cap, " + $"a {ScanRadius.Value:0.#}m radius, {StateDuration.Value:0.#}s states, " + $"and a {FinalSummaryDuration.Value:0.#}s final summary.")); } catch (Exception arg) { ZLog.LogError((object)string.Format("[{0}] Failed to install Harmony patches: {1}", "TotemSentinel", arg)); } } private void Update() { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) ZNet instance = ZNet.instance; if (_hasActiveSonarSession && (Object)(object)instance != (Object)null && _sessionWorldUid != 0L && instance.GetWorldUID() != _sessionWorldUid) { ZLog.Log((object)"[TotemSentinel] Cleared camp checks after the active world changed."); ResetSonarSession(); } Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { if ((Object)(object)instance == (Object)null) { ResetSonarSession(); } else { SuspendSonarForDeath(); } return; } if (((Character)localPlayer).IsDead()) { SuspendSonarForDeath(); return; } ResumeSonarAfterDeath(); if (_scanInProgress) { UpdateActiveScan(localPlayer); } else { if (!_hasActiveSonarSession || Console.IsVisible() || TextInput.IsVisible() || !Input.GetKeyDown(PingHotkey.Value)) { return; } if (ActiveSonarCharges <= 0) { ZLog.Log((object)"[TotemSentinel] Ping rejected: no camp checks remain."); SonarPresenter.ShowNoChargesWarning(); return; } if (!SonarAbilityPanel.CanBeginScan) { ZLog.Log((object)"[TotemSentinel] Ping ignored: the camp-check display is still presenting the previous state."); return; } bool key = Input.GetKey(GreedModifierKey.Value); float num = (key ? (ScanRadius.Value * GreedMultiplier.Value) : ScanRadius.Value); Vector3 val = ((Component)localPlayer).transform.position - LastScanOrigin; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude > num * num) { ZLog.Log((object)("[TotemSentinel] Ping rejected: out of range " + $"distance={Math.Sqrt(sqrMagnitude):0.0}m radius={num:0.0}m charges={ActiveSonarCharges}.")); SonarPresenter.ShowOutOfRangeWarning(); } else { StartActiveScan(key); } } } private void OnDestroy() { TotemAlertCommands.ClearTestScenario(); ResetSonarSession(); if (_patchesApplied) { _harmony.UnpatchSelf(); _patchesApplied = false; } } private void OnGUI() { SonarAbilityPanel.Draw(_showAbilityPreview); } internal static bool SetAbilityPreview(bool? visible = null) { _showAbilityPreview = visible ?? (!_showAbilityPreview); return _showAbilityPreview; } internal static void GrantTotemSonar(Vector3 origin, int totemCount) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) if (totemCount > 0) { RestoreInterruptedScanCharge("a new totem was discovered"); int num = (_hasActiveSonarSession ? ActiveSonarCharges : 0); long num2 = (long)Math.Max(1, MaxSonarCharges.Value) * (long)totemCount; ActiveSonarCharges = (int)Math.Min(MaximumStoredSonarCharges, Math.Min(2147483647L, num + num2)); int num3 = ActiveSonarCharges - num; LastScanOrigin = origin; _sessionWorldUid = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldUID() : 0); _hasActiveSonarSession = true; _deathSuspended = false; SonarAbilityPanel.Arm(); ZLog.Log((object)("[TotemSentinel] Camp checks granted " + $"origin=({origin.x:0.0},{origin.y:0.0},{origin.z:0.0}) " + $"totems={totemCount} added={num3} " + $"charges={ActiveSonarCharges}/{MaximumStoredSonarCharges} " + $"radius={ScanRadius.Value:0.0}m hotkey={PingHotkey.Value}.")); } } private static void StartActiveScan(bool isGreed = false) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (ActiveSonarCharges <= 0) { SonarPresenter.ShowNoChargesWarning(); return; } _isGreedScan = isGreed; if (!TryReadLocalPulse(out var result, out var elapsedTicks)) { ZLog.LogError((object)"[TotemSentinel] A sonar scan could not access the current ZDO sector table."); SonarPresenter.ShowScanUnavailableWarning(); return; } ActiveSonarCharges--; _scanInProgress = true; _scanStartedAt = Time.unscaledTime; _nextScanPulseAt = _scanStartedAt + 1f; _scanCpuTicks = elapsedTicks; _scanPulseCount = 1; if (isGreed) { ArmGreedState(); } SonarPresenter.BeginScan(LastScanOrigin, result, ActiveSonarCharges, isGreed); } private static void UpdateActiveScan(Player localPlayer) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) float unscaledTime = Time.unscaledTime; if (unscaledTime - _scanStartedAt < StateDuration.Value) { if (!(unscaledTime < _nextScanPulseAt)) { if (!TryReadLocalPulse(out var result, out var elapsedTicks)) { AbortActiveScan(); return; } _scanCpuTicks += elapsedTicks; _scanPulseCount++; _nextScanPulseAt = unscaledTime + 1f; SonarAbilityPanel.UpdateScan(result); } return; } if (!TryReadLocalPulse(out var result2, out var elapsedTicks2)) { AbortActiveScan(); return; } _scanCpuTicks += elapsedTicks2; _scanPulseCount++; _scanInProgress = false; double num = (double)_scanCpuTicks * 1000.0 / (double)Stopwatch.Frequency; Vector3 val = ((Component)localPlayer).transform.position - LastScanOrigin; double num2 = Math.Sqrt(((Vector3)(ref val)).sqrMagnitude); float num3 = (_isGreedScan ? (ScanRadius.Value * GreedMultiplier.Value) : ScanRadius.Value); ZLog.Log((object)("[TotemSentinel] Camp scan complete " + $"origin=({LastScanOrigin.x:0.0},{LastScanOrigin.y:0.0},{LastScanOrigin.z:0.0}) " + $"distance={num2:0.0}m radius={num3:0.0}m isGreed={_isGreedScan} " + $"goblins={result2.Goblins} shamans={result2.Shamans} brutes={result2.Brutes} " + $"fulings={result2.Fulings} coins={result2.Coins} blackMetal={result2.BlackMetal} valuables={result2.Valuables} " + $"charges={ActiveSonarCharges} pulses={_scanPulseCount} " + $"scanCpu={num:0.000}ms source=local-zdo.")); SonarPresenter.CompleteScan(result2, ActiveSonarCharges); ResetActiveScanMetrics(); } private static bool TryReadLocalPulse(out SonarScanner.ScanResult result, out long elapsedTicks) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) float radius = (_isGreedScan ? (ScanRadius.Value * GreedMultiplier.Value) : ScanRadius.Value); long timestamp = Stopwatch.GetTimestamp(); bool result2 = SonarScanner.TryScan(LastScanOrigin, radius, out result); elapsedTicks = Stopwatch.GetTimestamp() - timestamp; return result2; } private static void AbortActiveScan() { ZLog.LogError((object)"[TotemSentinel] A live scan pulse could not access the current local ZDO sector table."); ResetActiveScan(); SonarAbilityPanel.CancelScan(); SonarPresenter.ShowScanUnavailableWarning(); } private static void SuspendSonarForDeath() { if (_hasActiveSonarSession && !_deathSuspended) { bool scanInProgress = _scanInProgress; RestoreInterruptedScanCharge("the player died"); _deathSuspended = true; SonarAbilityPanel.Suspend(); ZLog.Log((object)("[TotemSentinel] Camp checks preserved through death " + $"charges={ActiveSonarCharges}/{MaximumStoredSonarCharges} " + $"interruptedChargeRestored={scanInProgress}.")); } } private static void ResumeSonarAfterDeath() { if (_deathSuspended) { _deathSuspended = false; SonarAbilityPanel.Resume(); ZLog.Log((object)("[TotemSentinel] Camp checks restored after respawn " + $"charges={ActiveSonarCharges}/{MaximumStoredSonarCharges}.")); } } private static void RestoreInterruptedScanCharge(string reason) { if (_scanInProgress) { ActiveSonarCharges = Math.Min(MaximumStoredSonarCharges, ActiveSonarCharges + 1); ResetActiveScan(); SonarAbilityPanel.CancelScan(); ZLog.Log((object)("[TotemSentinel] Interrupted camp check cancelled because " + reason + "; one charge was restored.")); } } private static void ResetActiveScan() { _scanInProgress = false; _isGreedScan = false; ResetActiveScanMetrics(); } private static void ResetActiveScanMetrics() { _scanStartedAt = 0f; _nextScanPulseAt = 0f; _scanCpuTicks = 0L; _scanPulseCount = 0; } private static void ResetSonarSession() { //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) ActiveSonarCharges = 0; LastScanOrigin = Vector3.zero; _hasActiveSonarSession = false; _sessionWorldUid = 0L; _deathSuspended = false; DisarmGreedState(); ResetActiveScan(); SonarAbilityPanel.Reset(); } internal static void ArmGreedState() { _greedUntil = Time.unscaledTime + GreedDuration.Value; ZLog.Log((object)string.Format("[{0}] Greed's Gambit activated for {1:0}s. Any damage will enrage the horde!", "TotemSentinel", GreedDuration.Value)); } internal static void DisarmGreedState() { _greedUntil = 0f; } internal static void TriggerGreedRetribution(Player localPlayer) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) if (!IsGreedActive) { return; } _greedUntil = 0f; ZLog.LogWarning((object)"[TotemSentinel] A single scratch triggered Greed's Retribution! Alerting horde across 3x sector."); if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, "<color=#EF4444>CURSED! The Totem's greed awakens the horde!</color>", 0, (Sprite)null, false); } float num = ScanRadius.Value * GreedMultiplier.Value; float num2 = num * num; Vector3 val = (((Object)(object)localPlayer != (Object)null) ? ((Component)localPlayer).transform.position : LastScanOrigin); try { List<BaseAI> allInstances = BaseAI.GetAllInstances(); int num3 = 0; if (allInstances != null) { foreach (BaseAI item in allInstances) { if (!((Object)(object)item == (Object)null)) { Vector3 val2 = ((Component)item).transform.position - val; if (((Vector3)(ref val2)).sqrMagnitude <= num2) { item.Alert(); item.SetHuntPlayer(true); num3++; } } } } ZLog.Log((object)string.Format("[{0}] Greed's Retribution: {1} creatures alerted.", "TotemSentinel", num3)); } catch (Exception arg) { ZLog.LogError((object)string.Format("[{0}] Failed alerting creatures during retribution: {1}", "TotemSentinel", arg)); } SonarPresenter.TriggerCursed(GreedDuration.Value); } } } namespace TotemSentinel.Services { internal static class SonarScanner { internal readonly struct ScanResult { internal readonly int Goblins; internal readonly int Shamans; internal readonly int Brutes; internal readonly int Coins; internal readonly int BlackMetal; internal readonly int Valuables; internal int Fulings => Goblins + Shamans + Brutes; internal ScanResult(int goblins, int shamans, int brutes, int coins, int blackMetal, int valuables = 0) { Goblins = goblins; Shamans = shamans; Brutes = brutes; Coins = coins; BlackMetal = blackMetal; Valuables = valuables; } } private static readonly int GoblinPrefabHash = StringExtensionMethods.GetStableHashCode("Goblin"); private static readonly int GoblinShamanPrefabHash = StringExtensionMethods.GetStableHashCode("GoblinShaman"); private static readonly int GoblinBrutePrefabHash = StringExtensionMethods.GetStableHashCode("GoblinBrute"); private static readonly int CoinsPrefabHash = StringExtensionMethods.GetStableHashCode("Coins"); private static readonly int BlackMetalScrapPrefabHash = StringExtensionMethods.GetStableHashCode("BlackMetalScrap"); private static readonly int RubyPrefabHash = StringExtensionMethods.GetStableHashCode("Ruby"); private static readonly int AmberPrefabHash = StringExtensionMethods.GetStableHashCode("Amber"); private static readonly int AmberPearlPrefabHash = StringExtensionMethods.GetStableHashCode("AmberPearl"); private static readonly int SilverNecklacePrefabHash = StringExtensionMethods.GetStableHashCode("SilverNecklace"); private static readonly int GoblinTotemPrefabHash = StringExtensionMethods.GetStableHashCode("GoblinTotem"); private static FieldRef<ZDOMan, List<ZDO>[]> _objectsBySectorRef; private static FieldRef<ZDOMan, int> _widthRef; private static bool _initialized; internal static bool Initialize() { try { _objectsBySectorRef = AccessTools.FieldRefAccess<ZDOMan, List<ZDO>[]>("m_objectsBySector"); _widthRef = AccessTools.FieldRefAccess<ZDOMan, int>("m_width"); _initialized = true; return true; } catch (Exception arg) { _initialized = false; ZLog.LogError((object)string.Format("[{0}] Could not bind ZDOMan sector fields: {1}", "TotemSentinel", arg)); return false; } } internal static bool TryScan(Vector3 centerPoint, float radius, out ScanResult result) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) result = default(ScanResult); ZDOMan instance = ZDOMan.instance; if (!_initialized || instance == null || (Object)(object)ZoneSystem.instance == (Object)null) { return false; } List<ZDO>[] array = _objectsBySectorRef.Invoke(instance); int num = _widthRef.Invoke(instance); if (array == null || num <= 0 || array.Length != num * num) { return false; } Vector2s zone = ZoneSystem.GetZone(centerPoint); float num2 = radius * radius; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; int num8 = 0; int num9 = Mathf.Clamp(Mathf.CeilToInt(radius / 64f) + 1, 2, 5); for (int i = zone.y - num9; i <= zone.y + num9; i++) { int num10 = num / 2; if (i < -num10 || i >= num10) { continue; } for (int j = zone.x - num9; j <= zone.x + num9; j++) { if (j < -num10 || j >= num10) { continue; } uint sector = ZoneSystem.SectorToIndex(j, i).Sector; if (sector >= array.Length) { continue; } List<ZDO> list = array[sector]; if (list == null) { continue; } for (int k = 0; k < list.Count; k++) { ZDO val = list[k]; if (val == null) { continue; } int prefab = val.GetPrefab(); if (prefab != GoblinPrefabHash && prefab != GoblinShamanPrefabHash && prefab != GoblinBrutePrefabHash && prefab != CoinsPrefabHash && prefab != BlackMetalScrapPrefabHash && prefab != RubyPrefabHash && prefab != AmberPrefabHash && prefab != AmberPearlPrefabHash && prefab != SilverNecklacePrefabHash && prefab != GoblinTotemPrefabHash) { continue; } Vector3 val2 = val.GetPosition() - centerPoint; if (!(((Vector3)(ref val2)).sqrMagnitude > num2)) { if (prefab == CoinsPrefabHash) { int num11 = val.GetInt(ZDOVars.s_stack, 1); num6 += ((num11 <= 0) ? 1 : num11); } else if (prefab == BlackMetalScrapPrefabHash) { int num12 = val.GetInt(ZDOVars.s_stack, 1); num7 += ((num12 <= 0) ? 1 : num12); } else if (prefab == RubyPrefabHash || prefab == AmberPrefabHash || prefab == AmberPearlPrefabHash || prefab == SilverNecklacePrefabHash || prefab == GoblinTotemPrefabHash) { int num13 = val.GetInt(ZDOVars.s_stack, 1); num8 += ((num13 <= 0) ? 1 : num13); } else if (prefab == GoblinPrefabHash) { num3++; } else if (prefab == GoblinShamanPrefabHash) { num4++; } else { num5++; } } } } } result = new ScanResult(num3, num4, num5, num6, num7, num8); return true; } } } namespace TotemSentinel.Patches { [HarmonyPatch(typeof(Character), "ApplyDamage")] internal static class PlayerDamagePatch { private static void Postfix(Character __instance, HitData hit) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && hit != null && hit.GetTotalDamage() > 0.05f && TotemSentinelPlugin.IsGreedActive) { TotemSentinelPlugin.TriggerGreedRetribution(Player.m_localPlayer); } } } [HarmonyPatch(typeof(Humanoid), "Pickup", new Type[] { typeof(GameObject), typeof(bool), typeof(bool) })] internal static class TotemPickupPatch { private readonly struct PickupState { internal readonly bool Eligible; internal readonly Vector3 Origin; internal readonly int TotemCount; internal PickupState(bool eligible, Vector3 origin, int totemCount) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Eligible = eligible; Origin = origin; TotemCount = totemCount; } } private static readonly int GoblinTotemPrefabHash = StringExtensionMethods.GetStableHashCode("GoblinTotem"); private static void Prefix(Humanoid __instance, GameObject go, ref PickupState __state) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) __state = default(PickupState); if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)go == (Object)null) { return; } ItemDrop component = go.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null)) { component.Load(); ItemData itemData = component.m_itemData; GameObject val = itemData?.m_dropPrefab; if (!((Object)(object)val == (Object)null) && StringExtensionMethods.GetStableHashCode(((Object)val).name) == GoblinTotemPrefabHash && !itemData.m_pickedUp) { __state = new PickupState(eligible: true, ((Component)component).transform.position, Mathf.Max(1, itemData.m_stack)); } } } private static void Postfix(PickupState __state, ref bool __result) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (__state.Eligible & __result) { TotemSentinelPlugin.GrantTotemSonar(__state.Origin, __state.TotemCount); } } } } namespace TotemSentinel.HUD { internal static class SonarAbilityPanel { private enum PanelState { Hidden, Ready, Scanning, Found, Clear, Complete, OutOfRange, Depleted, Unavailable, Cursed } private static readonly Vector3[] MapCorners = (Vector3[])(object)new Vector3[4]; private static readonly Color ReadyColor = new Color(0.94f, 0.94f, 0.94f, 1f); private static readonly Color GoldColor = new Color(1f, 0.69f, 0.18f, 1f); private static readonly Color OrangeColor = new Color(1f, 0.45f, 0.08f, 1f); private static readonly Color RedColor = new Color(1f, 0.16f, 0.19f, 1f); private static readonly Color GreenColor = new Color(0.08f, 0.78f, 0.3f, 1f); private static readonly Color MutedColor = new Color(0.72f, 0.72f, 0.72f, 1f); private static readonly Color BackgroundColor = new Color(0.025f, 0.025f, 0.025f, 0.9f); private static PanelState _state; private static SonarScanner.ScanResult _result; private static bool _hasResult; private static SonarScanner.ScanResult _resultBeforeScan; private static bool _hadResultBeforeScan; private static bool _hasScanBackup; private static bool _dismissed; private static bool _suspended; private static float _suspendedAt; private static float _stateStarted; private static float _finalScanStarted = -1f; private static bool _isGreedScan; private static float _cursedUntil; private static float _cursedStarted; private static GUIStyle _titleStyle; private static GUIStyle _mainStyle; private static GUIStyle _detailStyle; private static GUIStyle _summaryStyle; private static GUIStyle _closeStyle; internal static bool CanBeginScan { get { if (_state != PanelState.Ready) { return _state == PanelState.Hidden; } return true; } } internal static void Arm() { _result = default(SonarScanner.ScanResult); _hasResult = false; _hasScanBackup = false; _dismissed = false; _suspended = false; _finalScanStarted = -1f; SetState(PanelState.Ready); } internal static void BeginScan(SonarScanner.ScanResult result, int charges, bool isGreed = false) { _isGreedScan = isGreed; _resultBeforeScan = _result; _hadResultBeforeScan = _hasResult; _hasScanBackup = true; _result = result; _hasResult = true; _dismissed = false; SetState(PanelState.Scanning); } internal static void TriggerCursed(float duration) { _cursedStarted = Time.unscaledTime; _cursedUntil = Time.unscaledTime + duration; _dismissed = false; SetState(PanelState.Cursed); } internal static void UpdateScan(SonarScanner.ScanResult result) { if (_state == PanelState.Scanning) { _result = result; _hasResult = true; } } internal static void CompleteScan(SonarScanner.ScanResult result, int charges) { _result = result; _hasResult = true; _hasScanBackup = false; _dismissed = false; if (charges <= 0) { _finalScanStarted = Time.unscaledTime; } SetState((result.Fulings > 0) ? PanelState.Found : PanelState.Clear); } internal static void CancelScan() { if (_hasScanBackup) { _result = _resultBeforeScan; _hasResult = _hadResultBeforeScan; } _hasScanBackup = false; SetState((TotemSentinelPlugin.ActiveSonarCharges > 0) ? PanelState.Ready : PanelState.Hidden); } internal static void Suspend() { if (!_suspended) { _suspended = true; _suspendedAt = Time.unscaledTime; } } internal static void Resume() { if (_suspended) { float num = Time.unscaledTime - _suspendedAt; if (_finalScanStarted >= 0f) { _finalScanStarted += num; } _suspended = false; _suspendedAt = 0f; SetState((TotemSentinelPlugin.ActiveSonarCharges > 0) ? PanelState.Ready : (_hasResult ? PanelState.Complete : PanelState.Hidden)); } } internal static void ShowOutOfRange() { _dismissed = false; SetState(PanelState.OutOfRange); } internal static void ShowDepleted() { _dismissed = false; SetState(PanelState.Depleted); } internal static void ShowUnavailable() { _dismissed = false; SetState(PanelState.Unavailable); } internal static void Reset() { _result = default(SonarScanner.ScanResult); _hasResult = false; _resultBeforeScan = default(SonarScanner.ScanResult); _hadResultBeforeScan = false; _hasScanBackup = false; _dismissed = false; _suspended = false; _suspendedAt = 0f; _state = PanelState.Hidden; _stateStarted = 0f; _finalScanStarted = -1f; _isGreedScan = false; _cursedUntil = 0f; _cursedStarted = 0f; } internal static void Draw(bool preview) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) if (_suspended) { return; } UpdateState(); bool flag = TotemSentinelPlugin.HasActiveSonarSession && TotemSentinelPlugin.ActiveSonarCharges > 0; if (preview || (!_dismissed && (_state != PanelState.Hidden || flag))) { if (_state == PanelState.Hidden && flag && !_dismissed) { SetState(PanelState.Ready); } EnsureStyles(); bool showSummary = ShouldShowSummary(); Rect cardRect = GetCardRect(showSummary); float num = Mathf.Clamp((float)Screen.height / 1080f, 0.8f, 1.45f); float num2 = Mathf.Max(3f, 4f * num); Color accentColor = GetAccentColor(preview); DrawSolidRect(cardRect, accentColor); DrawSolidRect(new Rect(((Rect)(ref cardRect)).x + num2, ((Rect)(ref cardRect)).y + num2, ((Rect)(ref cardRect)).width - num2 * 2f, ((Rect)(ref cardRect)).height - num2 * 2f), BackgroundColor); _titleStyle.fontSize = Mathf.RoundToInt(17f * num); _mainStyle.fontSize = Mathf.RoundToInt(27f * num); _detailStyle.fontSize = Mathf.RoundToInt(13f * num); _summaryStyle.fontSize = Mathf.RoundToInt(13f * num); _closeStyle.fontSize = Mathf.RoundToInt(16f * num); DrawContent(cardRect, num, preview, accentColor, showSummary); } } private static void DrawContent(Rect card, float scale, bool preview, Color accent, bool showSummary) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0137: 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_022f: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) float num = 10f * scale; float num2 = ((Rect)(ref card)).width - num * 2f; Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref card)).x + num, ((Rect)(ref card)).y + 9f * scale, num2, 25f * scale); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(((Rect)(ref card)).x + num, ((Rect)(ref card)).y + 35f * scale, num2, 42f * scale); Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(((Rect)(ref card)).x + num, ((Rect)(ref card)).y + 79f * scale, num2, 38f * scale); _titleStyle.normal.textColor = accent; _mainStyle.normal.textColor = accent; _detailStyle.normal.textColor = ReadyColor; PanelState state = _state; if (state == PanelState.Hidden && preview) { GUI.Label(val, "CAMP CHECKS", _titleStyle); GUI.Label(val2, "-- / --", _mainStyle); GUI.Label(val3, "WAITING FOR A TOTEM", _detailStyle); return; } switch (state) { case PanelState.Ready: DrawReady(val, val2, val3); break; case PanelState.Scanning: { float num4 = Mathf.Max(0f, GetStateDuration() - (Time.unscaledTime - _stateStarted)); string text = (_isGreedScan ? "GREED SCAN" : "SCANNING"); string text2 = (_isGreedScan ? "3x WIDE LOOT SEARCH" : "LISTENING ACROSS THE CAMP"); GUI.Label(val, text, _titleStyle); GUI.Label(val2, $"{num4:0}s", _mainStyle); GUI.Label(val3, text2, _detailStyle); break; } case PanelState.Cursed: { float num3 = Mathf.Max(0f, _cursedUntil - Time.unscaledTime); GUI.Label(val, "CURSED!", _titleStyle); GUI.Label(val2, $"{num3:0}s", _mainStyle); GUI.Label(val3, "HORDE ALERTED ACROSS CAMP", _detailStyle); break; } case PanelState.Found: GUI.Label(val, "FULINGS FOUND", _titleStyle); GUI.Label(val2, _result.Fulings.ToString(), _mainStyle); GUI.Label(val3, "LAST CAMP CHECK", _detailStyle); break; case PanelState.Clear: GUI.Label(val, "CAMP", _titleStyle); GUI.Label(val2, "CLEAR", _mainStyle); GUI.Label(val3, "LAST CAMP CHECK", _detailStyle); break; case PanelState.Complete: GUI.Label(val, "CHECKS COMPLETE", _titleStyle); GUI.Label(val2, $"0 / {TotemSentinelPlugin.MaximumStoredSonarCharges}", _mainStyle); GUI.Label(val3, "CLOSES IN " + FormatFinalTimeRemaining(), _detailStyle); DrawCloseButton(card, scale); break; case PanelState.OutOfRange: GUI.Label(val, "OUT OF RANGE", _titleStyle); GUI.Label(val2, $"> {TotemSentinelPlugin.ScanRadius.Value:0}m", _mainStyle); GUI.Label(val3, "RETURN TO THE TOTEM'S CAMP", _detailStyle); break; case PanelState.Depleted: GUI.Label(val, "NO CHECKS", _titleStyle); GUI.Label(val2, "0", _mainStyle); GUI.Label(val3, "LAST RESULT REMAINS BELOW", _detailStyle); break; case PanelState.Unavailable: GUI.Label(val, "SCAN FAILED", _titleStyle); GUI.Label(val2, "--", _mainStyle); GUI.Label(val3, "CHECK THE COMFYSENTINEL LOG", _detailStyle); break; } if (showSummary) { DrawSummary(card, scale); } } private static void DrawReady(Rect titleRect, Rect mainRect, Rect detailRect) { //IL_000c: 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_0071: 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) int activeSonarCharges = TotemSentinelPlugin.ActiveSonarCharges; int maximumStoredSonarCharges = TotemSentinelPlugin.MaximumStoredSonarCharges; GUI.Label(titleRect, "CAMP CHECKS", _titleStyle); _mainStyle.richText = true; string text = ((activeSonarCharges < maximumStoredSonarCharges) ? $"<color=#FFB02E>{activeSonarCharges}</color> / {maximumStoredSonarCharges}" : $"{activeSonarCharges} / {maximumStoredSonarCharges}"); GUI.Label(mainRect, text, _mainStyle); _mainStyle.richText = false; GUI.Label(detailRect, $"\"{TotemSentinelPlugin.PingHotkey.Value}\" CHECK · SHIFT GREED", _detailStyle); } private static void DrawSummary(Rect card, float scale) { //IL_0048: 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) //IL_014a: Unknown result type (might be due to invalid IL or missing references) float num = 14f * scale; float num2 = ((Rect)(ref card)).y + 123f * scale; float num3 = 17f * scale; float num4 = ((Rect)(ref card)).width - num * 2f; DrawSolidRect(new Rect(((Rect)(ref card)).x + num, num2 - 6f * scale, num4, 1f), new Color(1f, 0.69f, 0.18f, 0.45f)); int row = 0; DrawSummaryRow(((Rect)(ref card)).x + num, num2, num4, num3, ref row, "FULINGS", _result.Goblins); DrawSummaryRow(((Rect)(ref card)).x + num, num2, num4, num3, ref row, "SHAMANS", _result.Shamans); DrawSummaryRow(((Rect)(ref card)).x + num, num2, num4, num3, ref row, "BRUTES", _result.Brutes); DrawSummaryRow(((Rect)(ref card)).x + num, num2, num4, num3, ref row, "COINS", _result.Coins); DrawSummaryRow(((Rect)(ref card)).x + num, num2, num4, num3, ref row, "BLACK METAL", _result.BlackMetal); DrawSummaryRow(((Rect)(ref card)).x + num, num2, num4, num3, ref row, "VALUABLES", _result.Valuables); if (row == 0) { GUI.Label(new Rect(((Rect)(ref card)).x + num, num2, num4, num3), "NOTHING DETECTED", _summaryStyle); } } private static void DrawSummaryRow(float x, float top, float width, float rowHeight, ref int row, string label, int count) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (count > 0) { GUI.Label(new Rect(x, top + (float)row * rowHeight, width, rowHeight), $"{label} {count}", _summaryStyle); row++; } } private static void DrawCloseButton(Rect card, float scale) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (GUI.Button(new Rect(((Rect)(ref card)).xMax - 31f * scale, ((Rect)(ref card)).y + 7f * scale, 23f * scale, 23f * scale), "X", _closeStyle)) { _dismissed = true; SetState(PanelState.Hidden); ZLog.Log((object)"[TotemSentinel] Final camp-check summary dismissed by the player."); } } private static void UpdateState() { if (_finalScanStarted >= 0f && Time.unscaledTime - _finalScanStarted >= GetFinalSummaryDuration()) { if (_state != PanelState.Hidden) { ZLog.Log((object)"[TotemSentinel] Final camp-check summary closed after its timer elapsed."); } _dismissed = true; _state = PanelState.Hidden; return; } float num = Time.unscaledTime - _stateStarted; float stateDuration = GetStateDuration(); if (_state == PanelState.Cursed && Time.unscaledTime >= _cursedUntil) { SetState((TotemSentinelPlugin.ActiveSonarCharges > 0) ? PanelState.Ready : PanelState.Complete); } else if ((_state == PanelState.Found || _state == PanelState.Clear) && num >= stateDuration) { SetState((TotemSentinelPlugin.ActiveSonarCharges > 0) ? PanelState.Ready : PanelState.Complete); } else if ((_state == PanelState.OutOfRange || _state == PanelState.Unavailable) && num >= stateDuration) { SetState((TotemSentinelPlugin.ActiveSonarCharges > 0) ? PanelState.Ready : PanelState.Complete); } else if (_state == PanelState.Depleted && num >= stateDuration) { SetState(_hasResult ? PanelState.Complete : PanelState.Hidden); } } private static bool ShouldShowSummary() { if (!_hasResult) { return false; } if (_state != PanelState.Ready && _state != PanelState.Scanning && _state != PanelState.Found && _state != PanelState.Clear && _state != PanelState.Complete && _state != PanelState.Depleted) { return _state == PanelState.Cursed; } return true; } private static Rect GetCardRect(bool showSummary) { //IL_0196: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp((float)Screen.height / 1080f, 0.8f, 1.45f); float num2 = 230f * num; float num3 = (showSummary ? Mathf.Max(1, GetSummaryRowCount()) : 0); float num4 = (125f + num3 * 17f + (showSummary ? 8f : 0f)) * num; float num5 = (float)Screen.width - num2 - 22f * num; float num6 = 285f * num; Minimap instance = Minimap.instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.m_smallRoot != (Object)null && instance.m_smallRoot.activeInHierarchy && (Object)(object)instance.m_mapImageSmall != (Object)null) { ((Graphic)instance.m_mapImageSmall).rectTransform.GetWorldCorners(MapCorners); float num7 = MapCorners[0].x; float num8 = MapCorners[0].y; for (int i = 1; i < MapCorners.Length; i++) { num7 = Mathf.Max(num7, MapCorners[i].x); num8 = Mathf.Min(num8, MapCorners[i].y); } num5 = num7 - num2; num6 = (float)Screen.height - num8 + 10f * num; } num5 = Mathf.Clamp(num5, 8f, (float)Screen.width - num2 - 8f); num6 = Mathf.Clamp(num6, 8f, (float)Screen.height - num4 - 8f); return new Rect(num5, num6, num2, num4); } private static int GetSummaryRowCount() { return 0 + ((_result.Goblins > 0) ? 1 : 0) + ((_result.Shamans > 0) ? 1 : 0) + ((_result.Brutes > 0) ? 1 : 0) + ((_result.Coins > 0) ? 1 : 0) + ((_result.BlackMetal > 0) ? 1 : 0) + ((_result.Valuables > 0) ? 1 : 0); } private static Color GetAccentColor(bool preview) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) switch (_state) { case PanelState.Cursed: return RedColor; case PanelState.Scanning: if (!_isGreedScan) { return OrangeColor; } return GoldColor; case PanelState.Found: return RedColor; case PanelState.Clear: return GreenColor; case PanelState.Complete: return GoldColor; case PanelState.OutOfRange: case PanelState.Depleted: case PanelState.Unavailable: return OrangeColor; case PanelState.Ready: return ReadyColor; default: if (!preview) { return ReadyColor; } return MutedColor; } } private static string FormatFinalTimeRemaining() { int num = Mathf.Max(0, Mathf.CeilToInt(GetFinalSummaryDuration() - (Time.unscaledTime - _finalScanStarted))); return $"{num / 60}:{num % 60:00}"; } private static float GetStateDuration() { if (TotemSentinelPlugin.StateDuration == null) { return 10f; } return TotemSentinelPlugin.StateDuration.Value; } private static float GetFinalSummaryDuration() { if (TotemSentinelPlugin.FinalSummaryDuration == null) { return 300f; } return TotemSentinelPlugin.FinalSummaryDuration.Value; } private static void DrawSolidRect(Rect rect, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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) Color color2 = GUI.color; GUI.color = color; GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture); GUI.color = color2; } private static void SetState(PanelState state) { _state = state; _stateStarted = Time.unscaledTime; } private static void EnsureStyles() { //IL_0009: 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_0029: 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_0054: 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_0081: Unknown result type (might be due to invalid IL or missing references) if (_titleStyle == null) { _titleStyle = CreateCenteredStyle((FontStyle)1, ReadyColor); _mainStyle = CreateCenteredStyle((FontStyle)1, ReadyColor); _detailStyle = CreateCenteredStyle((FontStyle)0, ReadyColor); _detailStyle.wordWrap = true; _summaryStyle = CreateCenteredStyle((FontStyle)0, GoldColor); _closeStyle = CreateCenteredStyle((FontStyle)1, ReadyColor); _closeStyle.hover.textColor = RedColor; _closeStyle.active.textColor = OrangeColor; } } private static GUIStyle CreateCenteredStyle(FontStyle fontStyle, Color color) { //IL_000a: 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) //IL_0016: 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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown GUIStyle val = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontStyle = fontStyle, clipping = (TextClipping)1 }; val.normal.textColor = color; return val; } } internal static class SonarPresenter { internal static void BeginScan(Vector3 origin, SonarScanner.ScanResult result, int charges, bool isGreed = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) PlayPingEffect(origin); SonarAbilityPanel.BeginScan(result, charges, isGreed); } internal static void TriggerCursed(float duration) { SonarAbilityPanel.TriggerCursed(duration); } internal static void CompleteScan(SonarScanner.ScanResult result, int charges) { SonarAbilityPanel.CompleteScan(result, charges); } internal static void ShowOutOfRangeWarning() { SonarAbilityPanel.ShowOutOfRange(); } internal static void ShowNoChargesWarning() { SonarAbilityPanel.ShowDepleted(); } internal static void ShowScanUnavailableWarning() { SonarAbilityPanel.ShowUnavailable(); } private static void PlayPingEffect(Vector3 origin) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) try { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { ZLog.LogWarning((object)"[TotemSentinel] ZNetScene was unavailable for the sonar effect."); return; } GameObject prefab = instance.GetPrefab("vfx_WishbonePing"); if ((Object)(object)prefab == (Object)null) { ZLog.LogWarning((object)"[TotemSentinel] Could not find vfx_WishbonePing."); } else if ((Object)(object)prefab.GetComponentInChildren<ZNetView>(true) != (Object)null) { ZLog.LogWarning((object)"[TotemSentinel] Skipped networked vfx_WishbonePing to preserve local-only scanning."); } else { Object.Instantiate<GameObject>(prefab, origin, Quaternion.identity); } } catch (Exception arg) { ZLog.LogError((object)string.Format("[{0}] Failed to play the sonar effect: {1}", "TotemSentinel", arg)); } } } } namespace TotemSentinel.Commands { internal static class TotemAlertCommands { [CompilerGenerated] private static class <>O { public static ConsoleEventFailable <0>__RunTotemAlertCommand; public static ConsoleEventFailable <1>__RunTotemCommand; } private static readonly List<GameObject> SpawnedTestObjects = new List<GameObject>(7); private static bool _registered; internal static void Register() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown if (!_registered) { object obj = <>O.<0>__RunTotemAlertCommand; if (obj == null) { ConsoleEventFailable val = RunTotemAlertCommand; <>O.<0>__RunTotemAlertCommand = val; obj = (object)val; } new ConsoleCommand("totemalert", "[on/off/status] - preview the ComfySentinel camp-check panel", (ConsoleEventFailable)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj2 = <>O.<1>__RunTotemCommand; if (obj2 == null) { ConsoleEventFailable val2 = RunTotemCommand; <>O.<1>__RunTotemCommand = val2; obj2 = (object)val2; } new ConsoleCommand("totem", "1 - spawn the ComfySentinel test camp; 'totem clear' removes it", (ConsoleEventFailable)obj2, false, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); _registered = true; } } private static object RunTotemAlertCommand(ConsoleEventArgs args) { bool flag; if (args.Length == 1) { flag = TotemSentinelPlugin.SetAbilityPreview(); } else if (string.Equals(args[1], "on", StringComparison.OrdinalIgnoreCase)) { flag = TotemSentinelPlugin.SetAbilityPreview(true); } else { if (!string.Equals(args[1], "off", StringComparison.OrdinalIgnoreCase)) { if (string.Equals(args[1], "status", StringComparison.OrdinalIgnoreCase)) { WriteStatus(args.Context); return true; } return "Use: totemalert [on|off|status]"; } flag = TotemSentinelPlugin.SetAbilityPreview(false); } Terminal context = args.Context; if (context != null) { context.AddString("ComfySentinel 1.5.2 is running. Panel preview: " + (flag ? "open" : "closed") + "."); } Terminal context2 = args.Context; if (context2 != null) { context2.AddString("Use 'totem 1' to create the test camp and 'totem clear' to remove it."); } return true; } private static object RunTotemCommand(ConsoleEventArgs args) { if (args.Length < 2) { return "Use: totem 1 | totem clear"; } if (string.Equals(args[1], "clear", StringComparison.OrdinalIgnoreCase)) { int num = ClearTestScenario(); Terminal context = args.Context; if (context != null) { context.AddString($"ComfySentinel test camp cleared ({num} tracked objects removed)."); } return true; } if (args[1] != "1") { return "Unknown scenario. Use: totem 1 | totem clear"; } if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return "Test spawning is restricted to a local world or a world hosted by this client."; } Player localPlayer = Player.m_localPlayer; ZNetScene instance = ZNetScene.instance; if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null) { return "Enter a fully loaded local/hosted world before spawning the test camp."; } try { ClearTestScenario(); string text = SpawnScenarioOne(localPlayer, instance); if (text != null) { ClearTestScenario(); return text; } Terminal context2 = args.Context; if (context2 != null) { context2.AddString("ComfySentinel scenario 1 created: totem, three Fuling types, 12 coins, and 8 black metal."); } Terminal context3 = args.Context; if (context3 != null) { context3.AddString("Close the console, pick up the loose totem to add " + $"{TotemSentinelPlugin.MaxSonarCharges.Value} checks, then press the configured hotkey when ready."); } ZLog.Log((object)"[TotemSentinel] Test scenario 1 created with 7 tracked objects."); return true; } catch (Exception ex) { ClearTestScenario(); ZLog.LogError((object)string.Format("[{0}] Failed to create test scenario 1: {1}", "TotemSentinel", ex)); return "Scenario creation failed: " + ex.Message; } } private static string SpawnScenarioOne(Player player, ZNetScene scene) { //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: 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_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0217: 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) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //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_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0256: 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_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_031f: 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_032b: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) GameObject val = FindPrefab(scene, "itemstand", "itemstandh", "piece_itemstand"); GameObject val2 = FindPrefab(scene, "GoblinTotem"); GameObject val3 = FindPrefab(scene, "Goblin"); GameObject val4 = FindPrefab(scene, "GoblinShaman"); GameObject val5 = FindPrefab(scene, "GoblinBrute"); GameObject val6 = FindPrefab(scene, "Coins"); GameObject val7 = FindPrefab(scene, "BlackMetalScrap"); GameObject val8 = FindPickableTemplate(scene); if ((Object)(object)val == (Object)null) { return "Could not find an item stand prefab in this Valheim build."; } if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null) { return "One or more required Fuling or loose-loot prefabs are unavailable in this world."; } if ((Object)(object)val8 == (Object)null) { return "Could not find a native Pickable prefab to use as the test interaction proxy."; } Vector3 forward = ((Component)player).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.01f) { forward = Vector3.forward; } ((Vector3)(ref forward)).Normalize(); Vector3 val9 = Vector3.Cross(Vector3.up, forward); Vector3 val10 = GroundPosition(((Component)player).transform.position + forward * 5f); Quaternion rotation = Quaternion.LookRotation(-forward, Vector3.up); GameObject obj = Spawn(val, val10, rotation); ItemStand component = obj.GetComponent<ItemStand>(); ZNetView component2 = obj.GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || !component2.IsValid()) { return "The available item stand prefab is missing its expected Valheim components."; } ConfigureStandVisual(component2, ((Object)val2).name); Vector3 position = (((Object)(object)component.m_attachOther != (Object)null) ? component.m_attachOther.position : (val10 + Vector3.up * 1.25f)); ConfigurePickableTotem(Spawn(val8, position, rotation), val2); Spawn(val3, GroundPosition(val10 + forward * 13f + val9 * 9f) + Vector3.up, Quaternion.identity); Spawn(val4, GroundPosition(val10 + forward * 17f - val9 * 11f) + Vector3.up, Quaternion.identity); Spawn(val5, GroundPosition(val10 + forward * 23f + val9 * 2f) + Vector3.up, Quaternion.identity); SpawnItemStack(val6, 12, GroundPosition(val10 + forward * 9f - val9 * 4f) + Vector3.up); SpawnItemStack(val7, 8, GroundPosition(val10 + forward * 11f + val9 * 4f) + Vector3.up); return null; } private static void SpawnItemStack(GameObject prefab, int stack, Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) ItemDrop component = Spawn(prefab, position, Quaternion.identity).GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("Test loot prefab " + ((Object)prefab).name + " is not an ItemDrop."); } component.SetStack(stack); } private static void ConfigureStandVisual(ZNetView standNetView, string itemPrefabName) { ZDO zDO = standNetView.GetZDO(); zDO.Set(ZDOVars.s_item, itemPrefabName); zDO.Set(ZDOVars.s_type, 0, false); standNetView.InvokeRPC(ZNetView.Everybody, "SetVisualItem", new object[4] { itemPrefabName, 0, 1, 0 }); } private static void ConfigurePickableTotem(GameObject pickableObject, GameObject totemPrefab) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) Pickable component = pickableObject.GetComponent<Pickable>(); if ((Object)(object)component == (Object)null) { throw new InvalidOperationException("The selected Pickable template did not instantiate correctly."); } ((MonoBehaviour)component).CancelInvoke(); component.m_itemPrefab = totemPrefab; component.m_amount = 1; component.m_minAmountScaled = 1; component.m_dontScale = true; component.m_extraDrops = new DropTable(); component.m_hideWhenPicked = null; component.m_respawnTimeMinutes = 0f; component.m_tarPreventsPicking = false; component.m_aggravateRange = 0f; component.m_harvestable = false; component.m_pickRaiseSkill = (SkillType)0; Renderer[] componentsInChildren = pickableObject.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } SphereCollider obj = pickableObject.AddComponent<SphereCollider>(); obj.radius = 0.6f; ((Collider)obj).isTrigger = false; } private static GameObject FindPickableTemplate(ZNetScene scene) { GameObject val = FindPrefab(scene, "Pickable_Branch", "pickable_branch", "Pickable_Barley", "pickable_barley"); if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponent<Pickable>() != (Object)null) { return val; } for (int i = 0; i < scene.m_prefabs.Count; i++) { GameObject val2 = scene.m_prefabs[i]; if ((Object)(object)val2 != (Object)null && (Object)(object)val2.GetComponent<Pickable>() != (Object)null) { return val2; } } return null; } private static GameObject FindPrefab(ZNetScene scene, params string[] candidateNames) { for (int i = 0; i < candidateNames.Length; i++) { GameObject prefab = scene.GetPrefab(candidateNames[i]); if ((Object)(object)prefab != (Object)null) { return prefab; } } for (int j = 0; j < scene.m_prefabs.Count; j++) { GameObject val = scene.m_prefabs[j]; if ((Object)(object)val == (Object)null) { continue; } for (int k = 0; k < candidateNames.Length; k++) { if (string.Equals(((Object)val).name, candidateNames[k], StringComparison.OrdinalIgnoreCase)) { return val; } } } return null; } private static GameObject Spawn(GameObject prefab, Vector3 position, Quaternion rotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(prefab, position, rotation); ZNetView component = val.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { component.GetZDO().Persistent = false; } SpawnedTestObjects.Add(val); return val; } private static Vector3 GroundPosition(Vector3 position) { //IL_0005: 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) float y = default(float); if (ZoneSystem.instance.GetGroundHeight(position, ref y)) { position.y = y; } return position; } internal static int ClearTestScenario() { int num = 0; ZNetScene instance = ZNetScene.instance; for (int num2 = SpawnedTestObjects.Count - 1; num2 >= 0; num2--) { GameObject val = SpawnedTestObjects[num2]; if (!((Object)(object)val == (Object)null)) { if ((Object)(object)instance != (Object)null) { instance.Destroy(val); } else { Object.Destroy((Object)(object)val); } num++; } } SpawnedTestObjects.Clear(); if (num > 0) { ZLog.Log((object)string.Format("[{0}] Cleared {1} tracked test scenario objects.", "TotemSentinel", num)); } return num; } private static void WriteStatus(Terminal context) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) if (context != null) { context.AddString("ComfySentinel 1.5.2: running"); } if (context != null) { context.AddString("Sonar session: " + (TotemSentinelPlugin.HasActiveSonarSession ? "active" : "waiting for a totem") + "; " + $"charges: {TotemSentinelPlugin.ActiveSonarCharges}/{TotemSentinelPlugin.MaximumStoredSonarCharges}; " + $"per totem: {TotemSentinelPlugin.MaxSonarCharges.Value}; radius: {TotemSentinelPlugin.ScanRadius.Value:0.#}m; " + $"hotkey: {TotemSentinelPlugin.PingHotkey.Value}"); } if (context != null) { context.AddString($"State duration: {TotemSentinelPlugin.StateDuration.Value:0.#}s; " + $"final summary: {TotemSentinelPlugin.FinalSummaryDuration.Value:0.#}s"); } if (context != null) { context.AddString($"Tracked scenario objects: {SpawnedTestObjects.Count}"); } } } }