r2mods/ilspy_dump/ror2_csproj/RoR2/CameraRigController.cs

786 lines
22 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using JetBrains.Annotations;
using RoR2.CameraModes;
using RoR2.ConVar;
using RoR2.Networking;
using RoR2.UI;
using UnityEngine;
using UnityEngine.Rendering.PostProcessing;
using UnityEngine.ResourceManagement.AsyncOperations;
namespace RoR2;
public class CameraRigController : MonoBehaviour
{
[Obsolete("CameraMode objects are now used instead of enums.", true)]
public enum CameraMode
{
None,
PlayerBasic,
Fly,
SpectateOrbit,
SpectateUser
}
public struct AimAssistInfo
{
public HurtBox aimAssistHurtbox;
public Vector3 localPositionOnHurtbox;
public Vector3 worldPosition;
}
[Tooltip("The main camera for rendering the scene.")]
[Header("Component References")]
public Camera sceneCam;
[Tooltip("The UI camera.")]
public Camera uiCam;
[Tooltip("The skybox camera.")]
public Camera skyboxCam;
[Tooltip("The particle system to play while sprinting.")]
public ParticleSystem sprintingParticleSystem;
[Tooltip("The particle system to play while skills are disabled.")]
public ParticleSystem disabledSkillsParticleSystem;
[Header("Camera Parameters")]
[Tooltip("The default FOV of this camera.")]
public float baseFov = 60f;
[Tooltip("The viewport to use.")]
public Rect viewport = new Rect(0f, 0f, 1f, 1f);
[Tooltip("The maximum distance of the raycast used to determine the aim vector.")]
public float maxAimRaycastDistance = 1000f;
[Tooltip("If true, treat this camera as though it's in a cutscene")]
public bool isCutscene;
[Header("Near-Camera Character Dithering")]
public bool enableFading = true;
public float fadeStartDistance = 1f;
public float fadeEndDistance = 4f;
[Header("Behavior")]
[Tooltip("Whether or not to create a HUD.")]
public bool createHud = true;
[Tooltip("Whether or not this camera being enabled forces player-owned cameras to be disabled.")]
public bool suppressPlayerCameras;
[Tooltip("Forces music to be enabled for this camera.")]
public bool enableMusic;
private ulong musicListenerId;
private bool musicEnabled;
[Header("Target (for debug only)")]
public GameObject nextTarget;
public static Action OnChangeHUD;
public static Action OnHUDUpdated;
private CameraModeBase _cameraMode;
private GameObject _target;
private CameraState desiredCameraState;
public CameraState currentCameraState;
public bool doNotOverrideCameraState;
private CameraState lerpCameraState;
private float lerpCameraTime = 1f;
private float lerpCameraTimeScale = 1f;
private ICameraStateProvider overrideCam;
private CameraModeBase.CameraModeContext cameraModeContext;
private NetworkUser _viewer;
private LocalUser _localUserViewer;
private static GameObject DamageNumberManagerPrefab;
private static GameObject HudPrefab;
private static string previousHudPath;
public CameraTargetParams targetParams;
private const string musicSystemDeviceShareSet = "Music_Audio_Device";
public AimAssistInfo lastAimAssist;
public AimAssistInfo aimAssist;
private static List<CameraRigController> instancesList = new List<CameraRigController>();
public static readonly ReadOnlyCollection<CameraRigController> readOnlyInstancesList = instancesList.AsReadOnly();
public static FloatConVar aimStickExponent = new FloatConVar("aim_stick_exponent", ConVarFlags.None, "1", "The exponent for stick input used for aiming.");
public static FloatConVar aimStickDualZoneThreshold = new FloatConVar("aim_stick_dual_zone_threshold", ConVarFlags.None, "0.90", "The threshold for stick dual zone behavior.");
public static FloatConVar aimStickDualZoneSlope = new FloatConVar("aim_stick_dual_zone_slope", ConVarFlags.None, "0.40", "The slope value for stick dual zone behavior.");
public static FloatConVar aimStickDualZoneSmoothing = new FloatConVar("aim_stick_smoothing", ConVarFlags.None, "0.05", "The smoothing value for stick aiming.");
public static FloatConVar aimStickGlobalScale = new FloatConVar("aim_stick_global_scale", ConVarFlags.Archive, "1.00", "The global sensitivity scale for stick aiming.");
public static FloatConVar aimStickAssistMinSlowdownScale = new FloatConVar("aim_stick_assist_min_slowdown_scale", ConVarFlags.None, "1", "The MIN amount the sensitivity scales down when passing over an enemy.");
public static FloatConVar aimStickAssistMaxSlowdownScale = new FloatConVar("aim_stick_assist_max_slowdown_scale", ConVarFlags.None, "0.4", "The MAX amount the sensitivity scales down when passing over an enemy. UNUSED");
public static FloatConVar aimStickAssistMinDelta = new FloatConVar("aim_stick_assist_min_delta", ConVarFlags.None, "0", "The MIN amount in radians the aim assist will turn towards");
public static FloatConVar aimStickAssistMaxDelta = new FloatConVar("aim_stick_assist_max_delta", ConVarFlags.None, "1.57", "The MAX amount in radians the aim assist will turn towards");
public static FloatConVar aimStickAssistMaxInputHelp = new FloatConVar("aim_stick_assist_max_input_help", ConVarFlags.None, "0.2", "The amount, from 0-1, that the aim assist will actually ADD magnitude towards. Helps you keep target while strafing. CURRENTLY UNUSED.");
public static FloatConVar aimStickAssistMaxSize = new FloatConVar("aim_stick_assist_max_size", ConVarFlags.None, "3", "The size, as a coefficient, of the aim assist 'white' zone.");
public static FloatConVar aimStickAssistMinSize = new FloatConVar("aim_stick_assist_min_size", ConVarFlags.None, "1", "The minimum size, as a percentage of the GUI, of the aim assist 'red' zone.");
public static BoolConVar enableSprintSensitivitySlowdown = new BoolConVar("enable_sprint_sensitivity_slowdown", ConVarFlags.Archive, "1", "Enables sensitivity reduction while sprinting.");
private float hitmarkerAlpha;
private float hitmarkerTimer;
public bool disableSpectating { get; set; }
public CameraModeBase cameraMode
{
get
{
return _cameraMode;
}
set
{
if (_cameraMode != value)
{
_cameraMode?.OnUninstall(this);
_cameraMode = value;
_cameraMode?.OnInstall(this);
}
}
}
public HUD hud { get; private set; }
public GameObject firstPersonTarget { get; private set; }
public TeamIndex targetTeamIndex { get; private set; } = TeamIndex.None;
public CharacterBody targetBody { get; private set; }
public Vector3 rawScreenShakeDisplacement { get; private set; }
public Vector3 crosshairWorldPosition { get; private set; }
public bool hasOverride => overrideCam != null;
public bool isControlAllowed
{
get
{
if (hasOverride)
{
return overrideCam.IsUserControlAllowed(this);
}
return true;
}
}
public bool isHudAllowed
{
get
{
if ((bool)target)
{
if (hasOverride)
{
return overrideCam.IsHudAllowed(this);
}
return true;
}
return false;
}
}
public GameObject target
{
get
{
return _target;
}
private set
{
if ((object)_target != value)
{
GameObject oldTarget = _target;
_target = value;
bool flag = _target;
targetParams = (flag ? target.GetComponent<CameraTargetParams>() : null);
targetBody = (flag ? target.GetComponent<CharacterBody>() : null);
cameraMode?.OnTargetChanged(this, new CameraModeBase.OnTargetChangedArgs
{
oldTarget = oldTarget,
newTarget = _target
});
CameraRigController.onCameraTargetChanged?.Invoke(this, target);
}
}
}
public NetworkUser viewer
{
get
{
return _viewer;
}
set
{
_viewer = value;
localUserViewer = (_viewer ? _viewer.localUser : null);
}
}
public LocalUser localUserViewer
{
get
{
return _localUserViewer;
}
private set
{
if (_localUserViewer != value)
{
if (_localUserViewer != null)
{
_localUserViewer.cameraRigController = null;
}
_localUserViewer = value;
if (_localUserViewer != null)
{
_localUserViewer.cameraRigController = this;
}
if ((bool)hud)
{
hud.localUserViewer = _localUserViewer;
}
}
}
}
public HurtBox lastCrosshairHurtBox { get; private set; }
public static event Action<CameraRigController, GameObject> onCameraTargetChanged;
public static event Action<CameraRigController> onCameraEnableGlobal;
public static event Action<CameraRigController> onCameraDisableGlobal;
private void StartStateLerp(float lerpDuration)
{
lerpCameraState = currentCameraState;
if (lerpDuration > 0f)
{
lerpCameraTime = 0f;
lerpCameraTimeScale = 1f / lerpDuration;
}
else
{
lerpCameraTime = 1f;
lerpCameraTimeScale = 0f;
}
}
public void SetOverrideCam(ICameraStateProvider newOverrideCam, float lerpDuration = 1f)
{
if (newOverrideCam != overrideCam)
{
if (overrideCam != null && newOverrideCam == null)
{
cameraMode?.MatchState(in cameraModeContext, in currentCameraState);
}
overrideCam = newOverrideCam;
StartStateLerp(lerpDuration);
}
}
public bool IsOverrideCam(ICameraStateProvider testOverrideCam)
{
return overrideCam == testOverrideCam;
}
public static IEnumerator InitializeReferences()
{
AsyncOperationHandle<GameObject> handle2 = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/DamageNumberManager");
while (!handle2.IsDone)
{
yield return null;
}
DamageNumberManagerPrefab = handle2.Result;
previousHudPath = GetHUDPath();
handle2 = LegacyResourcesAPI.LoadAsync<GameObject>(previousHudPath);
while (!handle2.IsDone)
{
yield return null;
}
HudPrefab = handle2.Result;
}
private void Start()
{
RoR2Application.onUpdate += EarlyUpdate;
OnChangeHUD = (Action)Delegate.Combine(OnChangeHUD, new Action(UpdateHUD));
UpdateHUD();
if ((bool)uiCam)
{
uiCam.transform.parent = null;
uiCam.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
}
if (!DamageNumberManager.instance)
{
if (DamageNumberManagerPrefab != null)
{
UnityEngine.Object.Instantiate(DamageNumberManagerPrefab);
}
else
{
AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/DamageNumberManager");
asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
{
UnityEngine.Object.Instantiate(x.Result);
};
}
}
currentCameraState = new CameraState
{
position = base.transform.position,
rotation = base.transform.rotation,
fov = baseFov
};
cameraMode = CameraModePlayerBasic.playerBasic;
if (enableMusic && (!RoR2Application.isInLocalMultiPlayer || _viewer.localUser.inputPlayer.name == "PlayerMain"))
{
EnableMusicForCamera();
}
}
private void UpdateHUD()
{
if (createHud)
{
if ((bool)hud)
{
UnityEngine.Object.Destroy(hud.gameObject);
}
string hUDPath = GetHUDPath();
if (HudPrefab == null || hUDPath != previousHudPath)
{
HudPrefab = LegacyResourcesAPI.Load<GameObject>(hUDPath);
previousHudPath = hUDPath;
}
GameObject gameObject = UnityEngine.Object.Instantiate(HudPrefab);
hud = gameObject.GetComponent<HUD>();
hud.cameraRigController = this;
SetPostProcessVolumeExclusive(hud.scoreboardPostProcessVolume);
hud.GetComponent<Canvas>().worldCamera = uiCam;
hud.GetComponent<CrosshairManager>().cameraRigController = this;
hud.localUserViewer = localUserViewer;
OnHUDUpdated?.Invoke();
}
}
[CanBeNull]
private static string GetHUDPath()
{
if (NetworkUser.readOnlyLocalPlayersList == null || NetworkUser.readOnlyLocalPlayersList.Count < 1)
{
return "Prefabs/HUDSimple";
}
UserProfile userProfile = NetworkUser.readOnlyLocalPlayersList[0]?.localUser?.userProfile;
if (userProfile != null)
{
switch ((HudType)userProfile.hudSizeMode)
{
case HudType.Default:
return "Prefabs/HUDSimple";
case HudType.Large:
return "Prefabs/HUDSimple_Big";
case HudType.Auto:
return "Prefabs/HUDSimple_Big";
default:
Debug.LogWarning(string.Format("Undefined {0}. Value : {1}. Resorting to default HUD.", "HudType", userProfile.hudSizeMode));
return "Prefabs/HUDSimple";
}
}
return "Prefabs/HUDSimple";
}
private void OnEnable()
{
instancesList.Add(this);
if ((bool)uiCam)
{
uiCam.gameObject.SetActive(value: true);
}
if ((bool)hud)
{
hud.gameObject.SetActive(value: true);
}
CameraRigController.onCameraEnableGlobal?.Invoke(this);
}
private void OnDisable()
{
CameraRigController.onCameraDisableGlobal?.Invoke(this);
if ((bool)uiCam)
{
uiCam.gameObject.SetActive(value: false);
}
if ((bool)hud)
{
hud.gameObject.SetActive(value: false);
}
instancesList.Remove(this);
}
private void OnDestroy()
{
RoR2Application.onUpdate -= EarlyUpdate;
OnChangeHUD = (Action)Delegate.Remove(OnChangeHUD, new Action(UpdateHUD));
cameraMode = null;
if ((bool)uiCam)
{
UnityEngine.Object.Destroy(uiCam.gameObject);
}
if ((bool)hud)
{
UnityEngine.Object.Destroy(hud.gameObject);
}
DisableMusicForCamera();
}
private void EarlyUpdate()
{
target = nextTarget;
if ((bool)targetBody)
{
targetTeamIndex = targetBody.teamComponent.teamIndex;
}
if (Time.deltaTime != 0f && !isCutscene)
{
lerpCameraTime += Time.deltaTime * lerpCameraTimeScale;
firstPersonTarget = null;
sceneCam.rect = viewport;
GenerateCameraModeContext(out cameraModeContext);
if (cameraMode != null)
{
cameraMode.CollectLookInput(in cameraModeContext, out var result);
CameraModeBase cameraModeBase = cameraMode;
ref CameraModeBase.CameraModeContext context = ref cameraModeContext;
CameraModeBase.ApplyLookInputArgs args = new CameraModeBase.ApplyLookInputArgs
{
lookInput = result.lookInput
};
cameraModeBase.ApplyLookInput(in context, in args);
}
}
}
private void LateUpdate()
{
if (Time.deltaTime == 0f || isCutscene)
{
return;
}
CameraState cameraState = currentCameraState;
if (cameraMode != null && cameraModeContext.cameraInfo.cameraRigController != null && !doNotOverrideCameraState)
{
cameraMode.Update(in cameraModeContext, out var result);
cameraState = result.cameraState;
firstPersonTarget = result.firstPersonTarget;
crosshairWorldPosition = result.crosshairWorldPosition;
SetParticleSystemActive(result.showSprintParticles, sprintingParticleSystem);
SetParticleSystemActive(result.showDisabledSkillsParticles, disabledSkillsParticleSystem);
}
if ((bool)hud)
{
CharacterMaster targetMaster = (targetBody ? targetBody.master : null);
hud.targetMaster = targetMaster;
}
CameraState cameraState2 = cameraState;
if (overrideCam != null)
{
if (!(overrideCam is UnityEngine.Object @object) || (bool)@object)
{
overrideCam.GetCameraState(this, ref cameraState2);
}
else
{
overrideCam = null;
}
}
if (lerpCameraTime >= 1f)
{
currentCameraState = cameraState2;
}
else
{
currentCameraState = CameraState.Lerp(ref lerpCameraState, ref cameraState2, RemapLerpTime(lerpCameraTime));
}
SetCameraState(currentCameraState);
}
public void UpdatePreviousCameraState(Vector3 position, Quaternion rotation)
{
cameraModeContext.cameraInfo.previousCameraState.position = position;
cameraModeContext.cameraInfo.previousCameraState.rotation = rotation;
}
private void GenerateCameraModeContext(out CameraModeBase.CameraModeContext result)
{
result.cameraInfo = default(CameraModeBase.CameraInfo);
result.targetInfo = default(CameraModeBase.TargetInfo);
result.viewerInfo = default(CameraModeBase.ViewerInfo);
ref CameraModeBase.CameraInfo cameraInfo = ref result.cameraInfo;
ref CameraModeBase.TargetInfo targetInfo = ref result.targetInfo;
ref CameraModeBase.ViewerInfo viewerInfo = ref result.viewerInfo;
cameraInfo.cameraRigController = this;
cameraInfo.sceneCam = sceneCam;
cameraInfo.overrideCam = overrideCam;
cameraInfo.previousCameraState = currentCameraState;
cameraInfo.baseFov = baseFov;
targetInfo.target = (target ? target : null);
targetInfo.body = targetBody;
targetInfo.inputBank = targetInfo.target?.GetComponent<InputBankTest>();
if (targetBody != null && targetBody.currentVehicle != null && targetBody.currentVehicle.targetParams != null)
{
targetInfo.targetParams = targetBody.currentVehicle.targetParams;
}
else
{
targetInfo.targetParams = targetParams;
}
targetInfo.teamIndex = targetInfo.target?.GetComponent<TeamComponent>()?.teamIndex ?? TeamIndex.None;
targetInfo.isSprinting = (bool)targetInfo.body && targetInfo.body.isSprinting;
targetInfo.skillsAreDisabled = (bool)targetInfo.body && targetInfo.body.allSkillsDisabled;
targetInfo.master = targetInfo.body?.master;
targetInfo.networkUser = targetInfo.master?.playerCharacterMasterController?.networkUser;
targetInfo.networkedViewAngles = targetInfo.networkUser?.GetComponent<NetworkedViewAngles>();
targetInfo.isViewerControlled = (bool)targetInfo.networkUser && (object)targetInfo.networkUser == localUserViewer?.currentNetworkUser;
viewerInfo.localUser = localUserViewer;
viewerInfo.userProfile = localUserViewer?.userProfile;
viewerInfo.inputPlayer = localUserViewer?.inputPlayer;
viewerInfo.eventSystem = localUserViewer?.eventSystem;
viewerInfo.hasCursor = (bool)viewerInfo.eventSystem && viewerInfo.eventSystem.isCursorVisible;
viewerInfo.isUIFocused = localUserViewer?.isUIFocused ?? false;
}
public void CloneCameraContext(CameraRigController cloneThisCamera)
{
if (!(cloneThisCamera == null))
{
cameraModeContext = cloneThisCamera.cameraModeContext;
}
}
public float Raycast(Ray ray, float maxDistance, float wallCushion)
{
int num = 0;
num = HGPhysics.SphereCastAll(out var hits, ray.origin, wallCushion, ray.direction, maxDistance, LayerIndex.world.mask, QueryTriggerInteraction.Ignore);
float num2 = maxDistance;
for (int i = 0; i < num; i++)
{
float distance = hits[i].distance;
if (distance < num2)
{
Collider collider = hits[i].collider;
if ((bool)collider && !collider.GetComponent<NonSolidToCamera>())
{
num2 = distance;
}
}
}
HGPhysics.ReturnResults(hits);
return num2;
}
private static float RemapLerpTime(float t)
{
float num = 1f;
float num2 = 0f;
float num3 = 1f;
if ((t /= num / 2f) < 1f)
{
return num3 / 2f * t * t + num2;
}
return (0f - num3) / 2f * ((t -= 1f) * (t - 2f) - 1f) + num2;
}
public void SetCameraState(CameraState cameraState)
{
currentCameraState = cameraState;
float num = ((localUserViewer == null) ? 1f : localUserViewer.userProfile.screenShakeScale);
Vector3 position = cameraState.position;
rawScreenShakeDisplacement = ShakeEmitter.ComputeTotalShakeAtPoint(cameraState.position);
Vector3 vector = rawScreenShakeDisplacement * num;
Vector3 position2 = position + vector;
if (vector != Vector3.zero && Physics.SphereCast(position, direction: vector, radius: sceneCam.nearClipPlane, hitInfo: out var hitInfo, maxDistance: vector.magnitude, layerMask: LayerIndex.world.mask, queryTriggerInteraction: QueryTriggerInteraction.Ignore))
{
position2 = position + vector.normalized * hitInfo.distance;
}
base.transform.SetPositionAndRotation(position2, cameraState.rotation);
if ((bool)sceneCam)
{
sceneCam.fieldOfView = cameraState.fov;
}
}
public static Ray ModifyAimRayIfApplicable(Ray originalAimRay, GameObject target, out float extraRaycastDistance)
{
CameraRigController cameraRigController = null;
for (int i = 0; i < readOnlyInstancesList.Count; i++)
{
CameraRigController cameraRigController2 = readOnlyInstancesList[i];
if (cameraRigController2.target == target && cameraRigController2._localUserViewer.cachedBodyObject == target && !cameraRigController2.hasOverride)
{
cameraRigController = cameraRigController2;
break;
}
}
if ((bool)cameraRigController)
{
Camera camera = cameraRigController.sceneCam;
extraRaycastDistance = (originalAimRay.origin - camera.transform.position).magnitude;
return camera.ViewportPointToRay(new Vector2(0.5f, 0.5f));
}
extraRaycastDistance = 0f;
return originalAimRay;
}
private void SetSprintParticlesActive(bool newSprintParticlesActive)
{
if (!sprintingParticleSystem)
{
return;
}
ParticleSystem.MainModule main = sprintingParticleSystem.main;
if (newSprintParticlesActive)
{
main.loop = true;
if (!sprintingParticleSystem.isPlaying)
{
sprintingParticleSystem.Play();
}
}
else
{
main.loop = false;
}
}
private void SetParticleSystemActive(bool newParticlesActive, ParticleSystem particleSystem)
{
if (!particleSystem)
{
return;
}
ParticleSystem.MainModule main = particleSystem.main;
if (newParticlesActive)
{
main.loop = true;
if (!particleSystem.isPlaying)
{
particleSystem.Play();
}
}
else
{
main.loop = false;
}
}
public void SetPostProcessVolumeExclusive(PostProcessVolume volume)
{
if (!(volume == null) && !(sceneCam == null))
{
volume.targetLayer = sceneCam.GetComponent<PostProcessLayer>();
}
}
[InitDuringStartup]
private static void Init()
{
SceneCamera.onSceneCameraPreCull += delegate(SceneCamera sceneCam)
{
sceneCam.cameraRigController.sprintingParticleSystem.gameObject.layer = LayerIndex.defaultLayer.intVal;
};
SceneCamera.onSceneCameraPostRender += delegate(SceneCamera sceneCam)
{
sceneCam.cameraRigController.sprintingParticleSystem.gameObject.layer = LayerIndex.noDraw.intVal;
};
}
public static bool IsObjectSpectatedByAnyCamera(GameObject gameObject)
{
for (int i = 0; i < instancesList.Count; i++)
{
if (instancesList[i].target == gameObject)
{
return true;
}
}
return false;
}
[ContextMenu("Print Debug Info")]
private void PrintDebugInfo()
{
Debug.LogFormat("hasOverride={0} overrideCam={1} isControlAllowed={2}", hasOverride, overrideCam, isControlAllowed);
}
public void EnableMusicForCamera(string deviceShareSet = "Music_Audio_Device")
{
GameObject gameObject = new GameObject("MusicListener", typeof(AkGameObj), typeof(AkAudioListener));
Transform obj = gameObject.transform;
obj.localPosition = Vector3.zero;
obj.localRotation = Quaternion.identity;
obj.localScale = Vector3.one;
obj.SetParent(sceneCam.transform, worldPositionStays: false);
AkOutputSettings in_Settings = new AkOutputSettings(deviceShareSet);
ulong[] array = new ulong[1] { AkSoundEngine.GetAkGameObjectID(gameObject) };
AkSoundEngine.AddOutput(in_Settings, out var out_pDeviceID, array, (uint)array.Length);
musicListenerId = out_pDeviceID;
musicEnabled = true;
}
public void DisableMusicForCamera()
{
if (musicEnabled)
{
AkSoundEngine.RemoveOutput(musicListenerId);
}
}
}