using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using AIGraph;
using Agents;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CullingSystem;
using Globals;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using Spectate.Config;
using Spectate.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Spectate")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Spectate")]
[assembly: AssemblyTitle("Spectate")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace Spectate
{
public class AgentTarget
{
public readonly PlayerAgent Agent;
public Transform Transform => ((Component)Agent).transform;
public FPSCamera? FPSCamera => Agent.FPSCamera;
public FirstPersonItemHolder? FPHolder => Agent.FPItemHolder;
public PlayerLocomotion Locomotion => Agent.Locomotion;
public PLOC_State LocomotionStateEnum => Locomotion.m_currentStateEnum;
public bool IsDowned => (int)LocomotionStateEnum == 7;
public SNet_Player SAgent => Agent.Owner;
public bool IsBot => SAgent.IsBot;
public bool IsLocal => SAgent.IsLocal;
public Dam_PlayerDamageBase Damage => Agent.Damage;
public float Health => ((Dam_SyncedDamageBase)Damage).Health / ((Dam_SyncedDamageBase)Damage).HealthMax;
public float HealthPercent => Health * 100f;
public float Infection => Damage.Infection;
public float InfectionPercent => Infection * 100f;
public PlayerInventoryBase? Inventory => Agent.Inventory;
public InventorySlot? ActiveItemSlot
{
get
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
PlayerInventoryBase? inventory = Inventory;
if (inventory == null)
{
return null;
}
return inventory.WieldedSlot;
}
}
public AIG_CourseNode? CourseNode => ((Agent)Agent).CourseNode;
public AgentTarget(PlayerAgent agent)
{
Agent = agent;
}
public void SetRigActive(bool active)
{
Util.SetTargetActiveIfDiff(((Component)Agent.PlayerSyncModel).gameObject, active);
}
public static bool operator ==(AgentTarget? a, AgentTarget? b)
{
if ((object)a == b)
{
return true;
}
if ((object)a == null)
{
if ((object)b != null)
{
return (Object)(object)b.Agent == (Object)null;
}
return true;
}
if ((object)b == null)
{
return (Object)(object)a.Agent == (Object)null;
}
return (Object)(object)a.Agent == (Object)(object)b.Agent;
}
public static bool operator !=(AgentTarget? a, AgentTarget? b)
{
return !(a == b);
}
public override bool Equals(object? other)
{
if (other is AgentTarget agentTarget)
{
return this == agentTarget;
}
return false;
}
public override int GetHashCode()
{
return ((Object)Agent).GetHashCode();
}
}
public class InputHelper
{
public static int GetAlphaNumKeyDown()
{
int result = -1;
for (int i = 0; i < 10; i++)
{
if (Input.GetKeyDown((KeyCode)(48 + i)))
{
result = i;
break;
}
}
return result;
}
public static bool OnlyModifies(KeyCode mod, KeyCode altMod = 0, KeyCode nonMod = 0)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Invalid comparison between Unknown and I4
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Invalid comparison between Unknown and I4
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Invalid comparison between Unknown and I4
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Invalid comparison between Unknown and I4
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Invalid comparison between Unknown and I4
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Invalid comparison between Unknown and I4
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Invalid comparison between Unknown and I4
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Invalid comparison between Unknown and I4
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Invalid comparison between Unknown and I4
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Invalid comparison between Unknown and I4
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Invalid comparison between Unknown and I4
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Invalid comparison between Unknown and I4
bool num = Input.GetKey(mod) || Input.GetKey(altMod) || Input.GetKeyDown(nonMod);
bool flag = false;
if ((int)mod != 304 && (int)mod != 303 && (int)altMod != 304 && (int)altMod != 303)
{
flag |= Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
}
if ((int)mod != 306 && (int)mod != 305 && (int)altMod != 306 && (int)altMod != 305)
{
flag |= Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305);
}
if ((int)mod != 308 && (int)mod != 307 && (int)altMod != 308 && (int)altMod != 307)
{
flag |= Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307);
}
if (num)
{
return !flag;
}
return false;
}
public static Vector2 GetMouseDelta()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
return new Vector2(InputMapper.GetAxis.Invoke((InputAction)3, (eFocusState)0), InputMapper.GetAxis.Invoke((InputAction)4, (eFocusState)0));
}
}
internal static class Logger
{
private static ManualLogSource _mLogSource;
public static bool Ready => _mLogSource != null;
public static void Setup()
{
_mLogSource = Logger.CreateLogSource("io.takina.gtfo.Spectate");
}
public static void SetupFromInit(ManualLogSource logSource)
{
_mLogSource = logSource;
}
private static string Format(object data)
{
return data.ToString();
}
public static void Debug(object msg)
{
if (ConfigMgr.Debug)
{
_mLogSource.LogInfo((object)("[DEBUG] " + Format(msg)));
}
else
{
_mLogSource.LogDebug((object)Format(msg));
}
}
public static void Info(object msg)
{
_mLogSource.LogInfo((object)Format(msg));
}
public static void Warn(object msg)
{
_mLogSource.LogWarning((object)Format(msg));
}
public static void Error(object msg)
{
_mLogSource.LogError((object)Format(msg));
}
public static void Fatal(object msg)
{
_mLogSource.LogFatal((object)Format(msg));
}
}
[HarmonyPatch]
public class Patch
{
[HarmonyPatch(typeof(GS_ReadyToStopElevatorRide), "Enter")]
[HarmonyPostfix]
public static void GS_ReadyToStopElevatorRide_Enter(GS_ReadyToStopElevatorRide __instance)
{
SpectateCam.Instance?.Load();
}
[HarmonyPatch(typeof(LocalPlayerAgent), "get_CamPos")]
[HarmonyPrefix]
public static bool PlayerAgent_get_CamPos(ref Vector3 __result)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
SpectateCam? instance = SpectateCam.Instance;
if (instance != null && instance.Active)
{
__result = SpectateCam.Instance.CameraPos;
return false;
}
return true;
}
[HarmonyPatch(typeof(RundownManager), "EndGameSession")]
[HarmonyPrefix]
private static void EndGameSession()
{
SpectateCam.Instance?.Unload();
}
[HarmonyPatch(typeof(SNet_SessionHub), "LeaveHub")]
[HarmonyPrefix]
private static void LeaveHub()
{
SpectateCam.Instance?.Unload();
}
[HarmonyPatch(typeof(PUI_LocalPlayerStatus), "SetDamageAnim")]
[HarmonyPrefix]
public static bool PUI_LocalPlayerStatus_SetDamageAnim(PUI_LocalPlayerStatus __instance)
{
SpectateCam? instance = SpectateCam.Instance;
if (instance != null && instance.Active)
{
return false;
}
return true;
}
[HarmonyPatch(typeof(PlayerAgent), "GetDetectionMod")]
[HarmonyPrefix]
public static bool PlayerAgent_GetDetectionMod(PlayerAgent __instance, ref Vector3 dir, float distance)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
SpectateCam? instance = SpectateCam.Instance;
if (instance != null && instance.Active)
{
dir = SpectateCam.Instance.LastCamDir;
}
return true;
}
[HarmonyPatch(typeof(PlayerSync), "SendLocomotion")]
[HarmonyPrefix]
public static bool PlayerSync_SendLocomotion(PlayerSync __instance, PLOC_State state, Vector3 pos, ref Vector3 lookDir, float velFwd, float velRight)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
SpectateCam? instance = SpectateCam.Instance;
if (instance != null && instance.Active)
{
lookDir = SpectateCam.Instance.LastCamDir;
}
return true;
}
[HarmonyPatch(typeof(PLOC_Downed), "Enter")]
[HarmonyPostfix]
public static void PLOC_Downed_Enter(PLOC_Downed __instance)
{
if (((Agent)((PLOC_Base)__instance).m_owner).IsLocallyOwned && !((Object)(object)SpectateCam.Instance == (Object)null) && ConfigMgr.SwitchOnDeath && !SpectateCam.Instance.Active)
{
SpectateCam.Instance.Attach();
}
}
[HarmonyPatch(typeof(PLOC_Downed), "Exit")]
[HarmonyPostfix]
public static void PLOC_Downed_Exit(PLOC_Downed __instance)
{
if (((Agent)((PLOC_Base)__instance).m_owner).IsLocallyOwned && !((Object)(object)SpectateCam.Instance == (Object)null) && SpectateCam.Instance.Active)
{
SpectateCam.Instance.Detach();
}
}
}
[BepInPlugin("io.takina.gtfo.Spectate", "Spectate", "1.3.0")]
public class Plugin : BasePlugin
{
public const string NAME = "Spectate";
public const string GUID = "io.takina.gtfo.Spectate";
public const string VERSION = "1.3.0";
public static GameObject? PluginObject;
public event Action? OnManagersSetup;
public override void Load()
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
Logger.Setup();
Logger.Info("Spectate [io.takina.gtfo.Spectate @ 1.3.0]");
Logger.Info("Patching...");
Harmony val = new Harmony("io.takina.gtfo.Spectate");
ConfigMgr.Process();
ClassInjector.RegisterTypeInIl2Cpp<SpectateCam>();
ClassInjector.RegisterTypeInIl2Cpp<SpectateUI>();
OnManagersSetup += Initialize;
Global.OnAllManagersSetup += Action.op_Implicit(this.OnManagersSetup);
val.PatchAll(typeof(Patch));
Logger.Info("Finished Patching");
}
private void Initialize()
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
Logger.Debug("Initializing Plugin GameObject...");
PluginObject = new GameObject("io.takina.gtfo.Spectate");
Object.DontDestroyOnLoad((Object)(object)PluginObject);
PluginObject.AddComponent<SpectateCam>();
PluginObject.AddComponent<SpectateUI>();
}
public override bool Unload()
{
ConfigMgr.WriteConfigIfDirty();
return true;
}
}
public class SpectateCam : MonoBehaviour
{
private bool _wasActive;
private int _lastTargetPlayerIdx = -1;
private bool _freecam = ConfigMgr.DefaultFreecamView;
private bool _freecamFollow = ConfigMgr.AutoTransitionToFollowView;
private float _freeLookReturnTimer;
public Vector3 LastCamDir = Vector3.forward;
private float _pitch = ConfigMgr.CameraPitchAngleDeg;
private float _yaw;
private float _pitchTarget = ConfigMgr.CameraPitchAngleDeg;
private float _yawTarget;
private float _eyeY;
private float _eyeYTarget;
private Vector3 _eyeXZ = Vector3.zero;
private Vector3 _eyeXZTarget = Vector3.zero;
private Vector3 _eyePosComputed = Vector3.zero;
public const float DefaultCameraYPositionLerpGain = 11f;
public const float DefaultCameraXZPositionLerpGain = 15f;
public const float DefaultCameraLerpGain = 6f;
public const float DefaultOrbitCenterVerticalOffset = 0.325f;
public const float DefaultPitchAngleDeg = -18.75f;
public const float DefaultDistanceFromEye = 0.625f;
public const float DefaultScrollSensitivity = 0.5f;
public const float DefaultFreecamSensitivity = 1f;
public const float OrbitCenterVerticalOffsetMin = -1f;
public const float OrbitCenterVerticalOffsetMax = 5f;
public const float DistanceMin = 0.1f;
public const float DistanceMax = 5f;
public const float PitchAngleDegMin = -89f;
public const float PitchAngleDegMax = 89f;
private AgentTarget? _self;
private AgentTarget? _target;
public static SpectateCam? Instance { get; set; }
public bool SelfReady
{
get
{
if (_self != null)
{
return (Object)(object)_self.FPSCamera != (Object)null;
}
return false;
}
}
public bool TargetReady => _target != null;
public bool Active { get; private set; }
public bool Freecam => _freecam;
public Vector3 CameraPos
{
get
{
//IL_0054: 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_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
if (!Active)
{
AgentTarget? self = _self;
Vector3? obj;
if ((object)self == null)
{
obj = null;
}
else
{
FPSCamera? fPSCamera = self.FPSCamera;
obj = ((fPSCamera != null) ? new Vector3?(fPSCamera.Position) : null);
}
return (Vector3)(((??)obj) ?? Vector3.zero);
}
return _eyePosComputed;
}
}
public AgentTarget? Self
{
get
{
if (_self == null)
{
_self = new AgentTarget(PlayerManager.GetLocalPlayerAgent());
}
return _self;
}
}
public AgentTarget? Target => _target;
public event Action? OnActive;
public SpectateCam(IntPtr ptr)
: base(ptr)
{
}//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: 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_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
private void Awake()
{
if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
{
Object.Destroy((Object)(object)((Component)this).gameObject);
return;
}
Instance = this;
Object.DontDestroyOnLoad((Object)(object)this);
}
public bool Load()
{
PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
if ((Object)(object)localPlayerAgent == (Object)null)
{
Logger.Error("SpectateCam: Failed to load - local player agent is null");
return false;
}
_self = new AgentTarget(localPlayerAgent);
return (Object)(object)_self.FPSCamera != (Object)null;
}
public bool Unload()
{
Active = false;
_self = null;
_target = null;
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetTarget(PlayerAgent agent)
{
_target = new AgentTarget(agent);
}
public bool Attach()
{
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
if (Active)
{
return true;
}
if (!SelfReady && !Load())
{
Logger.Error("SpectateCam: Attach failed - self not ready and cannot be loaded");
return false;
}
if (!TargetReady && !TrySetAnyNonLocalTarget())
{
Logger.Warn("SpectateCam: Attach failed - no valid target available");
return false;
}
LastCamDir = _self.FPSCamera.Forward;
GuiManager.CrosshairLayer.ShowPrecisionDot();
SpectateUI.Instance?.UpdateForAttach();
SetRelatedActive(spectateActive: true);
UpdateCull();
SetActive(active: true);
Logger.Debug("Attach");
return true;
}
public bool Detach()
{
if (!Active)
{
return true;
}
if (!SelfReady && !Load())
{
Logger.Error("SpectateCam: Detach failed - self not ready and cannot be loaded");
Logger.Info("SpectateCam: Detach falling back to Unload");
Unload();
return false;
}
CrosshairGuiLayer crosshairLayer = GuiManager.CrosshairLayer;
if (crosshairLayer != null)
{
FirstPersonItemHolder? fPHolder = _self.FPHolder;
float? obj;
if (fPHolder == null)
{
obj = null;
}
else
{
ItemEquippable wieldedItem = fPHolder.WieldedItem;
obj = ((wieldedItem != null) ? new float?(wieldedItem.HipFireCrosshairSize) : null);
}
crosshairLayer.ShowSpreadCircle(obj ?? 40f);
}
SpectateUI.Instance?.UpdateForDetach();
SetRelatedActive(spectateActive: false);
RevertCull();
SetActive(active: false);
Logger.Debug("Detach");
return true;
}
private void SetActive(bool active)
{
if (active && !_wasActive)
{
this.OnActive?.Invoke();
}
_wasActive = Active;
Active = active;
if (!Active)
{
_yaw = 0f;
_pitch = ConfigMgr.CameraPitchAngleDeg;
_freeLookReturnTimer = 0f;
}
}
private void SetRelatedActive(bool spectateActive)
{
if (!SelfReady)
{
Logger.Error("SpectateCam: SetRelatedActive failed - self not ready");
return;
}
_self.SetRigActive(!spectateActive);
_self.Agent.DeadDebugMode = spectateActive;
Util.SetTargetActiveIfDiff((Behaviour?)(object)_self.Inventory, !spectateActive);
PlayerInventoryBase? inventory = _self.Inventory;
Util.SetTargetActiveIfDiff((inventory != null) ? ((Component)inventory.m_flashlight).gameObject : null, !spectateActive);
FirstPersonItemHolder? fPHolder = _self.FPHolder;
Util.SetTargetActiveIfDiff((fPHolder != null) ? ((Component)fPHolder).gameObject : null, !spectateActive);
FirstPersonItemHolder? fPHolder2 = _self.FPHolder;
if (fPHolder2 != null)
{
PlayerFPSBody fPSArms = fPHolder2.FPSArms;
if (fPSArms != null)
{
fPSArms.SetVisible(!spectateActive && !_self.IsDowned);
}
}
FPSCamera fPSCamera = _self.FPSCamera;
if ((Object)(object)fPSCamera != (Object)null)
{
fPSCamera.MouseLookEnabled = !spectateActive;
fPSCamera.PlayerAgentRotationEnabled = !spectateActive;
fPSCamera.PlayerMoveEnabled = !spectateActive;
}
}
private void Update()
{
if (!((Behaviour)this).enabled || !((Component)this).gameObject.activeInHierarchy)
{
return;
}
ProcessInput();
UpdateTransitions();
if (Active)
{
if (_target == null)
{
Detach();
return;
}
UpdateLerp(_freecam);
UpdateCamera();
UpdateCull();
}
}
private void UpdateTransitions()
{
if (SelfReady)
{
if (Active && !_self.IsDowned && !ConfigMgr.DevEnables(eDevOpts.AllowSpectatingAnytime))
{
Detach();
}
else if (Active && ConfigMgr.AutoTransitionToFollowView && _freeLookReturnTimer >= 0f)
{
_freeLookReturnTimer -= Time.deltaTime;
}
}
}
private void ProcessInput()
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: 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)
//IL_00af: 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)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
if (!InputMapper.Current.FocusStateFilterPass((eFocusState)4))
{
return;
}
if ((ConfigMgr.DevEnables(eDevOpts.AllowSpectatingAnytime) || (SelfReady && _self.IsDowned)) && Input.GetKeyDown(ConfigMgr.GetKeybind(SpectateInputAction.ToggleSpectate)))
{
if (Active)
{
if (!Detach())
{
Logger.Warn("SpectateCam: Failed to detach SpecCam");
}
}
else if (!Attach())
{
Logger.Warn("SpectateCam: Failed to attach SpecCam");
}
}
if (!Active)
{
return;
}
if (Input.GetKeyDown(ConfigMgr.GetKeybind(SpectateInputAction.ToggleFreecam)))
{
if (_freecam)
{
_freecam = false;
OnFree2Follow();
}
else
{
_freecam = true;
OnFollow2Free();
}
}
if (_freecam && Input.GetKeyDown(ConfigMgr.GetKeybind(SpectateInputAction.ToggleAutoFollow)))
{
ConfigMgr.AutoTransitionToFollowView = !ConfigMgr.AutoTransitionToFollowView;
SpectateUI.Instance?.MarkUIDirty();
}
Vector2 mouseDelta = InputHelper.GetMouseDelta();
if (_freecam && mouseDelta != Vector2.zero)
{
AdjustYaw(mouseDelta.x * ConfigMgr.FreecamSensitivity);
AdjustPitch(mouseDelta.y * ConfigMgr.FreecamSensitivity);
if (ConfigMgr.AutoTransitionToFollowView)
{
_freecamFollow = false;
_freeLookReturnTimer = ConfigMgr.AutoTransitionDelay;
}
}
if (_freecam)
{
if (Input.GetKey((KeyCode)273))
{
AdjustPitch(ConfigMgr.FreecamSensitivity);
}
if (Input.GetKey((KeyCode)274))
{
AdjustPitch(0f - ConfigMgr.FreecamSensitivity);
}
if (Input.GetKey((KeyCode)276))
{
AdjustYaw(0f - ConfigMgr.FreecamSensitivity);
}
if (Input.GetKey((KeyCode)275))
{
AdjustYaw(ConfigMgr.FreecamSensitivity);
}
}
if (Input.GetKeyDown((KeyCode)323))
{
TrySetNextTarget();
}
if (Input.GetKeyDown((KeyCode)324))
{
TrySetPreviousTarget();
}
int alphaNumKeyDown = InputHelper.GetAlphaNumKeyDown();
if (alphaNumKeyDown > 0)
{
TrySetTargetByIdx(alphaNumKeyDown - 1);
}
float num = Input.mouseScrollDelta.y * ConfigMgr.ScrollSensitivity;
if (InputMapper.Current.FocusStateFilterPass((eFocusState)6) || !(Mathf.Abs(num) > 0f))
{
return;
}
if (InputHelper.OnlyModifies((KeyCode)304, (KeyCode)303, (KeyCode)0))
{
if (_freecam)
{
SpectateUI.Instance?.WarnFreecamNoAdjustPitch();
}
else
{
ConfigMgr.CameraPitchAngleDeg -= 0.5f * num;
}
}
else if (InputHelper.OnlyModifies((KeyCode)306, (KeyCode)305, (KeyCode)0))
{
ConfigMgr.CameraOrbitVerticalOffset = Mathf.Clamp(ConfigMgr.CameraOrbitVerticalOffset + 0.05f * num, -1f, 5f);
}
else
{
ConfigMgr.CameraDistance = Mathf.Clamp(ConfigMgr.CameraDistance - 0.05f * num, 0.1f, 5f);
}
}
private void UpdateCamera()
{
//IL_004f: 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_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_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_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_010b: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_012b: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
if (!SelfReady || !TargetReady)
{
Logger.Error("SpectateCam: UpdateCull failed - target or self not ready");
return;
}
if (ConfigMgr.AutoTransitionToFollowView && _freecam)
{
if (_freeLookReturnTimer < 0.001f)
{
_freecamFollow = true;
}
if (_freecamFollow)
{
UpdateYawPitchWithFollowView(instant: false);
}
}
SetEye(GetTargetOrbitCenter());
Vector3 val = _eyeXZ + Vector3.up * _eyeY;
Vector3 forward = ((Agent)_target.Agent).Forward;
Vector3 val2 = ((Vector3)(ref forward)).normalized;
if (_freecam)
{
val2 = Quaternion.Euler(0f, _yaw, 0f) * Vector3.forward;
}
float num = (float)Math.PI / 180f * (_freecam ? _pitch : ConfigMgr.CameraPitchAngleDeg);
Vector3 val3 = val2 + Vector3.up * Mathf.Tan(num);
((Vector3)(ref val3)).Normalize();
_eyePosComputed = val - val3 * ConfigMgr.CameraDistance;
RaycastHit val4 = default(RaycastHit);
if (Physics.Raycast(val, -val3, ref val4, ConfigMgr.CameraDistance, LayerManager.MASK_WORLD))
{
_eyePosComputed = val4.m_Point + val3 * 0.1f;
}
_self.FPSCamera.OverridePositionAndRotation(_eyePosComputed, Quaternion.LookRotation(val3));
_self.FPSCamera.OverrideFieldOfView((float)CellSettingsManager.GetIntValue((eCellSettingID)52));
}
private void UpdateLerp(bool freecamEnabled)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
_eyeXZ = Vector3.Lerp(_eyeXZ, _eyeXZTarget, Time.deltaTime * ConfigMgr.CameraXZLerpGain);
_eyeY = Mathf.Lerp(_eyeY, _eyeYTarget, Time.deltaTime * ConfigMgr.CameraYLerpGain);
if (freecamEnabled)
{
_yaw = Mathf.LerpAngle(_yaw, _yawTarget, Time.deltaTime * ConfigMgr.FreecamLerpGain);
float num = _yawTarget - _yaw;
_yaw = Mathf.Repeat(_yaw, 360f);
_yawTarget = _yaw + num;
_pitch = Mathf.LerpAngle(_pitch, _pitchTarget, Time.deltaTime * ConfigMgr.FreecamLerpGain);
}
}
private void UpdateCull()
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: 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_005d: 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_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
if (!SelfReady || !TargetReady)
{
Logger.Error("SpectateCam: UpdateCull failed - target or self not ready");
return;
}
Vector3 val = ((Agent)_target.Agent).Position;
RaycastHit val2 = default(RaycastHit);
if (Physics.Raycast(val, Vector3.down, ref val2, 64f, LayerManager.MASK_WORLD))
{
val = val2.m_Point;
}
CameraManager.CullingPosition = val;
CameraManager.CullingDirection = _self.FPSCamera.Forward;
_self.Agent.m_movingCuller.UpdatePosition(((Agent)_self.Agent).m_dimensionIndex, val);
C_Node currentNode = _self.Agent.m_movingCuller.CurrentNode;
AIG_CourseNode? courseNode = _target.CourseNode;
C_Node val3 = ((courseNode != null) ? courseNode.m_cullNode : null);
if (val3 != null)
{
if (((Il2CppObjectBase)currentNode).Pointer != ((Il2CppObjectBase)val3).Pointer)
{
_self.Agent.m_movingCuller.SetCurrentNode(val3);
}
}
else
{
Logger.Warn("SpectateCam: UpdateCull - failed to sync cull nodes, target node is null");
}
}
private void RevertCull()
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: 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_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: 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_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
if (!SelfReady)
{
Logger.Error("SpectateCam: RevertCull failed - self is not ready");
return;
}
Vector3 val = ((Agent)_self.Agent).Position;
RaycastHit val2 = default(RaycastHit);
if (Physics.Raycast(val, Vector3.down, ref val2, 64f, LayerManager.MASK_WORLD))
{
val = val2.m_Point;
}
CameraManager.CullingPosition = val;
CameraManager.CullingDirection = _self.FPSCamera.Forward;
_self.Agent.m_movingCuller.UpdatePosition(((Agent)_self.Agent).m_dimensionIndex, val);
C_Node currentNode = _self.Agent.m_movingCuller.CurrentNode;
AIG_CourseNode? courseNode = _self.CourseNode;
C_Node val3 = ((courseNode != null) ? courseNode.m_cullNode : null);
if (val3 != null)
{
if (((currentNode != null) ? new IntPtr?(((Il2CppObjectBase)currentNode).Pointer) : null) != ((val3 != null) ? new IntPtr?(((Il2CppObjectBase)val3).Pointer) : null))
{
_self.Agent.m_movingCuller.SetCurrentNode(val3);
}
}
else
{
Logger.Warn("SpectateCam: RevertCull - failed to sync cull nodes self or target node is null");
}
}
private void OnApplicationQuit()
{
ConfigMgr.WriteConfigIfDirty();
}
private bool TrySetAnyNonLocalTarget()
{
SNet_PlayerSlotManager slots = SNet.Slots;
List<SNet_Player> val = ((slots != null) ? slots.SlottedPlayers : null);
if (val == null || val.Count == 0)
{
return false;
}
_lastTargetPlayerIdx = 0;
for (int i = 0; i < val.Count; i++)
{
if (TrySetTargetByIdx(i))
{
return true;
}
}
return false;
}
private bool TrySetNextTarget()
{
SNet_PlayerSlotManager slots = SNet.Slots;
int num = ((slots == null) ? null : slots.SlottedPlayers?.Count) ?? (-1);
if (num <= 0)
{
return false;
}
for (int i = 1; i <= num; i++)
{
int playerIdx = (_lastTargetPlayerIdx + i) % num;
if (TrySetTargetByIdx(playerIdx))
{
return true;
}
}
return false;
}
private bool TrySetPreviousTarget()
{
SNet_PlayerSlotManager slots = SNet.Slots;
int num = ((slots == null) ? null : slots.SlottedPlayers?.Count) ?? (-1);
if (num <= 0)
{
return false;
}
for (int i = 1; i <= num; i++)
{
int playerIdx = (_lastTargetPlayerIdx - i + num) % num;
if (TrySetTargetByIdx(playerIdx))
{
return true;
}
}
return false;
}
private bool TrySetTargetByIdx(int playerIdx)
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
SNet_PlayerSlotManager slots = SNet.Slots;
List<SNet_Player> val = ((slots != null) ? slots.SlottedPlayers : null);
if (val == null || val.Count == 0)
{
return false;
}
if (playerIdx >= 0 && playerIdx < val.Count && !val[playerIdx].IsLocal)
{
SetTarget(((Il2CppObjectBase)val[playerIdx].PlayerAgent).Cast<PlayerAgent>());
if ((ConfigMgr.NoPosLerpOnSwitchTarget && playerIdx != _lastTargetPlayerIdx) || !_freecam)
{
SetEye(GetTargetOrbitCenter(), instant: true);
}
_lastTargetPlayerIdx = playerIdx;
return true;
}
return false;
}
private Vector3 GetTargetOrbitCenter()
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
AgentTarget? target = _target;
Vector3 result = (((object)target != null) ? target.Agent.m_eyePosition : Vector3.zero);
result.y += ConfigMgr.CameraOrbitVerticalOffset;
return result;
}
private void OnFollow2Free()
{
if (!TargetReady)
{
Logger.Error("SpectateCam: OnTransitionToFreecam failed - target not ready");
return;
}
UpdateYawPitchWithFollowView(instant: true);
SpectateUI.Instance?.MarkUIDirty();
}
private void OnFree2Follow()
{
if (!TargetReady)
{
Logger.Error("SpectateCam: OnTransitionToFollow failed - target not ready");
return;
}
UpdateYawPitchWithFollowView(instant: true);
SpectateUI.Instance?.MarkUIDirty();
}
private void UpdateYawPitchWithFollowView(bool instant)
{
//IL_0001: 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)
SetYaw(Vector3.SignedAngle(Vector3.forward, ((Agent)_target.Agent).Forward, Vector3.up), instant);
SetPitch(ConfigMgr.CameraPitchAngleDeg, instant);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AdjustPitch(float deltaPitch, bool instant = false)
{
SetPitch(_pitchTarget + deltaPitch, instant);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AdjustYaw(float deltaYaw, bool instant = false)
{
SetYaw(_yawTarget + deltaYaw, instant);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetPitch(float pitch, bool instant = false)
{
pitch = Mathf.Clamp(pitch, -89f, 89f);
_pitchTarget = pitch;
if (instant)
{
_pitch = pitch;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetYaw(float yaw, bool instant = false)
{
_yawTarget = yaw;
if (instant)
{
_yaw = yaw;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetEyeXZ(Vector3 eyeXZ, bool instant = false)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
eyeXZ.y = 0f;
_eyeXZTarget = eyeXZ;
if (instant)
{
_eyeXZ = eyeXZ;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetEyeY(float eyeY, bool instant = false)
{
_eyeYTarget = eyeY;
if (instant)
{
_eyeY = eyeY;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetEye(Vector3 pos, bool instant = false)
{
//IL_0001: 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)
SetEyeXZ(pos, instant);
SetEyeY(pos.y, instant);
}
}
public static class Util
{
public const float GOOD_ENOUGH_DEG_EPS = 0.2f;
public static bool GoodEnoughDeg(float a, float b)
{
return NearlyEqual(a, b, 0.2f);
}
public static bool NearlyEqual(float a, float b, float eps = 0.0001f)
{
return Mathf.Abs(a - b) < eps;
}
public static void SetTargetActiveIfDiff(GameObject? obj, bool active)
{
if (!((Object)(object)obj == (Object)null) && obj.activeSelf != active)
{
obj.SetActive(active);
}
}
public static void SetTargetActiveIfDiff(Behaviour? beh, bool active)
{
if (!((Object)(object)beh == (Object)null) && beh.enabled != active)
{
beh.enabled = active;
}
}
}
}
namespace Spectate.UI
{
public enum eSpectateUIComp
{
SpectateTarget,
Title,
ViewMode,
Menu
}
public enum eSpectateMenuItem
{
HideMenu,
ShowMenu,
EnterSpectate,
ExitSpectate,
ToggleFreecam,
EnableFreecamAutoTransition,
DisableFreecamAutoTransition,
SwitchPlayer,
SelectPlayer,
AdjustDistance,
AdjustOrbitCenterHeight,
AdjustFollowPitch
}
public enum eSpectateUIState
{
FPDowned,
FPNotDowned,
HideMenu,
ShowMenu
}
public struct MenuKeybindEntry
{
private string _keyName;
private bool _isAssociated;
private SpectateInputAction _associatedAction;
public MenuKeybindEntry(string keyName)
{
_isAssociated = false;
_associatedAction = SpectateInputAction.None;
_keyName = keyName;
}
public MenuKeybindEntry(SpectateInputAction action)
{
_isAssociated = true;
_associatedAction = action;
_keyName = "";
}
public override string ToString()
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (_isAssociated)
{
return CellSettingGlobals.GetLocalizedKeyCode(ConfigMgr.GetKeybind(_associatedAction));
}
return _keyName;
}
}
public class SpectateUI : MonoBehaviour
{
private bool _wasUIActive;
private bool _isUIDirty = true;
private eSpectateUIState _uiState = eSpectateUIState.FPNotDowned;
private eSpectateUIState _uiStatePrev = eSpectateUIState.FPNotDowned;
private eSpectateUIState _uiStateRendered = eSpectateUIState.ShowMenu;
private readonly List<GameObject> _uiRoots = new List<GameObject>();
private readonly Dictionary<eSpectateUIComp, bool> _uiCompState = new Dictionary<eSpectateUIComp, bool>();
private const float MenuCenterOffsetX = 300f;
private const float MenuLeftPadding = 50f;
private const float MenuElementWidth = 250f;
private const float MenuCenterDivideSpacing = 5f;
private const int MaxMenuItems = 10;
private const float MenuItemSpacing = 27f;
private const float MenuOptionHeight = 22f;
private const float MenuKeybindHeight = 16f;
private const string SpecTargetTextColor = "FFFFFF";
private const string StateHighlightColor = "04B065";
private TextMeshPro? _specTargetTmp;
private GameObject? _menuObj;
private TextMeshPro? _menuTitleTmp;
private TextMeshPro? _menuViewModeTmp;
private GameObject? _menuListObj;
private List<(TextMeshPro?, TextMeshPro?)> _menuItemsTmp = new List<(TextMeshPro, TextMeshPro)>(10);
private SpriteRenderer? _menuBackground;
private string _specTargetStr = "";
private readonly string _menuTitleStr = "SPECTATE";
private string _menuViewModeStr = "";
private readonly List<(string, string)> _menuItemsStr = new List<(string, string)>();
private readonly Dictionary<eSpectateMenuItem, (string, MenuKeybindEntry)> _menuItems = new Dictionary<eSpectateMenuItem, (string, MenuKeybindEntry)>
{
[eSpectateMenuItem.ShowMenu] = ("Show Menu", new MenuKeybindEntry(SpectateInputAction.ToggleMenu)),
[eSpectateMenuItem.HideMenu] = ("Hide Menu", new MenuKeybindEntry(SpectateInputAction.ToggleMenu)),
[eSpectateMenuItem.EnterSpectate] = ("Enter Spectate", new MenuKeybindEntry(SpectateInputAction.ToggleSpectate)),
[eSpectateMenuItem.ExitSpectate] = ("Exit Spectate", new MenuKeybindEntry(SpectateInputAction.ToggleSpectate)),
[eSpectateMenuItem.ToggleFreecam] = ("Toggle Free-Look", new MenuKeybindEntry(SpectateInputAction.ToggleFreecam)),
[eSpectateMenuItem.EnableFreecamAutoTransition] = ("Enable Auto-Follow", new MenuKeybindEntry(SpectateInputAction.ToggleAutoFollow)),
[eSpectateMenuItem.DisableFreecamAutoTransition] = ("Disable Auto-Follow", new MenuKeybindEntry(SpectateInputAction.ToggleAutoFollow)),
[eSpectateMenuItem.SwitchPlayer] = ("Switch Player", new MenuKeybindEntry("LMB / RMB")),
[eSpectateMenuItem.SelectPlayer] = ("Select Player", new MenuKeybindEntry("1 - 8")),
[eSpectateMenuItem.AdjustDistance] = ("Camera Distance", new MenuKeybindEntry("Scroll")),
[eSpectateMenuItem.AdjustOrbitCenterHeight] = ("Camera Vertical Offset", new MenuKeybindEntry("Ctrl + Scroll")),
[eSpectateMenuItem.AdjustFollowPitch] = ("Camera Pitch", new MenuKeybindEntry("Shift + Scroll"))
};
public static SpectateUI? Instance { get; private set; }
public eSpectateUIState UIState => _uiState;
public SpectateUI(IntPtr ptr)
: base(ptr)
{
}
private void Awake()
{
if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
{
Object.Destroy((Object)(object)((Component)this).gameObject);
}
else
{
Instance = this;
}
}
private bool AllTMPExist()
{
if ((Object)(object)_menuObj != (Object)null)
{
return (Object)(object)_specTargetTmp != (Object)null;
}
return false;
}
private void Update()
{
if ((!(SpectateCam.Instance?.Self != null) || !SpectateCam.Instance.Self.IsDowned) && !ConfigMgr.DevEnables(eDevOpts.AllowSpectatingAnytime))
{
SetUIActive(active: false);
}
else if (CheckOrCreateTMP())
{
ProcessInput();
SpectateCam? instance = SpectateCam.Instance;
if (instance != null && instance.Active)
{
UpdatePlayerStatusUI(SpectateCam.Instance.Target);
}
SetUIActive(active: true);
if (_isUIDirty || UIState != _uiStateRendered)
{
RefreshUI();
}
}
}
public void UpdateForAttach()
{
if (_uiStatePrev == eSpectateUIState.HideMenu || _uiStatePrev == eSpectateUIState.ShowMenu)
{
SetUIState(_uiStatePrev);
}
else
{
SetUIState(eSpectateUIState.HideMenu);
}
}
public void UpdateForDetach()
{
bool valueOrDefault = (SpectateCam.Instance?.Self?.IsDowned).GetValueOrDefault();
SetUIState((!valueOrDefault) ? eSpectateUIState.FPNotDowned : eSpectateUIState.FPDowned);
UpdatePlayerStatusUI(SpectateCam.Instance?.Self);
}
private void ProcessInput()
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
if (InputMapper.Current.FocusStateFilterPass((eFocusState)4) && Input.GetKeyDown(ConfigMgr.GetKeybind(SpectateInputAction.ToggleMenu)))
{
switch (UIState)
{
case eSpectateUIState.ShowMenu:
SetUIState(eSpectateUIState.HideMenu);
break;
case eSpectateUIState.HideMenu:
SetUIState(eSpectateUIState.ShowMenu);
break;
}
}
}
private bool CheckOrCreateTMP()
{
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Expected O, but got Unknown
//IL_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
//IL_0212: Unknown result type (might be due to invalid IL or missing references)
//IL_0231: Unknown result type (might be due to invalid IL or missing references)
//IL_028e: Unknown result type (might be due to invalid IL or missing references)
//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
//IL_02fb: Expected O, but got Unknown
//IL_0313: Unknown result type (might be due to invalid IL or missing references)
//IL_0329: Unknown result type (might be due to invalid IL or missing references)
//IL_033f: Unknown result type (might be due to invalid IL or missing references)
//IL_0355: Unknown result type (might be due to invalid IL or missing references)
//IL_0361: Unknown result type (might be due to invalid IL or missing references)
//IL_0409: Unknown result type (might be due to invalid IL or missing references)
//IL_0424: Unknown result type (might be due to invalid IL or missing references)
//IL_044f: Unknown result type (might be due to invalid IL or missing references)
//IL_0485: Unknown result type (might be due to invalid IL or missing references)
//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
//IL_04cb: Unknown result type (might be due to invalid IL or missing references)
//IL_0598: Unknown result type (might be due to invalid IL or missing references)
if (AllTMPExist())
{
return true;
}
RemoveAllUIRoots();
PlayerGuiLayer playerLayer = GuiManager.PlayerLayer;
PUI_LocalPlayerStatus val = ((playerLayer != null) ? playerLayer.m_playerStatus : null);
if ((Object)(object)val == (Object)null)
{
return false;
}
Transform parent = ((Component)val).transform.parent;
TextMeshPro healthText = val.m_healthText;
_specTargetTmp = CreateTMPFrom(healthText, "io.takina.gtfo.Spectate_SpectateTarget");
RegisterUIRoot(((Component)_specTargetTmp).gameObject);
((Transform)((TMP_Text)_specTargetTmp).rectTransform).SetParent(parent, false);
((TMP_Text)_specTargetTmp).rectTransform.anchorMin = new Vector2(0.5f, 1f);
((TMP_Text)_specTargetTmp).rectTransform.anchorMax = new Vector2(0.5f, 1f);
((TMP_Text)_specTargetTmp).rectTransform.anchoredPosition3D = new Vector3(0f, -200f, 0f);
((TMP_Text)_specTargetTmp).rectTransform.sizeDelta = new Vector2(300f, 100f);
((TMP_Text)_specTargetTmp).alignment = (TextAlignmentOptions)514;
((Component)_specTargetTmp).gameObject.SetActive(false);
_menuObj = new GameObject("io.takina.gtfo.Spectate_SpectateMenu");
RegisterUIRoot(_menuObj);
RectTransform val2 = _menuObj.AddComponent<RectTransform>();
((Transform)val2).SetParent(parent, false);
((Transform)val2).localScale = Vector3.one;
val2.anchorMin = new Vector2(0f, 0.5f);
val2.anchorMax = new Vector2(0f, 0.5f);
val2.pivot = new Vector2(0.5f, 0.5f);
val2.anchoredPosition3D = new Vector3(300f, 0f, 0f);
_menuTitleTmp = CreateTMPFrom(healthText, "io.takina.gtfo.Spectate_MenuTitle");
((Transform)((TMP_Text)_menuTitleTmp).rectTransform).SetParent(_menuObj.transform, false);
((TMP_Text)_menuTitleTmp).rectTransform.pivot = new Vector2(1f, 0f);
((TMP_Text)_menuTitleTmp).rectTransform.anchoredPosition3D = new Vector3(0f, 55f, 0f);
((TMP_Text)_menuTitleTmp).rectTransform.sizeDelta = new Vector2(250f, 45f);
((TMP_Text)_menuTitleTmp).alignment = (TextAlignmentOptions)516;
_menuViewModeTmp = CreateTMPFrom(healthText, "io.takina.gtfo.Spectate_ViewMode");
((Transform)((TMP_Text)_menuViewModeTmp).rectTransform).SetParent(_menuObj.transform, false);
((TMP_Text)_menuViewModeTmp).rectTransform.pivot = new Vector2(1f, 0f);
((TMP_Text)_menuViewModeTmp).rectTransform.anchoredPosition3D = new Vector3(0f, 13f, 0f);
((TMP_Text)_menuViewModeTmp).rectTransform.sizeDelta = new Vector2(250f, 40f);
((TMP_Text)_menuViewModeTmp).alignment = (TextAlignmentOptions)516;
_menuListObj = new GameObject("io.takina.gtfo.Spectate_SpectateMenuList");
RectTransform val3 = _menuListObj.AddComponent<RectTransform>();
((Transform)val3).SetParent((Transform)(object)val2, false);
((Transform)val3).localScale = Vector3.one;
val3.anchorMin = new Vector2(0.5f, 0.5f);
val3.anchorMax = new Vector2(0.5f, 0.5f);
val3.pivot = new Vector2(0.5f, 0.5f);
val3.anchoredPosition3D = Vector3.zero;
for (int i = 0; i < 10; i++)
{
TextMeshPro val4 = CreateTMPFrom(healthText, $"{"io.takina.gtfo.Spectate"}_MenuOption_{i}");
TextMeshPro val5 = CreateTMPFrom(healthText, $"{"io.takina.gtfo.Spectate"}_MenuKeybind_{i}");
((Transform)((TMP_Text)val4).rectTransform).SetParent((Transform)(object)val3, false);
((TMP_Text)val4).rectTransform.pivot = new Vector2(1f, 0.5f);
((TMP_Text)val4).rectTransform.sizeDelta = new Vector2(250f, 22f);
((TMP_Text)val4).rectTransform.anchoredPosition3D = new Vector3(0f, 0f - ((float)i + 0.5f) * 27f, 0f);
((TMP_Text)val4).alignment = (TextAlignmentOptions)516;
((Transform)((TMP_Text)val5).rectTransform).SetParent((Transform)(object)val3, false);
((TMP_Text)val5).rectTransform.pivot = new Vector2(0f, 0.5f);
((TMP_Text)val5).rectTransform.sizeDelta = new Vector2(250f, 16f);
((TMP_Text)val5).rectTransform.anchoredPosition3D = new Vector3(5f, 0f - ((float)i + 0.5f) * 27f, 0f);
((TMP_Text)val5).alignment = (TextAlignmentOptions)513;
_menuItemsTmp.Add((val4, val5));
}
RefreshUI();
Transform val6 = parent.Find("PUI_CommunicationMenu(Clone)/Root/Backround");
if ((Object)(object)val6 == (Object)null)
{
Logger.Warn("SpectateUI: Can't find bg transform in CommunicationMenu! Using \"" + ((Object)parent).name + "\"");
return true;
}
GameObject val7 = Object.Instantiate<GameObject>(((Component)val6).gameObject);
((Object)val7).name = "io.takina.gtfo.Spectate_MenuBackground";
_menuBackground = val7.GetComponent<SpriteRenderer>();
((Renderer)_menuBackground).sortingOrder = -20;
RectTransform component = val7.GetComponent<RectTransform>();
((Transform)component).SetParent(_menuObj.transform);
component.anchoredPosition3D = new Vector3(-25f, -55f, 0f);
return true;
}
private TextMeshPro CreateTMPFrom(TextMeshPro from, string name)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: 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)
TextMeshPro obj = Object.Instantiate<TextMeshPro>(from);
((Object)obj).name = name;
((Graphic)obj).color = new Color(1f, 1f, 1f, 0.8f);
((TMP_Text)obj).enableAutoSizing = true;
((TMP_Text)obj).autoSizeTextContainer = false;
((TMP_Text)obj).enableWordWrapping = false;
((TMP_Text)obj).overflowMode = (TextOverflowModes)1;
((TMP_Text)obj).margin = Vector4.zero;
((TMP_Text)obj).fontSize = 26f;
((TMP_Text)obj).fontSizeMin = 0f;
((TMP_Text)obj).fontSizeMax = 69f;
((TMP_Text)obj).rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
((TMP_Text)obj).rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
((TMP_Text)obj).rectTransform.pivot = new Vector2(0.5f, 0.5f);
return obj;
}
public void UpdatePlayerStatusUI(AgentTarget? target)
{
if (target == null || (Object)(object)target.Agent == (Object)null)
{
Logger.Error("SpectateUI: Could not update player status text: no target!");
return;
}
PlayerGuiLayer playerLayer = GuiManager.PlayerLayer;
PUI_LocalPlayerStatus obj = ((playerLayer != null) ? playerLayer.m_playerStatus : null);
if (obj != null)
{
obj.UpdateHealth(target.Health, false);
}
if (obj != null)
{
obj.UpdateInfection(target.Infection, 0f);
}
}
private void AddMenuItem(eSpectateMenuItem item, bool enableUI = true)
{
if (_menuItemsStr.Count >= 10)
{
Logger.Warn("SpectateUI: AddMenuItem (" + item.ToString() + ") but menu is full!");
return;
}
if (_menuItems.TryGetValue(item, out (string, MenuKeybindEntry) value))
{
_menuItemsStr.Add((value.Item1, value.Item2.ToString()));
}
else
{
Logger.Warn("SpectateUI: Tried to add unknown menu item!");
}
if (enableUI)
{
EnableUI(eSpectateUIComp.Menu);
}
}
private void UpdateViewMode(bool freecam, bool enableUI = true)
{
string text = (freecam ? "<#04B065FF>FREE-LOOK</color>" : "<#FFFFFF60>FREE-LOOK</color>");
string text2 = ((!freecam) ? "<#04B065FF>FOLLOW</color>" : "<#FFFFFF60>FOLLOW</color>");
_menuViewModeStr = text + " / " + text2;
if (enableUI)
{
EnableUI(eSpectateUIComp.ViewMode);
}
}
private void UpdateSpectateTargetText(bool enableUI = true)
{
SpectateCam? instance = SpectateCam.Instance;
object obj;
if (instance == null)
{
obj = null;
}
else
{
AgentTarget? target = instance.Target;
obj = (((object)target != null) ? target.Agent.InteractionName : null);
}
if (obj == null)
{
obj = "<#FFDE21>Unknown</color>";
}
string value = (string)obj;
_specTargetStr = $"<#{"FFFFFF"}>Spectating\n<size=36>{value}</size></color>";
if (enableUI)
{
EnableUI(eSpectateUIComp.SpectateTarget);
}
}
public void SetUIState(eSpectateUIState state)
{
_uiStatePrev = _uiState;
_uiState = state;
}
public void MarkUIDirty()
{
_isUIDirty = true;
}
private void RefreshUI()
{
RefreshUI(SpectateCam.Instance?.Freecam ?? false);
}
private void RefreshUI(bool freecam)
{
_isUIDirty = false;
_uiStateRendered = _uiState;
ClearUI();
switch (_uiState)
{
case eSpectateUIState.ShowMenu:
EnableUI(eSpectateUIComp.Title);
UpdateViewMode(freecam);
AddMenuItem(eSpectateMenuItem.ExitSpectate);
AddMenuItem(eSpectateMenuItem.HideMenu);
AddMenuItem(eSpectateMenuItem.ToggleFreecam);
AddMenuItem(eSpectateMenuItem.SwitchPlayer);
AddMenuItem(eSpectateMenuItem.SelectPlayer);
AddMenuItem(eSpectateMenuItem.AdjustDistance);
AddMenuItem(eSpectateMenuItem.AdjustOrbitCenterHeight);
if (freecam)
{
if (ConfigMgr.AutoTransitionToFollowView)
{
AddMenuItem(eSpectateMenuItem.DisableFreecamAutoTransition);
}
else
{
AddMenuItem(eSpectateMenuItem.EnableFreecamAutoTransition);
}
}
else
{
AddMenuItem(eSpectateMenuItem.AdjustFollowPitch);
}
break;
case eSpectateUIState.HideMenu:
EnableUI(eSpectateUIComp.Title);
UpdateViewMode(freecam);
AddMenuItem(eSpectateMenuItem.ExitSpectate);
AddMenuItem(eSpectateMenuItem.ShowMenu);
break;
case eSpectateUIState.FPDowned:
case eSpectateUIState.FPNotDowned:
AddMenuItem(eSpectateMenuItem.EnterSpectate);
break;
}
RenderUI();
}
private void ClearUI()
{
_menuViewModeStr = "";
_menuItemsStr.Clear();
eSpectateUIComp[] values = Enum.GetValues<eSpectateUIComp>();
foreach (eSpectateUIComp key in values)
{
_uiCompState[key] = false;
}
}
private void RemoveAllUIRoots()
{
foreach (GameObject uiRoot in _uiRoots)
{
Object.Destroy((Object)(object)uiRoot);
}
_specTargetTmp = null;
_menuObj = null;
_menuTitleTmp = null;
_menuViewModeTmp = null;
_menuListObj = null;
_menuBackground = null;
_menuItemsTmp.Clear();
_uiRoots.Clear();
}
private void RegisterUIRoot(GameObject root)
{
if (!_uiRoots.Contains(root))
{
_uiRoots.Add(root);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnableUI(eSpectateUIComp comp)
{
_uiCompState[comp] = true;
}
private void RenderUI()
{
foreach (var (eSpectateUIComp3, flag2) in _uiCompState)
{
switch (eSpectateUIComp3)
{
case eSpectateUIComp.SpectateTarget:
if (flag2)
{
UpdateText(_specTargetTmp, _specTargetStr);
}
Util.SetTargetActiveIfDiff((Behaviour?)(object)_specTargetTmp, flag2);
break;
case eSpectateUIComp.Title:
if (flag2)
{
UpdateText(_menuTitleTmp, _menuTitleStr);
}
Util.SetTargetActiveIfDiff((Behaviour?)(object)_menuTitleTmp, flag2);
break;
case eSpectateUIComp.ViewMode:
if (flag2)
{
UpdateText(_menuViewModeTmp, _menuViewModeStr);
}
Util.SetTargetActiveIfDiff((Behaviour?)(object)_menuViewModeTmp, flag2);
break;
case eSpectateUIComp.Menu:
if (flag2)
{
int count = _menuItemsStr.Count;
for (int i = 0; i < 10; i++)
{
var (val, val2) = _menuItemsTmp[i];
if (i < count)
{
var (text, text2) = _menuItemsStr[i];
UpdateText(val, "<allcaps>" + text + "</allcaps>");
UpdateText(val2, "<color=orange>[" + text2 + "]</color>");
Util.SetTargetActiveIfDiff((Behaviour?)(object)val, active: true);
Util.SetTargetActiveIfDiff((Behaviour?)(object)val2, active: true);
}
else
{
Util.SetTargetActiveIfDiff((Behaviour?)(object)val, active: false);
Util.SetTargetActiveIfDiff((Behaviour?)(object)val2, active: false);
}
}
}
Util.SetTargetActiveIfDiff(_menuListObj, flag2);
break;
}
}
}
private void SetUIActive(bool active)
{
if (_wasUIActive == active)
{
return;
}
foreach (GameObject uiRoot in _uiRoots)
{
Util.SetTargetActiveIfDiff(uiRoot, active);
}
_wasUIActive = active;
}
private void UpdateText(TextMeshPro? tmp, string newText)
{
if (!((Object)(object)tmp == (Object)null) && !(((TMP_Text)tmp).text == newText) && newText != ((TMP_Text)tmp).text)
{
((TMP_Text)tmp).text = newText;
ForceTMPUpdate(tmp);
}
}
private void ForceTMPUpdate(TextMeshPro? tmp)
{
if (!((Object)(object)tmp == (Object)null))
{
((Graphic)tmp).SetAllDirty();
((TMP_Text)tmp).ForceMeshUpdate(false, false);
}
}
public void WarnFreecamNoAdjustPitch()
{
}
}
}
namespace Spectate.Config
{
public enum ConfigEntryRule
{
Min,
Max
}
public class ConfigEntryExtended<T>
{
private Dictionary<ConfigEntryRule, T> _rules = new Dictionary<ConfigEntryRule, T>();
private ConfigEntry<T> _entry;
public T Value
{
get
{
return _entry.Value;
}
set
{
_entry.Value = Enforce(value);
}
}
public object BoxedValue
{
get
{
return ((ConfigEntryBase)_entry).BoxedValue;
}
set
{
((ConfigEntryBase)_entry).BoxedValue = Enforce((T)value);
}
}
public ConfigEntryExtended(ConfigEntry<T> entry)
{
_entry = entry;
}
public bool AddRule(ConfigEntryRule rule, T ruleValue)
{
if (_rules.TryAdd(rule, ruleValue))
{
Enforce(rule);
return true;
}
return false;
}
private void Enforce()
{
T val = Enforce(_entry.Value);
if (val != null && !val.Equals(_entry.Value))
{
_entry.Value = val;
}
}
private T Enforce(T val)
{
foreach (var (configEntryRule2, val3) in _rules)
{
switch (configEntryRule2)
{
case ConfigEntryRule.Min:
if (Comparer<T>.Default.Compare(val, val3) < 0)
{
val = val3;
}
break;
case ConfigEntryRule.Max:
if (Comparer<T>.Default.Compare(val, val3) > 0)
{
val = val3;
}
break;
}
}
return val;
}
private void Enforce(ConfigEntryRule rule)
{
T value = _entry.Value;
value = Enforce(value, rule);
if (value != null && !value.Equals(_entry.Value))
{
_entry.Value = value;
}
}
private T Enforce(T val, ConfigEntryRule rule)
{
if (!_rules.TryGetValue(rule, out var value))
{
return val;
}
switch (rule)
{
case ConfigEntryRule.Min:
if (Comparer<T>.Default.Compare(val, value) < 0)
{
val = value;
}
break;
case ConfigEntryRule.Max:
if (Comparer<T>.Default.Compare(val, value) > 0)
{
val = value;
}
break;
}
return val;
}
public static implicit operator ConfigEntryExtended<T>(ConfigEntry<T> entry)
{
return new ConfigEntryExtended<T>(entry);
}
}
internal static class ConfigMgr
{
private static readonly ConfigFile Conf;
private static bool _configDirty;
private static readonly FileSystemWatcher? ConfigWatcher;
private static readonly Dictionary<string, eDevOpts> DevOptsStr2Enum;
private static readonly ConfigEntryExtended<bool> DebugConf;
private static readonly ConfigEntryExtended<string> DevOptsConf;
private static eDevOpts _devOptsVal;
private static readonly ConfigEntryExtended<bool> SwitchOnDeathConf;
private static readonly ConfigEntryExtended<bool> DefaultFreecamViewConf;
private static readonly ConfigEntryExtended<bool> AutoTransitionToFollowViewConf;
private static readonly ConfigEntryExtended<bool> NoPosLerpOnSwitchTargetConf;
private static readonly ConfigEntryExtended<float> AutoTransitionDelayConf;
private static bool _autoTransitionToFollowViewCache;
private static readonly ConfigEntryExtended<float> ScrollSensitivityConf;
private static readonly ConfigEntryExtended<float> FreecamSensitivityConf;
private static readonly ConfigEntryExtended<float> FreecamLerpGainConf;
private static readonly ConfigEntryExtended<float> CameraXZLerpGainConf;
private static readonly ConfigEntryExtended<float> CameraYLerpGainConf;
private static readonly ConfigEntryExtended<float> CameraDistanceConf;
private static readonly ConfigEntryExtended<float> CameraOrbitVerticalOffsetConf;
private static readonly ConfigEntryExtended<float> CameraPitchAngleDegConf;
private static float _cameraDistanceCache;
private static float _cameraOrbitVerticalOffsetCache;
private static float _cameraPitchAngleDegCache;
private static readonly Dictionary<SpectateInputAction, ConfigEntryExtended<KeyCode>> KeybindConfs;
private static readonly Dictionary<SpectateInputAction, KeybindSetting> KeybindSettingConfs;
public static bool Debug => DebugConf.Value;
public static bool SwitchOnDeath => SwitchOnDeathConf.Value;
public static bool DefaultFreecamView => DefaultFreecamViewConf.Value;
public static bool AutoTransitionToFollowView
{
get
{
return _autoTransitionToFollowViewCache;
}
set
{
_autoTransitionToFollowViewCache = value;
_configDirty = true;
}
}
public static bool NoPosLerpOnSwitchTarget => NoPosLerpOnSwitchTargetConf.Value;
public static float AutoTransitionDelay => AutoTransitionDelayConf.Value;
public static float ScrollSensitivity => ScrollSensitivityConf.Value;
public static float FreecamSensitivity => FreecamSensitivityConf.Value;
public static float FreecamLerpGain => FreecamLerpGainConf.Value;
public static float CameraXZLerpGain => CameraXZLerpGainConf.Value;
public static float CameraYLerpGain => CameraYLerpGainConf.Value;
public static float CameraDistance
{
get
{
return _cameraDistanceCache;
}
set
{
_cameraDistanceCache = value;
_configDirty = true;
}
}
public static float CameraOrbitVerticalOffset
{
get
{
return _cameraOrbitVerticalOffsetCache;
}
set
{
_cameraOrbitVerticalOffsetCache = value;
_configDirty = true;
}
}
public static float CameraPitchAngleDeg
{
get
{
return _cameraPitchAngleDegCache;
}
set
{
_cameraPitchAngleDegCache = value;
_configDirty = true;
}
}
public static bool DevEnables(eDevOpts opt)
{
return _devOptsVal.HasFlag(opt);
}
public static KeyCode GetKeybind(SpectateInputAction action)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
if (KeybindConfs.TryGetValue(action, out ConfigEntryExtended<KeyCode> value))
{
return value.Value;
}
Logger.Error($"GetKeybind: no config found for action {action}");
return (KeyCode)0;
}
public static void Process()
{
Logger.Info($"debug={Debug}");
_cameraDistanceCache = CameraDistanceConf.Value;
_cameraOrbitVerticalOffsetCache = CameraOrbitVerticalOffsetConf.Value;
_cameraPitchAngleDegCache = CameraPitchAngleDegConf.Value;
_autoTransitionToFollowViewCache = AutoTransitionToFollowViewConf.Value;
_devOptsVal = eDevOpts.None;
string[] array = DevOptsConf.Value.Split(' ', StringSplitOptions.RemoveEmptyEntries);
foreach (string text in array)
{
if (DevOptsStr2Enum.TryGetValue(text.Trim().ToLower(), out var value))
{
_devOptsVal |= value;
}
}
SpectateUI.Instance?.MarkUIDirty();
}
static ConfigMgr()
{
//IL_0087: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
//IL_011a: 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_0158: Expected O, but got Unknown
//IL_065d: Unknown result type (might be due to invalid IL or missing references)
_configDirty = false;
DevOptsStr2Enum = new Dictionary<string, eDevOpts>
{
["--any"] = eDevOpts.AllowSpectatingAnytime,
["--exp"] = eDevOpts.ExperimentalFeatures
};
_devOptsVal = eDevOpts.None;
_autoTransitionToFollowViewCache = false;
_cameraDistanceCache = float.NaN;
_cameraOrbitVerticalOffsetCache = float.NaN;
_cameraPitchAngleDegCache = float.NaN;
KeybindConfs = new Dictionary<SpectateInputAction, ConfigEntryExtended<KeyCode>>();
Dictionary<SpectateInputAction, KeybindSetting> obj = new Dictionary<SpectateInputAction, KeybindSetting>
{
[SpectateInputAction.ToggleSpectate] = new KeybindSetting
{
Name = "Toggle Spectate",
Description = "toggle spectate active/inactive",
DefaultKey = (KeyCode)118
},
[SpectateInputAction.ToggleFreecam] = new KeybindSetting
{
Name = "Toggle Free-Look View",
Description = "toggle free-look spectate view on/off",
DefaultKey = (KeyCode)102
},
[SpectateInputAction.ToggleAutoFollow] = new KeybindSetting
{
Name = "Toggle Auto Follow View",
Description = "toggle automatic transition to temporary follow view on/off",
DefaultKey = (KeyCode)116
}
};
KeybindSetting value = new KeybindSetting
{
Name = "Toggle Spectate Menu",
Description = "toggle spectate action menu on/off",
DefaultKey = (KeyCode)92
};
obj[SpectateInputAction.ToggleMenu] = value;
KeybindSettingConfs = obj;
string text = "Spectate.cfg";
string text2 = Path.Combine(Paths.ConfigPath, text);
Logger.Info("cfgPath = " + text2);
Conf = new ConfigFile(text2, true);
ConfigWatcher = new FileSystemWatcher(Paths.ConfigPath, text)
{
NotifyFilter = NotifyFilters.LastWrite,
EnableRaisingEvents = true
};
ConfigWatcher.Changed += async delegate
{
ConfigWatcher.EnableRaisingEvents = false;
await Task.Delay(500);
Logger.Debug("Reloading config file due to external change...");
Conf.Reload();
await Task.Delay(250);
Process();
await Task.Delay(250);
ConfigWatcher.EnableRaisingEvents = true;
};
int num = 1;
string text3 = $"({num++}) Behavior";
SwitchOnDeathConf = Conf.Bind<bool>(text3, "Switch on Death", false, "automatically switch to spectate upon death");
DefaultFreecamViewConf = Conf.Bind<bool>(text3, "Default to Free-Look View", true, "start game sessions with free-look enabled by default");
AutoTransitionToFollowViewConf = Conf.Bind<bool>(text3, "Auto Transition to Temporary Follow View", true, "automatically transition to temporary follow view after idling in free-look");
NoPosLerpOnSwitchTargetConf = Conf.Bind<bool>(text3, "No Position Smoothing on Target Switch", false, "disable camera position smoothing when switching spectate targets in free-look");
AutoTransitionDelayConf = Conf.Bind<float>(text3, "Auto Transition Delay", 3f, "delay after no mouse input in seconds before automatically transitioning to temporary follow view (min: 0.2)");
AutoTransitionDelayConf.AddRule(ConfigEntryRule.Min, 0.2f);
text3 = $"({num++}) Sensitivity";
ScrollSensitivityConf = Conf.Bind<float>(text3, "Scroll Sensitivity", 0.5f, "sensitivity for scroll wheel based adjustments (camera distance, camera pitch, orbit center offset) (min: 0.01)");
ScrollSensitivityConf.AddRule(ConfigEntryRule.Min, 0.01f);
FreecamSensitivityConf = Conf.Bind<float>(text3, "Free-Look Sensitivity", 1f, "sensitivity for free-look mouse movement (min: 0.01)");
FreecamSensitivityConf.AddRule(ConfigEntryRule.Min, 0.01f);
FreecamLerpGainConf = Conf.Bind<float>(text3, "Free-Look Smoothing Rate", 6f, "rate at which camera snaps to target: higher is snappier, lower is smoother (min: 1.0)");
FreecamLerpGainConf.AddRule(ConfigEntryRule.Min, 1f);
CameraXZLerpGainConf = Conf.Bind<float>(text3, "Camera XZ-Position Smoothing Rate", 15f, "rate at which camera horizontal position snaps to target: higher is snappier, lower is smoother (min: 7.0)");
CameraXZLerpGainConf.AddRule(ConfigEntryRule.Min, 7f);
CameraYLerpGainConf = Conf.Bind<float>(text3, "Camera Y-Position Smoothing Rate", 11f, "rate at which camera vertical position snaps to target: higher is snappier, lower is smoother (min: 7.0)");
CameraYLerpGainConf.AddRule(ConfigEntryRule.Min, 7f);
text3 = $"({num++}) Camera Settings <SYNCED>";
CameraOrbitVerticalOffsetConf = Conf.Bind<float>(text3, "Camera Orbit Vertical Offset", 0.325f, $"vertical offset of the camera orbit center/point from the player's position (min: {-1f:F2}, max: {5f:F2})");
CameraOrbitVerticalOffsetConf.AddRule(ConfigEntryRule.Min, -1f);
CameraOrbitVerticalOffsetConf.AddRule(ConfigEntryRule.Max, 5f);
CameraDistanceConf = Conf.Bind<float>(text3, "Camera Distance", 0.625f, $"distance of the camera from the orbit point (min: {0.1f:F2}, max: {5f:F2})");
CameraDistanceConf.AddRule(ConfigEntryRule.Min, 0.1f);
CameraDistanceConf.AddRule(ConfigEntryRule.Max, 5f);
CameraPitchAngleDegConf = Conf.Bind<float>(text3, "Camera Pitch Angle (deg)", -18.75f, $"pitch angle of the camera in degrees (min: {-89f:F2}, max: {89f:F2})");
CameraPitchAngleDegConf.AddRule(ConfigEntryRule.Min, -89f);
CameraPitchAngleDegConf.AddRule(ConfigEntryRule.Max, 89f);
text3 = $"({num++}) Keybinds";
foreach (KeyValuePair<SpectateInputAction, KeybindSetting> keybindSettingConf in KeybindSettingConfs)
{
keybindSettingConf.Deconstruct(out var key, out value);
SpectateInputAction key2 = key;
KeybindSetting keybindSetting = value;
KeybindConfs[key2] = Conf.Bind<KeyCode>(text3, keybindSetting.Name, keybindSetting.DefaultKey, keybindSetting.Description);
}
text3 = "(Z) Dev";
DebugConf = Conf.Bind<bool>(text3, "Enable Debug Logs", false, "debug logging");
DevOptsConf = Conf.Bind<string>(text3, "Dev Options", "", "if you know you know");
}
internal static void WriteConfigIfDirty()
{
if (_configDirty)
{
CameraDistanceConf.Value = _cameraDistanceCache;
CameraOrbitVerticalOffsetConf.Value = _cameraOrbitVerticalOffsetCache;
CameraPitchAngleDegConf.Value = _cameraPitchAngleDegCache;
AutoTransitionToFollowViewConf.Value = _autoTransitionToFollowViewCache;
Conf.Save();
_configDirty = false;
}
}
}
[Flags]
public enum eDevOpts
{
None = 0,
AllowSpectatingAnytime = 1,
ExperimentalFeatures = 2
}
public struct KeybindSetting
{
public string Name;
public string Description;
public KeyCode DefaultKey;
}
public enum SpectateInputAction
{
None,
ToggleSpectate,
ToggleFreecam,
ToggleAutoFollow,
ToggleMenu
}
}