Decompiled source of PeakSpectatorMode v1.1.1
PeakSpectatorMode.dll
Decompiled 4 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Ashley.MeshSplitter")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("com.rlabrecque.steamworks.net")] [assembly: IgnoresAccessChecksTo("DemiLib")] [assembly: IgnoresAccessChecksTo("DOTween")] [assembly: IgnoresAccessChecksTo("DOTweenPro")] [assembly: IgnoresAccessChecksTo("HBAO.Runtime")] [assembly: IgnoresAccessChecksTo("HBAO.Universal.Runtime")] [assembly: IgnoresAccessChecksTo("LightVolume.Runtime")] [assembly: IgnoresAccessChecksTo("Mono.Security")] [assembly: IgnoresAccessChecksTo("Newtonsoft.Json")] [assembly: IgnoresAccessChecksTo("Photon3Unity3D")] [assembly: IgnoresAccessChecksTo("PhotonChat")] [assembly: IgnoresAccessChecksTo("PhotonRealtime")] [assembly: IgnoresAccessChecksTo("PhotonUnityNetworking.Demos")] [assembly: IgnoresAccessChecksTo("PhotonUnityNetworking")] [assembly: IgnoresAccessChecksTo("PhotonUnityNetworking.Utilities")] [assembly: IgnoresAccessChecksTo("PhotonVoice.API")] [assembly: IgnoresAccessChecksTo("PhotonVoice")] [assembly: IgnoresAccessChecksTo("PhotonVoice.PUN")] [assembly: IgnoresAccessChecksTo("pworld")] [assembly: IgnoresAccessChecksTo("sc.posteffects.runtime")] [assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Attributes")] [assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Modules.Unity.Addressables")] [assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Modules.UnityLocalization")] [assembly: IgnoresAccessChecksTo("Sirenix.Serialization.Config")] [assembly: IgnoresAccessChecksTo("Sirenix.Serialization")] [assembly: IgnoresAccessChecksTo("Sirenix.Utilities")] [assembly: IgnoresAccessChecksTo("Tayx.Graphy")] [assembly: IgnoresAccessChecksTo("unity-websocket-sharp")] [assembly: IgnoresAccessChecksTo("Unity.Addressables")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")] [assembly: IgnoresAccessChecksTo("Unity.Burst")] [assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")] [assembly: IgnoresAccessChecksTo("Unity.Cinemachine")] [assembly: IgnoresAccessChecksTo("Unity.Collections")] [assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.RebindingUI")] [assembly: IgnoresAccessChecksTo("Unity.InternalAPIEngineBridge.004")] [assembly: IgnoresAccessChecksTo("Unity.InternalAPIEngineBridge.013")] [assembly: IgnoresAccessChecksTo("Unity.Localization")] [assembly: IgnoresAccessChecksTo("Unity.Mathematics")] [assembly: IgnoresAccessChecksTo("Unity.MemoryProfiler")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Center.Common")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Playmode.Common.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Playmode")] [assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")] [assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")] [assembly: IgnoresAccessChecksTo("Unity.Rendering.LightTransport.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipeline.Universal.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime.Shared")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.GPUDriven.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Universal.2D.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Universal.Config.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Universal.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Universal.Shaders")] [assembly: IgnoresAccessChecksTo("Unity.ResourceManager")] [assembly: IgnoresAccessChecksTo("Unity.ScriptableBuildPipeline")] [assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")] [assembly: IgnoresAccessChecksTo("Unity.Services.Authentication.PlayerAccounts")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Components")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")] [assembly: IgnoresAccessChecksTo("Unity.Services.Multiplayer")] [assembly: IgnoresAccessChecksTo("Unity.Services.QoS")] [assembly: IgnoresAccessChecksTo("Unity.Services.Wire.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Splines")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.UnifiedRayTracing.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")] [assembly: IgnoresAccessChecksTo("UnityEngine.AccessibilityModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.AdaptivePerformanceModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.AIModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.AMDModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.AndroidJNIModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.AnimationModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.AssetBundleModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.AudioModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.ClothModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.ClusterInputModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.ClusterRendererModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.ContentLoadModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.CoreModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.CrashReportingModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.DirectorModule")] [assembly: IgnoresAccessChecksTo("UnityEngine")] [assembly: IgnoresAccessChecksTo("UnityEngine.DSPGraphModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.GameCenterModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.GIModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.GraphicsStateCollectionSerializerModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.GridModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.HierarchyCoreModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.HierarchyModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.HotReloadModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.IdentifiersModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.ImageConversionModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.IMGUIModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.InputForUIModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.InputLegacyModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.InputModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.InsightsModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.JSONSerializeModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.LocalizationModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.MarshallingModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.MultiplayerModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.ParticleSystemModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.PerformanceReportingModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.Physics2DModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.PhysicsBackendPhysXModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.PhysicsModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.PropertiesModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.RenderAs2DModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.ScreenCaptureModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.ShaderRuntimeModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.ShaderVariantAnalyticsModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.SharedInternalsModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.SpriteMaskModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.SpriteShapeModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.StreamingModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.SubstanceModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.SubsystemsModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.TerrainModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.TerrainPhysicsModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.TextCoreFontEngineModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.TextCoreTextEngineModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.TextRenderingModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.TilemapModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.TLSModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: IgnoresAccessChecksTo("UnityEngine.UIElementsModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UIModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UmbraModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UnityAnalyticsCommonModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UnityAnalyticsModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UnityConnectModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UnityConsentModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UnityCurlModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UnityTestProtocolModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UnityWebRequestAssetBundleModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UnityWebRequestAudioModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UnityWebRequestModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UnityWebRequestTextureModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UnityWebRequestWWWModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.VectorGraphicsModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.VehiclesModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.VFXModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.VideoModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.VirtualTexturingModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.VRModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.WindModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.XRModule")] [assembly: IgnoresAccessChecksTo("UnityUIExtensions")] [assembly: IgnoresAccessChecksTo("websocket-sharp")] [assembly: IgnoresAccessChecksTo("Whinarn.UnityMeshSimplifier.Runtime")] [assembly: IgnoresAccessChecksTo("Zorro.AutoLOD")] [assembly: IgnoresAccessChecksTo("Zorro.ControllerSupport")] [assembly: IgnoresAccessChecksTo("Zorro.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Zorro.JiggleBones")] [assembly: IgnoresAccessChecksTo("Zorro.PhotonUtility")] [assembly: IgnoresAccessChecksTo("Zorro.Settings.Runtime")] [assembly: IgnoresAccessChecksTo("Zorro.UI.Runtime")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [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 PeakSpectatorMode { internal sealed class BetterPlayerDistanceIntegration { private const string BpdGuid = "com.AiAe.betterplayerdistance"; private const string BpdPluginTypeName = "BetterPlayerDistance.Plugin"; private const string OverlayFieldName = "Overlay"; private const string CanvasFieldName = "_canvas"; private bool _detected; private string _detectedVersion; private FieldInfo _overlayField; private FieldInfo _canvasField; private bool _suppressed; private bool _savedCanvasEnabled = true; internal bool IsLoaded => _detected; internal string DetectedVersion => _detectedVersion; internal void TryDetect() { try { if (!Chainloader.PluginInfos.TryGetValue("com.AiAe.betterplayerdistance", out var value) || value == null || (Object)(object)value.Instance == (Object)null) { L10n.LogDebug("BetterPlayerDistance not detected; skipping BPD2 compatibility (quiet fallback logging).", "BetterPlayerDistance 未检测到,跳过 BPD2 兼容(无噪音降级日志)。"); return; } _detectedVersion = ((value.Metadata != null && value.Metadata.Version != null) ? value.Metadata.Version.ToString() : "(unknown)"); Type type = AccessTools.TypeByName("BetterPlayerDistance.Plugin"); if (type == null) { L10n.LogWarning("BetterPlayerDistance v" + _detectedVersion + " loaded, but type BetterPlayerDistance.Plugin was not found.", "BetterPlayerDistance v" + _detectedVersion + " 已加载,但找不到类型 BetterPlayerDistance.Plugin。"); return; } _overlayField = AccessTools.Field(type, "Overlay"); if (_overlayField == null) { L10n.LogWarning("BetterPlayerDistance v" + _detectedVersion + " loaded, but field BetterPlayerDistance.Plugin.Overlay was not found.", "BetterPlayerDistance v" + _detectedVersion + " 已加载,但找不到字段 BetterPlayerDistance.Plugin.Overlay。"); return; } Type fieldType = _overlayField.FieldType; _canvasField = AccessTools.Field(fieldType, "_canvas"); if (_canvasField == null) { L10n.LogWarning("BetterPlayerDistance v" + _detectedVersion + " loaded, but field _canvas was not found in OverlayManager.", "BetterPlayerDistance v" + _detectedVersion + " 已加载,但 OverlayManager 中找不到 _canvas 字段。"); return; } _detected = true; L10n.LogInfo("BetterPlayerDistance v" + _detectedVersion + " detected; BPD2 compatibility enabled (Canvas.enabled switching mode).", "BetterPlayerDistance v" + _detectedVersion + " 已检测到,BPD2 兼容启用(Canvas.enabled 切换模式)。"); } catch (Exception ex) { _detected = false; L10n.LogWarning("BetterPlayerDistance compatibility detection failed: " + ex.GetType().Name + ": " + ex.Message, "BetterPlayerDistance 兼容检测失败:" + ex.GetType().Name + ": " + ex.Message); } } private Canvas ResolveCanvas() { if (!_detected || _overlayField == null || _canvasField == null) { return null; } try { object value = _overlayField.GetValue(null); if (value == null) { return null; } object? value2 = _canvasField.GetValue(value); return (Canvas)((value2 is Canvas) ? value2 : null); } catch (Exception ex) { L10n.LogDebug("[BPD2 Compat] ResolveCanvas exception: " + ex.GetType().Name + ": " + ex.Message, "[BPD2兼容] ResolveCanvas 异常:" + ex.GetType().Name + ": " + ex.Message); return null; } } internal void Suppress() { if (!_detected || _suppressed || !Configuration.EnableBetterPlayerDistanceIntegration) { return; } Canvas val = ResolveCanvas(); if ((Object)(object)val == (Object)null) { L10n.LogDebug("[BPD2 Compat] Canvas is missing during Suppress (BPD2 may not be initialized yet); skipping.", "[BPD2兼容] Suppress 时 Canvas 不存在(BPD2 可能尚未初始化),跳过。"); return; } try { _savedCanvasEnabled = ((Behaviour)val).enabled; if (((Behaviour)val).enabled) { ((Behaviour)val).enabled = false; } _suppressed = true; L10n.LogInfo($"[BPD2 Compat] Temporarily disabled BPD2 Canvas (saved enabled={_savedCanvasEnabled})", $"[BPD2兼容] 已临时关闭 BPD2 Canvas(暂存 enabled={_savedCanvasEnabled})"); } catch (Exception ex) { L10n.LogWarning("[BPD2 Compat] Suppress failed: " + ex.GetType().Name + ": " + ex.Message, "[BPD2兼容] Suppress 失败:" + ex.GetType().Name + ": " + ex.Message); } } internal void Restore() { if (!_detected || !_suppressed) { return; } Canvas val = ResolveCanvas(); if ((Object)(object)val == (Object)null) { _suppressed = false; L10n.LogDebug("[BPD2 Compat] Canvas is already missing during Restore (scene reload?); marking as reset.", "[BPD2兼容] Restore 时 Canvas 已不存在(Scene 重载?),标记复位。"); return; } try { ((Behaviour)val).enabled = _savedCanvasEnabled; _suppressed = false; L10n.LogInfo($"[BPD2 Compat] Restored BPD2 Canvas.enabled={_savedCanvasEnabled}", $"[BPD2兼容] 已恢复 BPD2 Canvas.enabled={_savedCanvasEnabled}"); } catch (Exception ex) { L10n.LogWarning("[BPD2 Compat] Restore failed: " + ex.GetType().Name + ": " + ex.Message, "[BPD2兼容] Restore 失败:" + ex.GetType().Name + ": " + ex.Message); } } } internal static class CharacterState { internal static bool IsAliveSpectatorTarget(Character character) { if ((Object)(object)character == (Object)null || (Object)(object)((Component)character).gameObject == (Object)null || !((Component)character).gameObject.activeInHierarchy || character.isBot) { return false; } if (!Configuration.DebugMode && (Object)(object)character == (Object)(object)Character.localCharacter) { return false; } return !IsDead(character); } internal static bool IsDead(Character character) { try { return (Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null || character.data.dead; } catch { return true; } } } internal enum SpectatorArrowStyle { RoundedGlass, OutlineGlass } internal static class Configuration { internal static ConfigEntry<KeyCode> ToggleKey; internal static ConfigEntry<KeyCode> ResetKey; internal static ConfigEntry<KeyCode> PreviousPlayerKey; internal static ConfigEntry<KeyCode> NextPlayerKey; internal static ConfigEntry<KeyCode> ToggleOverlayKey; internal static ConfigEntry<KeyCode> PeakTrailsToggleKey; internal static ConfigEntry<KeyCode> ForcedDeathKey; internal static ConfigEntry<float> NormalSpeed; internal static ConfigEntry<float> FastSpeed; internal static ConfigEntry<float> TurnSpeed; internal static ConfigEntry<float> AltSlowSpeedMultiplier; internal static ConfigEntry<float> MoveDamping; internal static ConfigEntry<float> TurnDamping; internal static ConfigEntry<KeyCode> TelescopeKey; internal static ConfigEntry<float> TelescopeMultiplier; internal static ConfigEntry<bool> EnableSoftFollow; internal static ConfigEntry<float> SoftFollowMaxDistance; internal static ConfigEntry<float> NameFontSize; internal static ConfigEntry<float> HeightFontSize; internal static ConfigEntry<float> OverlayOpacity; internal static ConfigEntry<float> LabelTextOpacity; internal static ConfigEntry<SpectatorArrowStyle> HeadArrowStyle; internal static ConfigEntry<bool> ShowFullPeakStatsExInfo; internal static ConfigEntry<float> SpectatorTeammateStaminaDistance; internal static ConfigEntry<KeyCode> OverlayCycleKey; internal static ConfigEntry<LogLanguage> LogLang; internal const float MaxPeakHeightMeters = 1920f; internal static readonly bool DebugMode = true; internal static readonly bool ShowOverlay = true; internal static readonly bool ShowXraySilhouette = true; internal static readonly bool HideHudInFreeCamera = true; internal static readonly bool EnablePeakTrailsCompatibility = true; internal static readonly bool EnablePeakStatsExCompatibility = true; internal static readonly bool ForcePeakStatsExInventoryInFreeCamera = true; internal static readonly bool EnableForcedDeath = true; internal static readonly bool ShowXrayDetailLayer = true; internal static readonly bool EnableSummitRosterCompatibility = true; internal static readonly bool MoveSummitRosterRight = true; internal static readonly bool ShowSummitRosterFocusArrow = true; internal static readonly bool EnableGhostSpectatorIntegration = true; internal static readonly bool EnableBetterPlayerDistanceIntegration = true; internal const KeyCode ResetZoomKey = (KeyCode)325; internal const float ForcedDeathHoldSeconds = 3f; internal const float TelescopeTransitionSpeed = 8f; internal const float LabelTextOffsetY = 0f; internal const float LabelArrowOffsetY = -38f; internal const float LabelScreenPadding = 48f; internal const float LabelDistanceScreenPadding = 36f; internal const float LabelCameraForwardOffset = 0.4f; internal const float FloatAmplitude = 7f; internal const float FloatSpeed = 1.15f; internal const float OverlayFadeSpeed = 5f; internal const float XrayOpacity = 0.34f; internal const float XrayDetailOpacity = 0.16f; internal const float XrayOcclusionCheckInterval = 0.12f; internal static void Initialize(ConfigFile config) { //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Expected O, but got Unknown //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Expected O, but got Unknown //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Expected O, but got Unknown //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Expected O, but got Unknown //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Expected O, but got Unknown //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Expected O, but got Unknown //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Expected O, but got Unknown //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Expected O, but got Unknown //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Expected O, but got Unknown //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Expected O, but got Unknown //IL_03e7: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Expected O, but got Unknown //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_0429: Expected O, but got Unknown //IL_044e: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Invalid comparison between Unknown and I4 //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_046f: Invalid comparison between Unknown and I4 LogLang = config.Bind<LogLanguage>("0. General 常规", "Log Language 日志语言", LogLanguage.Auto, "Language used for the mod's console/log messages. Auto follows the in-game language.\n模组控制台/日志信息使用的语言。Auto 表示跟随游戏内语言。"); ToggleKey = config.Bind<KeyCode>("1. Hotkeys 热键", "Spectator Toggle 观战开关", (KeyCode)284, "Toggle the free spectator camera on/off.\n开启或关闭自由观战相机。"); ResetKey = config.Bind<KeyCode>("1. Hotkeys 热键", "Reset Near Self 重置到自己附近", (KeyCode)285, "Reset the free camera near the local player.\n将自由相机重置到本地玩家附近。"); PreviousPlayerKey = config.Bind<KeyCode>("1. Hotkeys 热键", "Previous Player 上一个玩家", (KeyCode)113, "Snap the free camera near the previous other player.\n将自由相机快速切换到上一个其他玩家附近。"); NextPlayerKey = config.Bind<KeyCode>("1. Hotkeys 热键", "Next Player 下一个玩家", (KeyCode)101, "Snap the free camera near the next other player.\n将自由相机快速切换到下一个其他玩家附近。"); ToggleOverlayKey = config.Bind<KeyCode>("1. Hotkeys 热键", "Temporarily Hide Labels 临时隐藏标记", (KeyCode)102, "Smoothly show/hide player names and altitude in free camera.\n自由相机模式下平滑显示或隐藏玩家名称和海拔。"); OverlayCycleKey = config.Bind<KeyCode>("1. Hotkeys 热键", "Cycle Label Mode 标记显示模式循环", (KeyCode)99, "3-step cycle in free camera: name + arrow -> name only -> hide all -> back to name + arrow.\n自由相机下 3 段循环:名称+箭头 → 仅名称 → 全部隐藏 → 回到名称+箭头。"); PeakTrailsToggleKey = config.Bind<KeyCode>("1. Hotkeys 热键", "PEAKTrails Toggle PEAKTrails轨迹开关", (KeyCode)114, "Toggle PEAKTrails player trails while in free camera.\n自由相机模式下切换 PEAKTrails 玩家轨迹显示或隐藏。"); TelescopeKey = config.Bind<KeyCode>("1. Hotkeys 热键", "Telescope Key 望远镜按键", (KeyCode)120, "Hold to smoothly zoom in the free camera; release to smoothly restore the current scroll zoom.\n按住后平滑放大自由相机视角,松开后平滑恢复到当前滚轮缩放。"); ForcedDeathKey = config.Bind<KeyCode>("1. Hotkeys 热键", "Forced Death Key (Alt+) 强制死亡主按键(Alt+)", (KeyCode)284, "Hold together with Alt to trigger forced death.\n配合 Alt 长按触发强制死亡。"); NormalSpeed = config.Bind<float>("2. Camera 相机", "Normal Speed 普通速度", 12f, new ConfigDescription("Free camera normal move speed.\n自由相机普通移动速度。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 80f), Array.Empty<object>())); FastSpeed = config.Bind<float>("2. Camera 相机", "Shift Speed shift速度", 60f, new ConfigDescription("Move speed while holding Shift.\n按住 Shift 时的移动速度。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>())); TurnSpeed = config.Bind<float>("2. Camera 相机", "Turn Speed 转向速度", 50f, new ConfigDescription("Free camera mouse turn speed.\n自由相机鼠标转向速度。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 80f), Array.Empty<object>())); AltSlowSpeedMultiplier = config.Bind<float>("2. Camera 相机", "Alt Slow Multiplier Alt慢速倍率", 0.33f, new ConfigDescription("Move speed multiplier while holding Alt in F3 free camera; 0.33 = 33%.\nF3 自由相机模式下按住 Alt 时的移动速度倍率,0.33 表示 33%。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>())); MoveDamping = config.Bind<float>("2. Camera 相机", "Move Damping 移动阻尼", 3f, new ConfigDescription("Free camera move damping; higher stops faster.\n自由相机移动阻尼,数值越高停下越快。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>())); TurnDamping = config.Bind<float>("2. Camera 相机", "Turn Damping 转向阻尼", 5f, new ConfigDescription("Free camera turn damping; higher turns more steadily.\n自由相机转向阻尼,数值越高转向越稳。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>())); TelescopeMultiplier = config.Bind<float>("2. Camera 相机", "Telescope Multiplier 望远镜倍率", 5f, new ConfigDescription("Zoom multiplier while holding the telescope key.\n按住望远镜按键时的放大倍率。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 30f), Array.Empty<object>())); EnableSoftFollow = config.Bind<bool>("2. Camera 相机", "Soft Follow After Switch 切换后镜头软跟随玩家", true, "After switching to a player, auto soft-follow once the transition ends: the camera moves with the player; exits when you press any move key (WASD/Space/Ctrl/Q/E) or the camera goes beyond the set distance.\n切换玩家后过渡结束自动进入软跟随:相机随玩家一起移动;按任意位移键 (WASD/Space/Ctrl/Q/E) 或相机距目标超过设定距离时退出跟随。"); SoftFollowMaxDistance = config.Bind<float>("2. Camera 相机", "Soft Follow Max Distance 软跟随最大距离", 20f, new ConfigDescription("Auto-exit soft follow when the camera is farther than this many meters from the target.\n软跟随状态下相机距离目标超过此米数时自动退出。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>())); SpectatorTeammateStaminaDistance = config.Bind<float>("2. Camera 相机", "Free Camera Teammate Stamina Distance 自由相机队友体力条距离", 9999f, new ConfigDescription("Temporarily override the PeakStatsEx teammate stamina bar display distance while in free camera.\n自由相机模式下临时覆盖 PeakStatsEx 队友体力条显示距离。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10000f), Array.Empty<object>())); ShowFullPeakStatsExInfo = config.Bind<bool>("2. Camera 相机", "Show Full PeakStatsEx Info 自由相机显示完整peakstatsex信息", false, "When enabled, F3 free camera no longer hides PeakStatsEx top stats (timer, height, fog/lava, etc.); when disabled it stays minimal.\n开启后,F3 自由相机模式下不再隐藏 PeakStatsEx 的计时、高度、雾/岩浆等顶部统计信息;关闭时保持精简显示。"); NameFontSize = config.Bind<float>("3. Display 显示", "Name Font Size 名字字号", 12f, new ConfigDescription("Player name font size.\n玩家名称字号。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(9f, 60f), Array.Empty<object>())); HeightFontSize = config.Bind<float>("3. Display 显示", "World Altitude Font Size 世界海拔字号", 13f, new ConfigDescription("World altitude font size.\n世界海拔字号。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(9f, 60f), Array.Empty<object>())); OverlayOpacity = config.Bind<float>("3. Display 显示", "Marker Opacity 标记透明度", 0.7f, new ConfigDescription("Opacity of the overhead arrow marker; label text is controlled separately by \"Label Text Opacity\" and the two are not multiplied together.\n头顶箭头标记的不透明度;文字另由“标签文字透明度”独立控制,两者互不相乘。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); LabelTextOpacity = config.Bind<float>("3. Display 显示", "Label Text Opacity 标签文字透明度", 0.8f, new ConfigDescription("Opacity of the overhead label text (including its shadow); independent from \"Marker Opacity\" (arrow) and applied absolutely.\n头顶标签文字(含文字阴影)的不透明度;与“标记透明度”(箭头)相互独立、绝对生效。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); HeadArrowStyle = config.Bind<SpectatorArrowStyle>("3. Display 显示", "Head Arrow Style 头顶箭头样式", SpectatorArrowStyle.RoundedGlass, "RoundedGlass = rounded thick glass-filled arrow; OutlineGlass = outlined glass-filled arrow.\nRoundedGlass 为圆角粗箭头玻璃填充;OutlineGlass 为线框箭头玻璃填充。"); if ((int)PreviousPlayerKey.Value == 91) { PreviousPlayerKey.Value = (KeyCode)113; } if ((int)NextPlayerKey.Value == 93) { NextPlayerKey.Value = (KeyCode)101; } if (Mathf.Approximately(TelescopeMultiplier.Value, 10f)) { TelescopeMultiplier.Value = 5f; } } } internal sealed class ForceDeathController { private readonly MethodInfo _dieMethod = AccessTools.Method(typeof(Character), "Die", (Type[])null, (Type[])null); private GameObject _root; private CanvasGroup _group; private TextMeshProUGUI _text; private float _holdTime; private bool _triggered; internal void Update() { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) if (!Configuration.EnableForcedDeath) { ResetState(); return; } if (Plugin.GsIntegration != null && Plugin.GsIntegration.IsActive) { ResetState(); return; } bool num = IsHoldingCombo(); Character localCharacter = Character.localCharacter; if (!num || (Object)(object)localCharacter == (Object)null || CharacterState.IsDead(localCharacter)) { ResetState(); return; } EnsureUi(); _holdTime += Time.unscaledDeltaTime; float num2 = Mathf.Max(1f, 3f); float num3 = Mathf.Clamp01(_holdTime / num2); _group.alpha = Mathf.MoveTowards(_group.alpha, 1f, Time.unscaledDeltaTime * 8f); ((TMP_Text)_text).text = L10n.Game($"Warning: keep holding Alt+{Configuration.ForcedDeathKey.Value} to force death\n{num3 * num2:0.0}/{num2:0.0}s", $"警告:继续按住 Alt+{Configuration.ForcedDeathKey.Value} 将强制死亡\n{num3 * num2:0.0}/{num2:0.0}s"); if (!_triggered && _holdTime >= num2) { _triggered = true; ForceDie(); ResetState(); } } internal void Dispose() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } } private bool IsHoldingCombo() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307)) { return Input.GetKey(Configuration.ForcedDeathKey.Value); } return false; } private void ForceDie() { try { if (_dieMethod != null) { _dieMethod.Invoke(null, null); } } catch (Exception ex) { L10n.LogWarning("Alt+F3 forced death failed: " + ex.Message, "Alt+F3 强制死亡失败:" + ex.Message); } } private void ResetState() { _holdTime = 0f; _triggered = false; if ((Object)(object)_group != (Object)null) { _group.alpha = Mathf.MoveTowards(_group.alpha, 0f, Time.unscaledDeltaTime * 8f); } } private void EnsureUi() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root != (Object)null)) { _root = new GameObject("PeakSpectatorForceDeathWarning"); Object.DontDestroyOnLoad((Object)(object)_root); _root.layer = 5; Canvas obj = _root.AddComponent<Canvas>(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 1200; CanvasScaler obj2 = _root.AddComponent<CanvasScaler>(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); _group = _root.AddComponent<CanvasGroup>(); _group.alpha = 0f; _group.blocksRaycasts = false; _group.interactable = false; GameObject val = new GameObject("Panel"); val.layer = 5; val.transform.SetParent(_root.transform, false); RectTransform obj3 = val.AddComponent<RectTransform>(); obj3.anchorMin = new Vector2(0.5f, 0.82f); obj3.anchorMax = new Vector2(0.5f, 0.82f); obj3.pivot = new Vector2(0.5f, 0.5f); obj3.sizeDelta = new Vector2(720f, 120f); Image obj4 = val.AddComponent<Image>(); ((Graphic)obj4).color = new Color(0.12f, 0.02f, 0.02f, 0.78f); ((Graphic)obj4).raycastTarget = false; GameObject val2 = new GameObject("Text"); val2.layer = 5; val2.transform.SetParent(val.transform, false); RectTransform obj5 = val2.AddComponent<RectTransform>(); obj5.anchorMin = Vector2.zero; obj5.anchorMax = Vector2.one; obj5.offsetMin = new Vector2(20f, 10f); obj5.offsetMax = new Vector2(-20f, -10f); _text = val2.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_text).alignment = (TextAlignmentOptions)514; ((TMP_Text)_text).fontSize = 28f; ((Graphic)_text).color = new Color(1f, 0.78f, 0.58f, 1f); ((Graphic)_text).raycastTarget = false; ((TMP_Text)_text).textWrappingMode = (TextWrappingModes)0; } } } internal sealed class GhostSpectatorIntegration { private const string GhostSpectatorGuid = "SisyphusMD.GhostSpectator"; private bool _detected; private ConfigEntry<bool> _spectatorEnabledEntry; private string _detectedVersion; internal bool IsLoaded => _detected; internal string DetectedVersion => _detectedVersion; internal bool IsActive { get { //IL_0058: 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) if (!_detected || _spectatorEnabledEntry == null) { return false; } if (!Configuration.EnableGhostSpectatorIntegration) { return false; } if (!_spectatorEnabledEntry.Value) { return false; } Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.data == (Object)null) { return false; } if (!localCharacter.data.fullyPassedOut) { return false; } Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name == "Airport") { return false; } return true; } } internal bool IsCharacterPermaSpectator(Character character) { if (!_detected || (Object)(object)character == (Object)null) { return false; } try { if ((Object)(object)character == (Object)(object)Character.localCharacter) { return IsActive; } CharacterRefs refs = character.refs; if (refs == null) { return false; } PhotonView view = refs.view; if ((Object)(object)view == (Object)null) { return false; } Player owner = view.Owner; if (owner == null) { return false; } IDictionary customProperties = (IDictionary)owner.CustomProperties; if (customProperties == null) { return false; } if (customProperties["GhostSpectator.IsSpectator"] is bool result) { return result; } } catch (Exception ex) { L10n.LogDebug("IsCharacterPermaSpectator exception: " + ex.GetType().Name + ": " + ex.Message, "IsCharacterPermaSpectator 异常:" + ex.GetType().Name + ": " + ex.Message); } return false; } internal void TryDetect() { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown try { if (!Chainloader.PluginInfos.TryGetValue("SisyphusMD.GhostSpectator", out var value) || value == null || (Object)(object)value.Instance == (Object)null) { L10n.LogDebug("GhostSpectator not detected; running in standalone mode (quiet fallback logging).", "GhostSpectator 未检测到,运行在独立模式(无噪音降级日志)。"); return; } _detectedVersion = ((value.Metadata != null && value.Metadata.Version != null) ? value.Metadata.Version.ToString() : "(unknown)"); ConfigFile config = value.Instance.Config; if (config == null) { L10n.LogWarning("GhostSpectator v" + _detectedVersion + " loaded, but its Config is inaccessible; compatibility mode cannot be enabled.", "GhostSpectator v" + _detectedVersion + " 已加载,但其 Config 不可访问,兼容模式无法启用。"); return; } ConfigDefinition val = new ConfigDefinition("Spectator", "Enabled"); ConfigEntry<bool> val2 = default(ConfigEntry<bool>); if (!config.TryGetEntry<bool>(val, ref val2) || val2 == null) { L10n.LogWarning("GhostSpectator v" + _detectedVersion + " loaded, but the Spectator/Enabled config entry was not found. The version may be incompatible.", "GhostSpectator v" + _detectedVersion + " 已加载,但未找到 Spectator/Enabled 配置项。可能是版本不兼容。"); return; } _spectatorEnabledEntry = val2; _detected = true; L10n.LogInfo($"GhostSpectator v{_detectedVersion} detected; compatibility mode enabled. Current SpectatorEnabled value={_spectatorEnabledEntry.Value}.", $"GhostSpectator v{_detectedVersion} 已检测到,兼容模式启用。SpectatorEnabled 当前值={_spectatorEnabledEntry.Value}。"); } catch (Exception ex) { _detected = false; _spectatorEnabledEntry = null; L10n.LogWarning("GhostSpectator compatibility detection failed: " + ex.GetType().Name + ": " + ex.Message + ". Running in standalone mode.", "GhostSpectator 兼容检测失败:" + ex.GetType().Name + ": " + ex.Message + "。运行在独立模式。"); } } } internal enum LogLanguage { Auto, English, Chinese } internal static class L10n { internal static bool GameIsChinese { get { //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_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 Language cURRENT_LANGUAGE = LocalizedText.CURRENT_LANGUAGE; if ((int)cURRENT_LANGUAGE != 9) { return (int)cURRENT_LANGUAGE == 10; } return true; } } internal static bool UseChineseForLogs => ((Configuration.LogLang != null) ? Configuration.LogLang.Value : LogLanguage.Auto) switch { LogLanguage.English => false, LogLanguage.Chinese => true, _ => GameIsChinese, }; internal static string Game(string en, string zh) { if (!GameIsChinese) { return en; } return zh; } internal static void LogInfo(string en, string zh) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)(UseChineseForLogs ? zh : en)); } } internal static void LogWarning(string en, string zh) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)(UseChineseForLogs ? zh : en)); } } internal static void LogError(string en, string zh) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)(UseChineseForLogs ? zh : en)); } } internal static void LogDebug(string en, string zh) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)(UseChineseForLogs ? zh : en)); } } } internal sealed class PeakStatsExCompatibility { private struct InventoryOverrideState { internal RuntimeOverrideToken<bool> SlotsToken; internal PeakStatsExInfoOverrideState InfoState; } private struct PeakStatsExInfoOverrideState { internal RuntimeOverrideToken<bool> DisplayTimerToken; internal RuntimeOverrideToken<bool> DisplayHeightToken; internal RuntimeOverrideToken<bool> DisplayLevelToken; internal RuntimeOverrideToken<bool> DisplayBiomesToken; internal RuntimeOverrideToken<bool> DisplayDayNightCountdownToken; internal RuntimeOverrideToken<bool> DisplayFogToken; internal RuntimeOverrideToken<bool> DisplayLavaToken; internal RuntimeOverrideToken<bool> DisplayTerrainRandomiserSeedToken; internal RuntimeOverrideToken<bool> DisplayTerrainCustomiserSeedToken; internal RuntimeOverrideToken<bool> ShowStaminaInfoToken; internal RuntimeOverrideToken<bool> StaminaInfoShowAfflictionCountdownToken; } private sealed class ConfigValue<T> { private readonly object _entry; private readonly PropertyInfo _valueProperty; private readonly FieldInfo _typedValueField; internal bool IsValid { get { if (_entry != null) { return _valueProperty != null; } return false; } } internal object EntryObject => _entry; internal ConfigValue(object entry) { _entry = entry; if (_entry != null) { _valueProperty = _entry.GetType().GetProperty("Value"); _typedValueField = AccessTools.Field(_entry.GetType(), "_typedValue"); } } internal T Get(T fallback) { if (_entry == null) { return fallback; } object obj = ((_typedValueField != null) ? _typedValueField.GetValue(_entry) : _valueProperty?.GetValue(_entry, null)); if (obj is T) { return (T)obj; } return fallback; } internal void Set(T value) { if (_entry != null) { if (_typedValueField != null) { _typedValueField.SetValue(_entry, value); } else if (_entry is ConfigEntry<T> val) { val.Value = value; } else { _valueProperty?.SetValue(_entry, value, null); } } } } private readonly Harmony _harmony; private readonly RuntimeOverrideManager _overrides = new RuntimeOverrideManager(); private ConfigValue<float> _proximityDistance; private ConfigValue<bool> _displayTimer; private ConfigValue<bool> _displayHeight; private ConfigValue<bool> _displayLevel; private ConfigValue<bool> _displayBiomes; private ConfigValue<bool> _displayDayNightCountdown; private ConfigValue<bool> _displayFog; private ConfigValue<bool> _displayLava; private ConfigValue<bool> _displayTerrainRandomiserSeed; private ConfigValue<bool> _displayTerrainCustomiserSeed; private ConfigValue<bool> _showInventorySlots; private ConfigValue<bool> _showStaminaInfo; private ConfigValue<bool> _staminaInfoShowAfflictionCountdown; private FieldInfo _staminaBarsField; private PropertyInfo _observedCharacterProperty; private FieldInfo _isEnabledField; private FieldInfo _animateDisableCoroutineField; private object _lastProximityManager; private bool _initialized; private bool _initAttempted; private bool _loggedMissing; private bool _fullInfoOverrideActive; private PeakStatsExInfoOverrideState _fullInfoState; private bool _wasSpectatorActive; private float _clearInventoryUntil; internal PeakStatsExCompatibility(Harmony harmony) { _harmony = harmony; } internal void Update(bool spectatorActive) { if (!Configuration.EnablePeakStatsExCompatibility) { Restore(); _wasSpectatorActive = spectatorActive; return; } EnsureInitialized(); if (!spectatorActive) { if (_wasSpectatorActive) { _clearInventoryUntil = Time.time + 1.5f; } Restore(); ClearResidualInventoryIfNeeded(); _wasSpectatorActive = false; } else { _wasSpectatorActive = true; UpdateFullPeakStatsExInfoOverride(); } } internal void Restore() { _overrides.ReleaseAll(); _fullInfoOverrideActive = false; _fullInfoState = default(PeakStatsExInfoOverrideState); } private void EnsureInitialized() { if (_initialized || _initAttempted) { return; } Type type = AccessTools.TypeByName("PeakStatsEx.PluginConfig"); if (type == null) { _initAttempted = true; LogMissingOnce(); return; } _proximityDistance = CreateConfigValue<float>(type, "TeammateStaminaBarProximity"); if (_proximityDistance == null) { _initAttempted = true; LogMissingOnce(); return; } _displayTimer = CreateConfigValue<bool>(type, "DisplayTimer"); _displayHeight = CreateConfigValue<bool>(type, "DisplayHeight"); _displayLevel = CreateConfigValue<bool>(type, "DisplayLevel"); _displayBiomes = CreateConfigValue<bool>(type, "DisplayBiomes"); _displayDayNightCountdown = CreateConfigValue<bool>(type, "DisplayDayNightCountdown"); _displayFog = CreateConfigValue<bool>(type, "DisplayFog"); _displayLava = CreateConfigValue<bool>(type, "DisplayLava"); _displayTerrainRandomiserSeed = CreateConfigValue<bool>(type, "DisplayTerrainRandomiserSeed"); _displayTerrainCustomiserSeed = CreateConfigValue<bool>(type, "DisplayTerrainCustomiserSeed"); _showInventorySlots = CreateConfigValue<bool>(type, "ShowInventorySlots"); _showStaminaInfo = CreateConfigValue<bool>(type, "ShowStaminaInfo"); _staminaInfoShowAfflictionCountdown = CreateConfigValue<bool>(type, "StaminaInfoShowAfflictionCountdown"); Type type2 = AccessTools.TypeByName("PeakStatsEx.MonoBehaviours.ProximityStaminaManager"); _staminaBarsField = ((type2 != null) ? AccessTools.Field(type2, "staminaBars") : null); Type type3 = AccessTools.TypeByName("PeakStatsEx.MonoBehaviours.CharacterStaminaBar"); _observedCharacterProperty = ((type3 != null) ? AccessTools.Property(type3, "ObservedCharacter") : null); _isEnabledField = ((type3 != null) ? AccessTools.Field(type3, "isEnabled") : null); _animateDisableCoroutineField = ((type3 != null) ? AccessTools.Field(type3, "animateDisableCoroutine") : null); TryPatchPeakStatsEx(); _initialized = true; L10n.LogInfo("PeakStatsEx free-camera stamina bar distance compatibility enabled.", "已启用 PeakStatsEx 自由相机体力条距离兼容。"); } private void TryPatchPeakStatsEx() { PatchMethod("PeakStatsEx.MonoBehaviours.ProximityStaminaManager", "Update", "ProximityManagerUpdatePrefix", "ProximityManagerUpdatePostfix"); PatchMethod("PeakStatsEx.MonoBehaviours.TimerHeightStats", "Update", "TimerHeightStatsUpdatePrefix", "TimerHeightStatsUpdatePostfix"); PatchMethod("PeakStatsEx.MonoBehaviours.MapStats", "Update", "MapStatsUpdatePrefix", "MapStatsUpdatePostfix"); PatchMethod("PeakStatsEx.MonoBehaviours.CharacterStaminaBar", "Update", "CharacterStaminaBarUpdatePrefix", "CharacterStaminaBarUpdatePostfix"); PatchMethod("StaminaBar", "Update", "StaminaBarUpdatePrefix", "StaminaBarUpdatePostfix"); } private void PatchMethod(string typeName, string methodName, string prefixName, string postfixName) { //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) //IL_007a: Expected O, but got Unknown //IL_007a: Expected O, but got Unknown Type type = AccessTools.TypeByName(typeName); MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, methodName, (Type[])null, (Type[])null) : null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PeakStatsExCompatibility), prefixName, (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(PeakStatsExCompatibility), postfixName, (Type[])null, (Type[])null); if (methodInfo != null && methodInfo2 != null && methodInfo3 != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), new HarmonyMethod(methodInfo3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private bool ShouldOverrideDistance() { if (Configuration.EnablePeakStatsExCompatibility && Plugin.CameraController != null && Plugin.CameraController.IsActive) { return _proximityDistance != null; } return false; } private bool ShouldHidePeakStatsExExtras() { if (Configuration.EnablePeakStatsExCompatibility && !Configuration.ShowFullPeakStatsExInfo.Value) { return SpectatorHudManager.ShouldHideHud(); } return false; } private bool ShouldShowFullPeakStatsExInfo() { if (Configuration.EnablePeakStatsExCompatibility && Configuration.ShowFullPeakStatsExInfo.Value && Plugin.CameraController != null) { return Plugin.CameraController.IsActive; } return false; } private bool ShouldForceInventoryInFreeCamera() { if (Configuration.EnablePeakStatsExCompatibility && Configuration.ForcePeakStatsExInventoryInFreeCamera && Plugin.CameraController != null) { return Plugin.CameraController.IsActive; } return false; } private void UpdateFullPeakStatsExInfoOverride() { if (ShouldShowFullPeakStatsExInfo()) { if (!_fullInfoOverrideActive) { _fullInfoState = BeginFullPeakStatsExInfoOverride(); _fullInfoOverrideActive = true; } } else if (_fullInfoOverrideActive) { EndPeakStatsExInfoOverride(_fullInfoState); _fullInfoState = default(PeakStatsExInfoOverrideState); _fullInfoOverrideActive = false; } } private RuntimeOverrideToken<float> BeginTemporaryDistanceOverride() { if (_proximityDistance == null) { return RuntimeOverrideToken<float>.Inactive; } return _overrides.Apply(GetOverrideKey(_proximityDistance), () => _proximityDistance.Get(30f), delegate(float value) { _proximityDistance.Set(value); }, Configuration.SpectatorTeammateStaminaDistance.Value); } private void EndTemporaryDistanceOverride(RuntimeOverrideToken<float> token) { token.Release(); } private RuntimeOverrideToken<bool> BeginBoolOverride(ConfigValue<bool> entry, bool value) { if (entry == null) { return RuntimeOverrideToken<bool>.Inactive; } return _overrides.Apply(GetOverrideKey(entry), () => entry.Get(fallback: true), delegate(bool current) { entry.Set(current); }, value); } private void EndBoolOverride(RuntimeOverrideToken<bool> token) { token.Release(); } private InventoryOverrideState BeginInventoryOverride() { InventoryOverrideState result = default(InventoryOverrideState); if (_showInventorySlots != null) { result.SlotsToken = _overrides.Apply(GetOverrideKey(_showInventorySlots), () => _showInventorySlots.Get(fallback: false), delegate(bool value) { _showInventorySlots.Set(value); }, value: true); } return result; } private void EndInventoryOverride(InventoryOverrideState state) { state.SlotsToken.Release(); EndPeakStatsExInfoOverride(state.InfoState); } private PeakStatsExInfoOverrideState BeginCompactPeakStatsExInfoOverride() { return new PeakStatsExInfoOverrideState { DisplayHeightToken = BeginBoolOverride(_displayHeight, value: false) }; } private PeakStatsExInfoOverrideState BeginFullPeakStatsExInfoOverride() { return new PeakStatsExInfoOverrideState { DisplayTimerToken = BeginBoolOverride(_displayTimer, value: true), DisplayHeightToken = BeginBoolOverride(_displayHeight, value: true), DisplayLevelToken = BeginBoolOverride(_displayLevel, value: true), DisplayBiomesToken = BeginBoolOverride(_displayBiomes, value: true), DisplayDayNightCountdownToken = BeginBoolOverride(_displayDayNightCountdown, value: true), DisplayFogToken = BeginBoolOverride(_displayFog, value: true), DisplayLavaToken = BeginBoolOverride(_displayLava, value: true), DisplayTerrainRandomiserSeedToken = BeginBoolOverride(_displayTerrainRandomiserSeed, value: true), DisplayTerrainCustomiserSeedToken = BeginBoolOverride(_displayTerrainCustomiserSeed, value: true), ShowStaminaInfoToken = BeginBoolOverride(_showStaminaInfo, value: true), StaminaInfoShowAfflictionCountdownToken = BeginBoolOverride(_staminaInfoShowAfflictionCountdown, value: true) }; } private void EndPeakStatsExInfoOverride(PeakStatsExInfoOverrideState state) { state.DisplayTimerToken.Release(); state.DisplayHeightToken.Release(); state.DisplayLevelToken.Release(); state.DisplayBiomesToken.Release(); state.DisplayDayNightCountdownToken.Release(); state.DisplayFogToken.Release(); state.DisplayLavaToken.Release(); state.DisplayTerrainRandomiserSeedToken.Release(); state.DisplayTerrainCustomiserSeedToken.Release(); state.ShowStaminaInfoToken.Release(); state.StaminaInfoShowAfflictionCountdownToken.Release(); } private static object GetOverrideKey<T>(ConfigValue<T> entry) { return entry?.EntryObject; } private bool TryDisableDeadStaminaBar(object characterStaminaBar) { Character observedCharacter = GetObservedCharacter(characterStaminaBar); if ((Object)(object)observedCharacter == (Object)null || !CharacterState.IsDead(observedCharacter)) { return false; } ForceDisableStaminaBar(characterStaminaBar); return true; } private void HideDeadStaminaBars(object proximityManager) { TrackProximityManager(proximityManager); if (!Configuration.EnablePeakStatsExCompatibility || proximityManager == null || _staminaBarsField == null || !(_staminaBarsField.GetValue(proximityManager) is IDictionary dictionary)) { return; } foreach (DictionaryEntry item in dictionary) { object key = item.Key; Character val = (Character)((key is Character) ? key : null); if ((Object)(object)val != (Object)null && CharacterState.IsDead(val)) { ForceDisableStaminaBar(item.Value); } } } private Character GetObservedCharacter(object characterStaminaBar) { if (characterStaminaBar == null || _observedCharacterProperty == null) { return null; } object? value = _observedCharacterProperty.GetValue(characterStaminaBar, null); return (Character)((value is Character) ? value : null); } private void ForceDisableStaminaBar(object characterStaminaBar) { if (characterStaminaBar != null) { object obj = ((characterStaminaBar is MonoBehaviour) ? characterStaminaBar : null); if (obj != null) { ((MonoBehaviour)obj).StopAllCoroutines(); } _isEnabledField?.SetValue(characterStaminaBar, false); _animateDisableCoroutineField?.SetValue(characterStaminaBar, null); Component val = (Component)((characterStaminaBar is Component) ? characterStaminaBar : null); if ((Object)(object)val != (Object)null && (Object)(object)val.gameObject != (Object)null && val.gameObject.activeSelf) { val.gameObject.SetActive(false); } } } private void ClearInventorySlots(object characterStaminaBar) { if (characterStaminaBar != null) { ClearSlotList(characterStaminaBar, "inventorySlotUIs"); ClearSlotList(characterStaminaBar, "backpackSlotUIs"); ClearInventorySlot(AccessTools.Field(characterStaminaBar.GetType(), "heldItemSlot")?.GetValue(characterStaminaBar)); } } private void TrackProximityManager(object proximityManager) { if (proximityManager != null) { _lastProximityManager = proximityManager; } } private void ClearResidualInventoryIfNeeded() { if (!(Time.time > _clearInventoryUntil) && (_showInventorySlots == null || !_showInventorySlots.Get(fallback: false))) { ClearInventorySlotsFromManager(_lastProximityManager); } } private void ClearInventorySlotsFromManager(object proximityManager) { if (proximityManager == null || _staminaBarsField == null || !(_staminaBarsField.GetValue(proximityManager) is IDictionary dictionary)) { return; } foreach (DictionaryEntry item in dictionary) { ClearInventorySlots(item.Value); } } private static void ClearSlotList(object owner, string fieldName) { if (!(AccessTools.Field(owner.GetType(), fieldName)?.GetValue(owner) is IEnumerable enumerable)) { return; } foreach (object item in enumerable) { ClearInventorySlot(item); } } private static void ClearInventorySlot(object slot) { if (slot == null) { return; } MethodInfo methodInfo = AccessTools.Method(slot.GetType(), "Clear", (Type[])null, (Type[])null); if (methodInfo == null) { return; } try { methodInfo.Invoke(slot, null); } catch (TargetInvocationException ex) when (ex.InnerException is NullReferenceException || ex.InnerException is MissingReferenceException) { } catch (NullReferenceException) { } catch (MissingReferenceException) { } } private static ConfigValue<T> CreateConfigValue<T>(Type configType, string propertyName) { object obj = AccessTools.Property(configType, propertyName)?.GetValue(null, null); if (obj == null) { return null; } ConfigValue<T> configValue = new ConfigValue<T>(obj); if (!configValue.IsValid) { return null; } return configValue; } private void LogMissingOnce() { if (!_loggedMissing) { _loggedMissing = true; L10n.LogInfo("No compatible PeakStatsEx version detected (1.2.0 / 1.2.1); skipped stamina bar distance compatibility.", "未检测到可兼容的 PeakStatsEx(1.2.0 / 1.2.1),已跳过体力条距离兼容。"); } } private static void ProximityManagerUpdatePrefix(out RuntimeOverrideToken<float> __state) { __state = RuntimeOverrideToken<float>.Inactive; if (Plugin.PeakStatsEx != null && Plugin.PeakStatsEx.ShouldOverrideDistance()) { __state = Plugin.PeakStatsEx.BeginTemporaryDistanceOverride(); } } private static void ProximityManagerUpdatePostfix(object __instance, RuntimeOverrideToken<float> __state) { if (Plugin.PeakStatsEx != null) { Plugin.PeakStatsEx.EndTemporaryDistanceOverride(__state); Plugin.PeakStatsEx.HideDeadStaminaBars(__instance); } } private static void TimerHeightStatsUpdatePrefix(out PeakStatsExInfoOverrideState __state) { __state = default(PeakStatsExInfoOverrideState); if (Plugin.PeakStatsEx != null) { if (Plugin.PeakStatsEx.ShouldShowFullPeakStatsExInfo()) { __state = Plugin.PeakStatsEx.BeginFullPeakStatsExInfoOverride(); } else if (Plugin.PeakStatsEx.ShouldHidePeakStatsExExtras()) { __state = Plugin.PeakStatsEx.BeginCompactPeakStatsExInfoOverride(); } } } private static void TimerHeightStatsUpdatePostfix(PeakStatsExInfoOverrideState __state) { if (Plugin.PeakStatsEx != null) { Plugin.PeakStatsEx.EndPeakStatsExInfoOverride(__state); } } private static void MapStatsUpdatePrefix(out PeakStatsExInfoOverrideState __state) { __state = default(PeakStatsExInfoOverrideState); if (Plugin.PeakStatsEx != null && Plugin.PeakStatsEx.ShouldShowFullPeakStatsExInfo()) { __state = Plugin.PeakStatsEx.BeginFullPeakStatsExInfoOverride(); } } private static void MapStatsUpdatePostfix(PeakStatsExInfoOverrideState __state) { if (Plugin.PeakStatsEx != null) { Plugin.PeakStatsEx.EndPeakStatsExInfoOverride(__state); } } private static void StaminaBarUpdatePrefix(out PeakStatsExInfoOverrideState __state) { __state = default(PeakStatsExInfoOverrideState); if (Plugin.PeakStatsEx != null && Plugin.PeakStatsEx.ShouldShowFullPeakStatsExInfo()) { __state = Plugin.PeakStatsEx.BeginFullPeakStatsExInfoOverride(); } } private static void StaminaBarUpdatePostfix(PeakStatsExInfoOverrideState __state) { if (Plugin.PeakStatsEx != null) { Plugin.PeakStatsEx.EndPeakStatsExInfoOverride(__state); } } private static bool CharacterStaminaBarUpdatePrefix(object __instance, out InventoryOverrideState __state) { __state = default(InventoryOverrideState); if (Plugin.PeakStatsEx == null) { return true; } if (Plugin.PeakStatsEx.TryDisableDeadStaminaBar(__instance)) { return false; } if (Plugin.PeakStatsEx.ShouldForceInventoryInFreeCamera()) { __state = Plugin.PeakStatsEx.BeginInventoryOverride(); } if (Plugin.PeakStatsEx.ShouldShowFullPeakStatsExInfo()) { __state.InfoState = Plugin.PeakStatsEx.BeginFullPeakStatsExInfoOverride(); } return true; } private static void CharacterStaminaBarUpdatePostfix(InventoryOverrideState __state) { if (Plugin.PeakStatsEx != null) { Plugin.PeakStatsEx.EndInventoryOverride(__state); } } } internal sealed class PeakTrailsCompatibility { private readonly Harmony _harmony; private FieldInfo _showTrailsField; private bool _initialized; private bool _initAttempted; private bool _available; private bool _overrideVisible; private bool _loggedMissing; internal bool ShouldControlTrails { get { if (Configuration.EnablePeakTrailsCompatibility && _available && Plugin.CameraController != null) { return Plugin.CameraController.IsActive; } return false; } } internal PeakTrailsCompatibility(Harmony harmony) { _harmony = harmony; } internal void UpdateInput(bool spectatorActive) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (!Configuration.EnablePeakTrailsCompatibility) { _overrideVisible = false; return; } EnsureInitialized(); if (!_available) { return; } if (!spectatorActive) { _overrideVisible = false; return; } if (Input.GetKeyDown(Configuration.PeakTrailsToggleKey.Value)) { _overrideVisible = !_overrideVisible; } ApplySpectatorTrailState(); } internal void ApplySpectatorTrailState() { SetShowTrails(_overrideVisible); } private void EnsureInitialized() { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown if (_initialized || _initAttempted) { return; } Type type = AccessTools.TypeByName("PEAKTrails.Patching+PlayerVisualUpdatePatch"); if (type == null) { _initAttempted = true; LogMissingOnce(); return; } _initialized = true; _showTrailsField = AccessTools.Field(type, "ShowTrails"); MethodInfo methodInfo = AccessTools.Method(type, "UpdateLocalTrailControls", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PeakTrailsCompatibility), "UpdateLocalTrailControlsPrefix", (Type[])null, (Type[])null); if (_showTrailsField == null || methodInfo == null || methodInfo2 == null) { _initAttempted = true; LogMissingOnce(); } else { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _available = true; L10n.LogInfo("PEAKTrails free-camera trail compatibility enabled. Use the configured key to toggle trail display in the spectator camera.", "已启用 PEAKTrails 自由相机轨迹兼容。按配置按键可在观战相机中切换轨迹显示。"); } } private void SetShowTrails(bool value) { try { _showTrailsField?.SetValue(null, value); } catch { } } private void LogMissingOnce() { if (!_loggedMissing) { _loggedMissing = true; L10n.LogInfo("No compatible PEAKTrails 1.1.3 detected; skipped trail compatibility.", "未检测到可兼容的 PEAKTrails 1.1.3,已跳过轨迹兼容。"); } } private static bool UpdateLocalTrailControlsPrefix() { if (Plugin.PeakTrails != null && Plugin.PeakTrails.ShouldControlTrails) { Plugin.PeakTrails.ApplySpectatorTrailState(); return false; } return true; } } [BepInPlugin("com.AiAe.peakspectatormode", "PeakSpectatorMode", "1.1.1")] public sealed class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; internal static SpectatorCameraController CameraController; internal static SpectatorOverlay Overlay; internal static XraySilhouetteManager Xray; internal static PeakTrailsCompatibility PeakTrails; internal static PeakStatsExCompatibility PeakStatsEx; internal static SummitRosterCompatibility SummitRoster; internal static SpectatorHudManager HudManager; internal static ForceDeathController ForceDeath; internal static GhostSpectatorIntegration GsIntegration; internal static BetterPlayerDistanceIntegration BpdIntegration; private Harmony _harmony; private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Configuration.Initialize(((BaseUnityPlugin)this).Config); _harmony = new Harmony("com.AiAe.peakspectatormode"); _harmony.PatchAll(); CameraController = new SpectatorCameraController(); Overlay = new SpectatorOverlay(); Xray = new XraySilhouetteManager(); PeakTrails = new PeakTrailsCompatibility(_harmony); PeakStatsEx = new PeakStatsExCompatibility(_harmony); SummitRoster = new SummitRosterCompatibility(_harmony); HudManager = new SpectatorHudManager(); ForceDeath = new ForceDeathController(); GsIntegration = new GhostSpectatorIntegration(); GsIntegration.TryDetect(); BpdIntegration = new BetterPlayerDistanceIntegration(); BpdIntegration.TryDetect(); L10n.LogInfo("PeakSpectatorMode v1.1.1 loaded.", "更好的观战视角 v1.1.1 已加载。"); } private void Start() { Overlay.TryInitialize(); } private void Update() { CameraController.UpdateInput(); Overlay.UpdateInput(CameraController.IsActive); PeakTrails.UpdateInput(CameraController.IsActive); PeakStatsEx.Update(CameraController.IsActive); ForceDeath.Update(); } private void LateUpdate() { CameraController.LateUpdate(); CameraController.UpdateSoftFollow(); Overlay.LateUpdate(CameraController.IsActive); Xray.LateUpdate(CameraController.IsActive); HudManager.LateUpdate(CameraController.IsActive); } private void OnDestroy() { CameraController.SetActive(active: false); BpdIntegration?.Restore(); HudManager.Restore(); PeakStatsEx.Restore(); SummitRoster?.Dispose(); ForceDeath.Dispose(); Overlay.Dispose(); Xray.Dispose(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } [HarmonyPatch(typeof(Character))] internal static class CharacterPatches { [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePostfix(Character __instance) { Plugin.Overlay?.RegisterCharacter(__instance); Plugin.Xray?.RegisterCharacter(__instance); } [HarmonyPatch("OnDestroy")] [HarmonyPostfix] private static void OnDestroyPostfix(Character __instance) { Plugin.Overlay?.UnregisterCharacter(__instance); Plugin.Xray?.UnregisterCharacter(__instance); } } [HarmonyPatch(typeof(GodCam), "DoFOV")] internal static class GodCamFovPatch { [HarmonyPrefix] private static bool Prefix(GodCam __instance, Transform transform, MainCamera cam) { if (Plugin.CameraController != null) { return !Plugin.CameraController.TryOverrideGodCamFov(__instance, transform, cam); } return true; } } [HarmonyPatch(typeof(GUIManager))] internal static class GuiManagerHudPatches { [HarmonyPatch("UpdateDyingBar")] [HarmonyPrefix] [HarmonyPriority(0)] private static bool UpdateDyingBarPrefix(GUIManager __instance) { return HideAndSkipIfNeeded(__instance); } [HarmonyPatch("UpdateSpectate")] [HarmonyPrefix] [HarmonyPriority(0)] private static bool UpdateSpectatePrefix(GUIManager __instance) { return HideAndSkipIfNeeded(__instance); } [HarmonyPatch("UpdateItems")] [HarmonyPrefix] [HarmonyPriority(0)] private static bool UpdateItemsPrefix(GUIManager __instance) { return HideAndSkipIfNeeded(__instance); } [HarmonyPatch("UpdateItemPrompts")] [HarmonyPrefix] [HarmonyPriority(0)] private static bool UpdateItemPromptsPrefix(GUIManager __instance) { return HideAndSkipIfNeeded(__instance); } private static bool HideAndSkipIfNeeded(GUIManager gui) { if (!SpectatorHudManager.ShouldHideHud()) { return true; } Plugin.HudManager?.HideGuiElements(gui); return false; } } internal sealed class RuntimeOverrideManager { private interface IRuntimeOverride { int RefCount { get; } void AddRef(); void ReleaseRef(); void Restore(); } private sealed class RuntimeOverride<T> : IRuntimeOverride { private readonly Action<T> _setter; private readonly T _original; private int _refCount; public int RefCount => _refCount; internal RuntimeOverride(Func<T> getter, Action<T> setter) { _setter = setter; _original = getter(); } public void AddRef() { _refCount++; } public void ReleaseRef() { if (_refCount > 0) { _refCount--; } } internal void Set(T value) { _setter(value); } public void Restore() { _setter(_original); _refCount = 0; } } private readonly Dictionary<object, IRuntimeOverride> _overrides = new Dictionary<object, IRuntimeOverride>(); internal RuntimeOverrideToken<T> Apply<T>(object key, Func<T> getter, Action<T> setter, T value) { if (key == null || getter == null || setter == null) { return RuntimeOverrideToken<T>.Inactive; } if (!_overrides.TryGetValue(key, out var value2)) { value2 = new RuntimeOverride<T>(getter, setter); _overrides.Add(key, value2); } if (!(value2 is RuntimeOverride<T> runtimeOverride)) { return RuntimeOverrideToken<T>.Inactive; } runtimeOverride.AddRef(); runtimeOverride.Set(value); return new RuntimeOverrideToken<T>(this, key, active: true); } internal void Release<T>(RuntimeOverrideToken<T> token) { if (token.Active && token.Key != null && _overrides.TryGetValue(token.Key, out var value)) { value.ReleaseRef(); if (value.RefCount <= 0) { value.Restore(); _overrides.Remove(token.Key); } } } internal void ReleaseAll() { foreach (IRuntimeOverride value in _overrides.Values) { value.Restore(); } _overrides.Clear(); } } internal struct RuntimeOverrideToken<T> { internal static readonly RuntimeOverrideToken<T> Inactive = new RuntimeOverrideToken<T>(null, null, active: false); private readonly RuntimeOverrideManager _manager; internal object Key { get; } internal bool Active { get; } internal RuntimeOverrideToken(RuntimeOverrideManager manager, object key, bool active) { _manager = manager; Key = key; Active = active; } internal void Release() { _manager?.Release(this); } } internal sealed class SpectatorCameraController { private const float MaxCameraPitch = 89.5f; private const float MinSwitchDuration = 0.2f; private const float MaxSwitchDuration = 0.5f; private const float MaxSwitchDistance = 80f; private const float EaseEdgeRatio = 0.25f; private const float AltSlowTransitionSpeed = 10f; private readonly FieldInfo _isGodCamField = AccessTools.Field(typeof(MainCameraMovement), "isGodCam"); private readonly FieldInfo _lookDataField = AccessTools.Field(typeof(GodCam), "lookData"); private readonly FieldInfo _targetFovField = AccessTools.Field(typeof(GodCam), "targetFov"); private readonly FieldInfo _forceField = AccessTools.Field(typeof(GodCam), "force"); private readonly FieldInfo _dragField = AccessTools.Field(typeof(GodCam), "drag"); private readonly FieldInfo _lookSensField = AccessTools.Field(typeof(GodCam), "lookSens"); private readonly FieldInfo _lookDragField = AccessTools.Field(typeof(GodCam), "lookDrag"); private Character _focusedPlayer; private bool _switchTransitionActive; private Vector3 _switchStartPosition; private Vector3 _switchTargetPosition; private Quaternion _switchStartRotation; private Quaternion _switchTargetRotation; private float _switchElapsed; private float _switchDuration; private bool _hasFovState; private float _defaultFov = 70f; private float _scrollFovTarget = 70f; private bool _followActive; private Character _followTarget; private Vector3 _followTargetPosSnapshot; private float _altSlowMultiplier = 1f; internal bool IsActive { get; private set; } internal Character FollowingTarget { get { if (!_followActive || !((Object)(object)_followTarget != (Object)null) || !CharacterState.IsAliveSpectatorTarget(_followTarget)) { return null; } return _followTarget; } } internal Character FocusedPlayer { get { if (!IsActive || !((Object)(object)_focusedPlayer != (Object)null) || !CharacterState.IsAliveSpectatorTarget(_focusedPlayer)) { return null; } return _focusedPlayer; } } internal void UpdateInput() { //IL_0005: 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_007c: 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) if (Input.GetKeyDown(Configuration.ToggleKey.Value) && !Input.GetKey((KeyCode)308) && !Input.GetKey((KeyCode)307)) { SetActive(!IsActive); } if (IsActive && Input.GetKeyDown((KeyCode)27)) { SetActive(active: false); } if (IsActive && Input.GetKeyDown(Configuration.ResetKey.Value)) { ResetToLocalPlayer(); } if (IsActive && Input.GetKeyDown(Configuration.PreviousPlayerKey.Value)) { CycleFocusedPlayer(-1); } if (IsActive && Input.GetKeyDown(Configuration.NextPlayerKey.Value)) { CycleFocusedPlayer(1); } if (IsActive) { ApplyGodCamSettings(); } } internal void LateUpdate() { UpdateSwitchTransition(); } internal void SetActive(bool active) { bool isActive = IsActive; MainCameraMovement instance = Singleton<MainCameraMovement>.Instance; if ((Object)(object)instance == (Object)null) { IsActive = false; _focusedPlayer = null; return; } IsActive = active; _isGodCamField?.SetValue(instance, active); if (active) { if (!isActive) { InitializeFovState(); } SyncGodCamState(instance); ResetCursorForCamera(); } else { _hasFovState = false; _focusedPlayer = null; _switchTransitionActive = false; _followActive = false; _followTarget = null; _altSlowMultiplier = 1f; } } private void ApplyGodCamSettings() { MainCameraMovement instance = Singleton<MainCameraMovement>.Instance; if (instance?.godcam != null) { float num = (Input.GetKey((KeyCode)304) ? Mathf.Max(Configuration.NormalSpeed.Value, Configuration.FastSpeed.Value / 10f) : Configuration.NormalSpeed.Value); float num2 = (IsAltHeld() ? Mathf.Clamp(Configuration.AltSlowSpeedMultiplier.Value, 0.05f, 1f) : 1f); _altSlowMultiplier = Mathf.Lerp(_altSlowMultiplier, num2, Time.unscaledDeltaTime * 10f); _forceField?.SetValue(instance.godcam, num * _altSlowMultiplier); _dragField?.SetValue(instance.godcam, Configuration.MoveDamping.Value); _lookSensField?.SetValue(instance.godcam, Configuration.TurnSpeed.Value); _lookDragField?.SetValue(instance.godcam, Configuration.TurnDamping.Value); } } private static bool IsAltHeld() { if (!Input.GetKey((KeyCode)308)) { return Input.GetKey((KeyCode)307); } return true; } internal bool TryOverrideGodCamFov(GodCam godCam, Transform cameraTransform, MainCamera mainCamera) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) if (!IsActive || godCam == null || (Object)(object)mainCamera == (Object)null || (Object)(object)mainCamera.cam == (Object)null) { return false; } ClampGodCamPitch(godCam, cameraTransform); EnsureFovState(mainCamera.cam); float num = Mathf.Clamp(mainCamera.cam.fieldOfView, 1f, 120f); float num2 = Mathf.Lerp(num / 70f, 1f, 0.25f); _scrollFovTarget += (0f - Input.mouseScrollDelta.y) * 2f * num2; _scrollFovTarget = Mathf.Clamp(_scrollFovTarget, 1f, 120f); if (Input.GetKeyDown((KeyCode)325)) { _scrollFovTarget = Mathf.Clamp(_defaultFov, 1f, 120f); } float num3 = _scrollFovTarget; if (Input.GetKey(Configuration.TelescopeKey.Value)) { num3 = CalculateZoomFov(_scrollFovTarget, Configuration.TelescopeMultiplier.Value); } float num4 = Mathf.Max(0.01f, 8f); mainCamera.cam.fieldOfView = Mathf.Lerp(num, num3, Time.unscaledDeltaTime * num4); _targetFovField?.SetValue(godCam, _scrollFovTarget); return true; } private void ClampGodCamPitch(GodCam godCam, Transform cameraTransform) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if (_lookDataField == null || godCam == null || (Object)(object)cameraTransform == (Object)null || !(_lookDataField.GetValue(godCam) is Vector2 val)) { return; } float num = Mathf.Clamp(val.y, -89.5f, 89.5f); if (!Mathf.Approximately(num, val.y)) { val.y = num; _lookDataField.SetValue(godCam, val); Vector3 val2 = HelperFunctions.LookToDirection(new Vector3(val.x, val.y, 0f), Vector3.forward); if (((Vector3)(ref val2)).sqrMagnitude > 0.0001f) { cameraTransform.rotation = Quaternion.LookRotation(((Vector3)(ref val2)).normalized); } } } private void SyncGodCamState(MainCameraMovement movement) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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) if (movement.godcam != null) { Vector3 val = DirectionToLook(((Component)movement).transform.forward); val.y = Mathf.Clamp(val.y, -89.5f, 89.5f); _lookDataField?.SetValue(movement.godcam, (object)new Vector2(val.x, val.y)); Camera val2 = (((Object)(object)MainCamera.instance != (Object)null) ? MainCamera.instance.cam : Camera.main); if ((Object)(object)val2 != (Object)null) { _targetFovField?.SetValue(movement.godcam, val2.fieldOfView); } ApplyGodCamSettings(); } } private void InitializeFovState() { Camera val = (((Object)(object)MainCamera.instance != (Object)null) ? MainCamera.instance.cam : Camera.main); if ((Object)(object)val == (Object)null) { _hasFovState = false; _defaultFov = 70f; _scrollFovTarget = 70f; } else { _defaultFov = Mathf.Clamp(val.fieldOfView, 1f, 120f); _scrollFovTarget = _defaultFov; _hasFovState = true; } } private void EnsureFovState(Camera cam) { if (!_hasFovState) { if ((Object)(object)cam == (Object)null) { _defaultFov = 70f; _scrollFovTarget = 70f; } else { _defaultFov = Mathf.Clamp(cam.fieldOfView, 1f, 120f); _scrollFovTarget = _defaultFov; } _hasFovState = true; } } private static float CalculateZoomFov(float baseFov, float multiplier) { baseFov = Mathf.Clamp(baseFov, 1f, 120f); multiplier = Mathf.Max(1f, multiplier); float num = baseFov * (MathF.PI / 180f); return Mathf.Clamp(2f * Mathf.Atan(Mathf.Tan(num * 0.5f) / multiplier) * 57.29578f, 1f, 120f); } internal void ResetToLocalPlayer() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) MainCameraMovement instance = Singleton<MainCameraMovement>.Instance; Character localCharacter = Character.localCharacter; if (!((Object)(object)instance == (Object)null) && !((Object)(object)localCharacter == (Object)null)) { Transform transform = ((Component)instance).transform; _focusedPlayer = null; _switchTransitionActive = false; _followActive = false; _followTarget = null; Vector3 characterResetPosition = GetCharacterResetPosition(localCharacter); transform.position = characterResetPosition - transform.forward * 2.4f + Vector3.up * 1.2f; SyncGodCamState(instance); } } private void CycleFocusedPlayer(int direction) { List<Character> cycleTargets = GetCycleTargets(); if (cycleTargets.Count == 0) { _focusedPlayer = null; return; } int num = cycleTargets.IndexOf(_focusedPlayer); int index = ((num >= 0) ? ((num + direction + cycleTargets.Count) % cycleTargets.Count) : ((direction <= 0) ? (cycleTargets.Count - 1) : 0)); _focusedPlayer = cycleTargets[index]; SetActive(active: true); StartCameraSwitchTransition(_focusedPlayer); } private void StartCameraSwitchTransition(Character target) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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) MainCameraMovement instance = Singleton<MainCameraMovement>.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)target == (Object)null)) { Transform transform = ((Component)instance).transform; if (TryGetTargetCameraPose(target, transform, out var position, out var rotation)) { _switchStartPosition = transform.position; _switchStartRotation = transform.rotation; _switchTargetPosition = position; _switchTargetRotation = rotation; _switchElapsed = 0f; _switchDuration = CalculateSwitchDuration(Vector3.Distance(_switchStartPosition, _switchTargetPosition)); _switchTransitionActive = true; } } } private void UpdateSwitchTransition() { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_0082: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if (!_switchTransitionActive || !IsActive) { return; } MainCameraMovement instance = Singleton<MainCameraMovement>.Instance; Character focusedPlayer = FocusedPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)focusedPlayer == (Object)null) { _switchTransitionActive = false; return; } _switchElapsed += Time.unscaledDeltaTime; float num = Mathf.Clamp01(_switchElapsed / Mathf.Max(0.01f, _switchDuration)); float num2 = TripleEase(num); Transform transform = ((Component)instance).transform; if (TryGetTargetCameraPose(focusedPlayer, transform, out var position, out var rotation)) { _switchTargetPosition = position; _switchTargetRotation = rotation; } transform.position = Vector3.LerpUnclamped(_switchStartPosition, _switchTargetPosition, num2); transform.rotation = Quaternion.Slerp(_switchStartRotation, _switchTargetRotation, num2); SyncGodCamState(instance); if (num >= 1f) { _switchTransitionActive = false; StartSoftFollow(focusedPlayer); } } private void StartSoftFollow(Character target) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null || !Configuration.EnableSoftFollow.Value) { _followActive = false; _followTarget = null; } else { _followTarget = target; _followTargetPosSnapshot = SafeGetTargetCenter(target); _followActive = true; } } internal void UpdateSoftFollow() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) if (!_followActive || !IsActive || _switchTransitionActive) { return; } if ((Object)(object)_followTarget == (Object)null || !CharacterState.IsAliveSpectatorTarget(_followTarget)) { _followActive = false; _followTarget = null; return; } MainCameraMovement instance = Singleton<MainCameraMovement>.Instance; if ((Object)(object)instance == (Object)null) { return; } Transform transform = ((Component)instance).transform; Vector3 val = SafeGetTargetCenter(_followTarget); float num = Vector3.Distance(transform.position, val); float num2 = Mathf.Max(1f, Configuration.SoftFollowMaxDistance.Value); if (num > num2) { _followActive = false; _followTarget = null; return; } Vector3 val2 = val - _followTargetPosSnapshot; if (((Vector3)(ref val2)).sqrMagnitude > 0f) { transform.position += val2; } _followTargetPosSnapshot = val; } private static bool HasMovementInput() { if (!Input.GetKey((KeyCode)119) && !Input.GetKey((KeyCode)97) && !Input.GetKey((KeyCode)115) && !Input.GetKey((KeyCode)100) && !Input.GetKey((KeyCode)32) && !Input.GetKey((KeyCode)306) && !Input.GetKey((KeyCode)113)) { return Input.GetKey((KeyCode)101); } return true; } private static Vector3 SafeGetTargetCenter(Character target) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null) { return Vector3.zero; } try { return target.Center; } catch { return ((Object)(object)((Component)target).transform != (Object)null) ? ((Component)target).transform.position : Vector3.zero; } } private static float CalculateSwitchDuration(float distance) { float num = Mathf.InverseLerp(0f, 80f, Mathf.Max(0f, distance)); return Mathf.Lerp(0.2f, 0.5f, num); } private static float TripleEase(float t) { t = Mathf.Clamp01(t); float num = Mathf.Clamp(0.25f, 0.0001f, 0.4999f); float num2 = 1f / (1f - num); if (t <= num) { return num2 * t * t / (2f * num); } if (t < 1f - num) { return num2 * num / 2f + num2 * (t - num); } float num3 = num2 * num / 2f; float num4 = num2 * (1f - 2f * num); float num5 = t - (1f - num); float num6 = num2 * num5 - num2 * num5 * num5 / (2f * num); return num3 + num4 + num6; } private static bool TryGetTargetCameraPose(Character target, Transform cameraTransform, out Vector3 position, out Quaternion rotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; rotation = Quaternion.identity; if ((Object)(object)target == (Object)null) { return false; } Vector3 characterFocusPoint = GetCharacterFocusPoint(target); Vector3 characterBackDirection = GetCharacterBackDirection(target, cameraTransform); position = characterFocusPoint - characterBackDirection * 4f + Vector3.up * 1.4f; Vector3 val = characterFocusPoint - position; if (((Vector3)(ref val)).sqrMagnitude > 0.001f) { rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up); return true; } rotation = (((Object)(object)cameraTransform != (Object)null) ? cameraTransform.rotation : Quaternion.identity); return true; } private static List<Character> GetCycleTargets() { List<Character> list = new List<Character>(); foreach (Character allCharacter in Character.AllCharacters) { if (CharacterState.IsAliveSpectatorTarget(allCharacter)) { list.Add(allCharacter); } } list.Sort((Character a, Character b) => GetSortKey(a).CompareTo(GetSortKey(b))); return list; } private static int GetSortKey(Character character) { try { if ((Object)(object)((MonoBehaviourPun)character).photonView != (Object)null) { return ((MonoBehaviourPun)character).photonView.OwnerActorNr; } } catch { } return ((Object)character).GetInstanceID(); } private static Vector3 GetCharacterResetPosition(Character character) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_002f: 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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null) { return Vector3.zero; } try { return character.Head; } catch { return character.Center + Vector3.up * 1.2f; } } private static Vector3 GetCharacterFocusPoint(Character character) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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) try { return character.Head; } catch { return character.Center + Vector3.up * 1.2f; } } private static Vector3 GetCharacterBackDirection(Character character, Tr