From 7d49cc66361ab5e3818ba77e03b69406d85616e0 Mon Sep 17 00:00:00 2001 From: artehe <112902041+artehe@users.noreply.github.com> Date: Fri, 24 May 2024 21:47:38 +0100 Subject: [PATCH 1/6] Have freecam on death and also allow for first person following of pmcs --- Source/Configuration/PluginConfigSettings.cs | 4 +- Source/Coop/FreeCamera/FreeCamera.cs | 189 ++++++++++++++---- .../Coop/FreeCamera/FreeCameraController.cs | 180 ++++++++--------- 3 files changed, 238 insertions(+), 135 deletions(-) diff --git a/Source/Configuration/PluginConfigSettings.cs b/Source/Configuration/PluginConfigSettings.cs index c92b2ecbd..3cc4c2c1e 100644 --- a/Source/Configuration/PluginConfigSettings.cs +++ b/Source/Configuration/PluginConfigSettings.cs @@ -121,12 +121,12 @@ public bool SETTING_DEBUGShowPlayerList public int WaitingTimeBeforeStart { get; private set; } - public int BlackScreenOnDeathTime + public float BlackScreenOnDeathTime { get { return StayInTarkovPlugin.Instance.Config.Bind - ("Coop", "BlackScreenOnDeathTime", 500, new ConfigDescription("How long to wait until your death waits to become a Free Camera")).Value; + ("Coop", "BlackScreenOnDeathTime", 5F, new ConfigDescription("How long to wait after death until you become a Free Camera")).Value; } } diff --git a/Source/Coop/FreeCamera/FreeCamera.cs b/Source/Coop/FreeCamera/FreeCamera.cs index f516ec0ea..885ec6ffc 100644 --- a/Source/Coop/FreeCamera/FreeCamera.cs +++ b/Source/Coop/FreeCamera/FreeCamera.cs @@ -1,4 +1,9 @@ -using JetBrains.Annotations; +#nullable enable + +using StayInTarkov.Coop.Components.CoopGameComponents; +using StayInTarkov.Coop.Players; +using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace StayInTarkov.Coop.FreeCamera @@ -10,85 +15,195 @@ namespace StayInTarkov.Coop.FreeCamera /// https://gist.github.com/ashleydavis/f025c03a9221bc840a2b /// /// This is HEAVILY based on Terkoiz's work found here. Thanks for your work Terkoiz! - /// https://dev.sp-tarkov.com/Terkoiz/Freecam/raw/branch/master/project/Terkoiz.Freecam/FreecamController.cs + /// https://dev.sp-tarkov.com/Terkoiz/Freecam/raw/branch/master/project/Terkoiz.Freecam/Freecam.cs /// public class FreeCamera : MonoBehaviour { + private CoopPlayer? _playerSpectating; + private bool _isSpectatingPlayer = false; + public bool IsActive = false; - [UsedImplicitly] - public void Update() + private void StopSpectatingPlayer() { - if (!IsActive) + if (_playerSpectating != null) { - return; + _playerSpectating = null; } + if (_isSpectatingPlayer) + { + _isSpectatingPlayer = false; + transform.parent = null; + } + } + + private void SpectateNextPlayer() + { + UpdatePlayerSpectator(true); + } - var fastMode = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift); - var movementSpeed = fastMode ? 20f : 3f; + private void SpectatePreviousPlayer() + { + UpdatePlayerSpectator(false); + } + /// + /// Updates the player beign followed by the camera + /// + /// True for the next player and false for the previous player + private void UpdatePlayerSpectator(bool nextPlayer) + { + List players = [.. SITGameComponent.GetCoopGameComponent() + .Players + .Values + .Where(x => !x.IsYourPlayer && !x.IsAI && x.HealthController.IsAlive) + ]; + if (players.Count > 0) + { + if (_playerSpectating == null) + { + if (players[0] != null) + { + _playerSpectating = players[0]; + } + } + else + { + // We want to look for the next player + if (nextPlayer) + { + int playerIndex = players.IndexOf(_playerSpectating) + 1; + if (players.Count - 1 >= playerIndex) + { + _playerSpectating = players[playerIndex]; + } + else + { + _playerSpectating = players[0]; + } + } + // We are going backwards looking for the previous player + else + { + int playerIndex = players.IndexOf(_playerSpectating) - 1; + if (playerIndex >= 0) + { + _playerSpectating = players[playerIndex]; + } + else + { + _playerSpectating = players[players.Count - 1]; + } + } + + } + + if (_playerSpectating != null) + { + // Attach the camera to the player we are spectating; + transform.parent = _playerSpectating?.PlayerBones.Head.Original; + transform.localPosition = new Vector3(-0.05f, 0.17f, 0f); + transform.localEulerAngles = new Vector3(260, 80, 0); + _isSpectatingPlayer = true; + } + } + else + { + StopSpectatingPlayer(); + } + } + + private void MoveAndRotateCamera() + { + bool fastMode = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift); + float movementSpeed = fastMode ? 20f : 3f; + + // Strafe Right if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) { transform.position += (-transform.right * (movementSpeed * Time.deltaTime)); } + // Strafe Left if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) { transform.position += (transform.right * (movementSpeed * Time.deltaTime)); } + // Forwards if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) { transform.position += (transform.forward * (movementSpeed * Time.deltaTime)); } + // Backwards if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) { transform.position += (-transform.forward * (movementSpeed * Time.deltaTime)); } - if (true) + // Up + if (Input.GetKey(KeyCode.Q)) { - if (Input.GetKey(KeyCode.Q)) - { - transform.position += (transform.up * (movementSpeed * Time.deltaTime)); - } + transform.position += (transform.up * (movementSpeed * Time.deltaTime)); + } - if (Input.GetKey(KeyCode.E)) - { - transform.position += (-transform.up * (movementSpeed * Time.deltaTime)); - } + // Down + if (Input.GetKey(KeyCode.E)) + { + transform.position += (-transform.up * (movementSpeed * Time.deltaTime)); + } - if (Input.GetKey(KeyCode.R) || Input.GetKey(KeyCode.PageUp)) - { - transform.position += (Vector3.up * (movementSpeed * Time.deltaTime)); - } + // Up + if (Input.GetKey(KeyCode.R) || Input.GetKey(KeyCode.PageUp)) + { + transform.position += (Vector3.up * (movementSpeed * Time.deltaTime)); + } - if (Input.GetKey(KeyCode.F) || Input.GetKey(KeyCode.PageDown)) - { - transform.position += (-Vector3.up * (movementSpeed * Time.deltaTime)); - } + // Down + if (Input.GetKey(KeyCode.F) || Input.GetKey(KeyCode.PageDown)) + { + transform.position += (-Vector3.up * (movementSpeed * Time.deltaTime)); } float newRotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * 3f; float newRotationY = transform.localEulerAngles.x - Input.GetAxis("Mouse Y") * 3f; transform.localEulerAngles = new Vector3(newRotationY, newRotationX, 0f); - - //if (FreecamPlugin.CameraMousewheelZoom.Value) - //{ - // float axis = Input.GetAxis("Mouse ScrollWheel"); - // if (axis != 0) - // { - // var zoomSensitivity = fastMode ? FreecamPlugin.CameraFastZoomSpeed.Value : FreecamPlugin.CameraZoomSpeed.Value; - // transform.position += transform.forward * (axis * zoomSensitivity); - // } - //} } - [UsedImplicitly] - private void OnDestroy() + protected void OnDestroy() { Destroy(this); } + + protected void Update() + { + if (!IsActive) + { + return; + } + + // Spectate the next player + if (Input.GetKey(KeyCode.Mouse0)) + { + SpectateNextPlayer(); + } + // Spectate the previous player + else if (Input.GetKey(KeyCode.Mouse1)) + { + SpectatePreviousPlayer(); + } + // Stop following the currently selected player + else if (Input.GetKey(KeyCode.End)) + { + StopSpectatingPlayer(); + } + + // If we aren't spectating anyone then just update the camera normally + if (!_isSpectatingPlayer) + { + MoveAndRotateCamera(); + } + } } } \ No newline at end of file diff --git a/Source/Coop/FreeCamera/FreeCameraController.cs b/Source/Coop/FreeCamera/FreeCameraController.cs index 71676ec26..6cd49a17e 100644 --- a/Source/Coop/FreeCamera/FreeCameraController.cs +++ b/Source/Coop/FreeCamera/FreeCameraController.cs @@ -1,13 +1,15 @@ -using BSG.CameraEffects; +using BepInEx.Logging; +using BSG.CameraEffects; using Comfort.Common; using EFT; using EFT.CameraControl; using EFT.UI; -using HarmonyLib; using StayInTarkov.Configuration; using StayInTarkov.Coop.Components.CoopGameComponents; +using StayInTarkov.Coop.Players; using StayInTarkov.Coop.SITGameModes; using System; +using System.Collections; using UnityEngine; using UnityStandardAssets.ImageEffects; @@ -27,15 +29,19 @@ public class FreeCameraController : MonoBehaviour private bool _uiHidden; private GamePlayerOwner _gamePlayerOwner; + private DateTime _lastTime = DateTime.MinValue; + + private ManualLogSource Logger { get; } = BepInEx.Logging.Logger.CreateLogSource("FreeCameraController"); + private CoopPlayer Player => (CoopPlayer) Singleton.Instance.MainPlayer; public GameObject CameraParent { get; set; } public Camera CameraFreeCamera { get; private set; } public Camera CameraMain { get; private set; } - void Awake() + protected void Awake() { CameraParent = new GameObject("CameraParent"); - var FCamera = CameraParent.GetOrAddComponent(); + Camera FCamera = CameraParent.GetOrAddComponent(); FCamera.enabled = false; } @@ -61,107 +67,100 @@ public void Start() { return; } + + Player.OnPlayerDead += Player_OnPlayerDead; } - private DateTime _lastTime = DateTime.MinValue; + private IEnumerator PlayerDeathRoutine() + { + yield return new WaitForSeconds(PluginConfigSettings.Instance.CoopSettings.BlackScreenOnDeathTime); + + var fpsCamInstance = CameraClass.Instance; + if (fpsCamInstance == null) + { + Logger.LogDebug("fpsCamInstance for camera is null"); + yield break; + } - int DeadTime = 0; + // Reset FOV after died + if (fpsCamInstance.Camera != null) + fpsCamInstance.Camera.fieldOfView = Singleton.Instance.Game.Settings.FieldOfView; + + EffectsController effectsController = fpsCamInstance.EffectsController; + if (effectsController == null) + { + Logger.LogDebug("effects controller for camera is null"); + yield break; + } + + DisableAndDestroyEffect(effectsController.GetComponent()); + DisableAndDestroyEffect(effectsController.GetComponent()); + DisableAndDestroyEffect(effectsController.GetComponent()); + DisableAndDestroyEffect(effectsController.GetComponent()); + DisableAndDestroyEffect(effectsController.GetComponent()); + DisableAndDestroyEffect(effectsController.GetComponent()); + DisableAndDestroyEffect(effectsController.GetComponent()); + DisableAndDestroyEffect(effectsController.GetComponent()); + DisableAndDestroyEffect(effectsController.GetComponent()); + DisableAndDestroyEffect(effectsController.GetComponent()); + //DisableAndDestroyEffect(effectsController.GetComponent()); + + var ccBlends = fpsCamInstance.EffectsController.GetComponents(); + if (ccBlends != null) + foreach (var ccBlend in ccBlends) + DisableAndDestroyEffect(ccBlend); + + DisableAndDestroyEffect(fpsCamInstance.VisorEffect); + DisableAndDestroyEffect(fpsCamInstance.NightVision); + DisableAndDestroyEffect(fpsCamInstance.ThermalVision); + + // Go to free camera mode + ToggleCamera(); + ToggleUi(); + } + + private void Player_OnPlayerDead(EFT.Player player, IPlayer lastAggressor, DamageInfo damageInfo, EBodyPart part) + { + Player.OnPlayerDead -= Player_OnPlayerDead; + StartCoroutine(PlayerDeathRoutine()); + } public void Update() { if (_gamePlayerOwner == null) return; - if (_gamePlayerOwner.Player == null) + if (Player == null) return; - if (_gamePlayerOwner.Player.PlayerHealthController == null) + if (Player.PlayerHealthController == null) return; - if (!SITGameComponent.TryGetCoopGameComponent(out var coopGC)) + if (!SITGameComponent.TryGetCoopGameComponent(out SITGameComponent coopGC)) return; - var coopGame = coopGC.LocalGameInstance as CoopSITGame; + CoopSITGame coopGame = coopGC.LocalGameInstance as CoopSITGame; if (coopGame == null) return; var quitState = coopGC.GetQuitState(); - - if (_gamePlayerOwner.Player.PlayerHealthController.IsAlive - && (Input.GetKey(KeyCode.F9) || (quitState != SITGameComponent.EQuitState.NONE && !_freeCamScript.IsActive)) - && _lastTime < DateTime.Now.AddSeconds(-3)) + if (Player.PlayerHealthController.IsAlive && + (Input.GetKey(KeyCode.F9) || (quitState != SITGameComponent.EQuitState.NONE && !_freeCamScript.IsActive)) && + _lastTime < DateTime.Now.AddSeconds(-3)) { _lastTime = DateTime.Now; ToggleCamera(); ToggleUi(); - } - - if (!_gamePlayerOwner.Player.PlayerHealthController.IsAlive) - { - // This is to make sure the screen effect remove code only get executed once, instead of running every frame. - if (DeadTime == -1) - return; - - if (DeadTime < PluginConfigSettings.Instance.CoopSettings.BlackScreenOnDeathTime) - { - DeadTime++; - } - else - { - DeadTime = -1; - - var fpsCamInstance = CameraClass.Instance; - if (fpsCamInstance == null) - return; - - // Reset FOV after died - if (fpsCamInstance.Camera != null) - fpsCamInstance.Camera.fieldOfView = Singleton.Instance.Game.Settings.FieldOfView; - - var effectsController = fpsCamInstance.EffectsController; - if (effectsController == null) - return; - - DisableAndDestroyEffect(effectsController.GetComponent()); - DisableAndDestroyEffect(effectsController.GetComponent()); - DisableAndDestroyEffect(effectsController.GetComponent()); - DisableAndDestroyEffect(effectsController.GetComponent()); - DisableAndDestroyEffect(effectsController.GetComponent()); - DisableAndDestroyEffect(effectsController.GetComponent()); - DisableAndDestroyEffect(effectsController.GetComponent()); - DisableAndDestroyEffect(effectsController.GetComponent()); - DisableAndDestroyEffect(effectsController.GetComponent()); - DisableAndDestroyEffect(effectsController.GetComponent()); - //DisableAndDestroyEffect(effectsController.GetComponent()); - - var ccBlends = fpsCamInstance.EffectsController.GetComponents(); - if (ccBlends != null) - foreach (var ccBlend in ccBlends) - DisableAndDestroyEffect(ccBlend); - - DisableAndDestroyEffect(fpsCamInstance.VisorEffect); - DisableAndDestroyEffect(fpsCamInstance.NightVision); - DisableAndDestroyEffect(fpsCamInstance.ThermalVision); - - // Go to free camera mode - ToggleCamera(); - ToggleUi(); - } - } + } } - //DateTime? _lastOcclusionCullCheck = null; - //Vector3? _playerDeathOrExitPosition; - //bool showAtDeathOrExitPosition; - /// /// Toggles the Freecam mode /// public void ToggleCamera() { // Get our own Player instance. Null means we're not in a raid - var localPlayer = GetLocalPlayerFromWorld(); - if (localPlayer == null) + if (Player == null) return; if (!_freeCamScript.IsActive) @@ -169,16 +168,14 @@ public void ToggleCamera() GameObject[] allGameObject = Resources.FindObjectsOfTypeAll(); foreach (GameObject gobj in allGameObject) { - if (gobj.GetComponent() != null) - { - gobj.GetComponent().ForceEnable(true); - } + gobj.GetComponent()?.ForceEnable(true); } - SetPlayerToFreecamMode(localPlayer); + Logger.LogDebug($"Enabled Culling on {allGameObject.Length}."); + SetPlayerToFreecamMode(Player); } else { - SetPlayerToFirstPersonMode(localPlayer); + SetPlayerToFirstPersonMode(Player); } } @@ -188,21 +185,20 @@ public void ToggleCamera() public void ToggleUi() { // Check if we're currently in a raid - if (GetLocalPlayerFromWorld() == null) + if (Player == null) return; // If we don't have the UI Component cached, go look for it in the scene if (_playerUi == null) { - var gameObject = GameObject.Find("BattleUIScreen"); + GameObject gameObject = GameObject.Find("BattleUIScreen"); if (gameObject == null) return; _playerUi = gameObject.GetComponent(); - if (_playerUi == null) { - //FreecamPlugin.Logger.LogError("Failed to locate player UI"); + Logger.LogError("Failed to locate player UI"); return; } } @@ -224,11 +220,9 @@ private void SetPlayerToFreecamMode(EFT.Player localPlayer) // This means our character will be fully visible, while letting the camera move freely localPlayer.PointOfView = EPointOfView.ThirdPerson; - // Get the PlayerBody reference. It's a protected field, so we have to use traverse to fetch it - var playerBody = Traverse.Create(localPlayer).Field("_playerBody").Value; - if (playerBody != null) + if (localPlayer.PlayerBody != null) { - playerBody.PointOfView.Value = EPointOfView.FreeCamera; + localPlayer.PlayerBody.PointOfView.Value = EPointOfView.FreeCamera; localPlayer.GetComponent().UpdatePointOfView(); } @@ -244,12 +238,6 @@ private void SetPlayerToFirstPersonMode(EFT.Player localPlayer) { _freeCamScript.IsActive = false; - //if (FreecamPlugin.CameraRememberLastPosition.Value) - //{ - // _lastPosition = _mainCamera.transform.position; - // _lastRotation = _mainCamera.transform.rotation; - //} - // re-enable _gamePlayerOwner _gamePlayerOwner.enabled = true; @@ -265,7 +253,7 @@ private void SetPlayerToFirstPersonMode(EFT.Player localPlayer) private EFT.Player GetLocalPlayerFromWorld() { // If the GameWorld instance is null or has no RegisteredPlayers, it most likely means we're not in a raid - var gameWorld = Singleton.Instance; + GameWorld gameWorld = Singleton.Instance; if (gameWorld == null || gameWorld.MainPlayer == null) return null; @@ -284,7 +272,7 @@ public void DisableAndDestroyEffect(MonoBehaviour effect) public void OnDestroy() { - GameObject.Destroy(CameraParent); + Destroy(CameraParent); // Destroy FreeCamScript before FreeCamController if exists Destroy(_freeCamScript); From af3ed699dbaef146680b24f5f41efa70d247684c Mon Sep 17 00:00:00 2001 From: artehe <112902041+artehe@users.noreply.github.com> Date: Sat, 25 May 2024 20:07:27 +0100 Subject: [PATCH 2/6] filter to only human players --- Source/Coop/FreeCamera/FreeCamera.cs | 10 ++++++---- Source/Coop/FreeCamera/FreeCameraController.cs | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Source/Coop/FreeCamera/FreeCamera.cs b/Source/Coop/FreeCamera/FreeCamera.cs index 885ec6ffc..6edecb15a 100644 --- a/Source/Coop/FreeCamera/FreeCamera.cs +++ b/Source/Coop/FreeCamera/FreeCamera.cs @@ -33,8 +33,8 @@ private void StopSpectatingPlayer() if (_isSpectatingPlayer) { _isSpectatingPlayer = false; - transform.parent = null; } + transform.parent = null; } private void SpectateNextPlayer() @@ -53,11 +53,13 @@ private void SpectatePreviousPlayer() /// True for the next player and false for the previous player private void UpdatePlayerSpectator(bool nextPlayer) { - List players = [.. SITGameComponent.GetCoopGameComponent() + SITGameComponent coopGameComponent = SITGameComponent.GetCoopGameComponent(); + List players = [.. coopGameComponent .Players .Values - .Where(x => !x.IsYourPlayer && !x.IsAI && x.HealthController.IsAlive) + .Where(x => !x.IsYourPlayer && x.HealthController.IsAlive && x.GroupId?.Contains("SIT") == true) ]; + if (players.Count > 0) { if (_playerSpectating == null) @@ -102,7 +104,7 @@ private void UpdatePlayerSpectator(bool nextPlayer) { // Attach the camera to the player we are spectating; transform.parent = _playerSpectating?.PlayerBones.Head.Original; - transform.localPosition = new Vector3(-0.05f, 0.17f, 0f); + transform.localPosition = new Vector3(-0.05f, 0.17f, -0.5f); transform.localEulerAngles = new Vector3(260, 80, 0); _isSpectatingPlayer = true; } diff --git a/Source/Coop/FreeCamera/FreeCameraController.cs b/Source/Coop/FreeCamera/FreeCameraController.cs index 6cd49a17e..e0f0126c4 100644 --- a/Source/Coop/FreeCamera/FreeCameraController.cs +++ b/Source/Coop/FreeCamera/FreeCameraController.cs @@ -170,7 +170,6 @@ public void ToggleCamera() { gobj.GetComponent()?.ForceEnable(true); } - Logger.LogDebug($"Enabled Culling on {allGameObject.Length}."); SetPlayerToFreecamMode(Player); } else From e26eb32970bbdeed3ff490149cd93e1a8d61546f Mon Sep 17 00:00:00 2001 From: artehe <112902041+artehe@users.noreply.github.com> Date: Sun, 26 May 2024 10:39:05 +0100 Subject: [PATCH 3/6] I went too far with the position --- Source/Coop/FreeCamera/FreeCamera.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Coop/FreeCamera/FreeCamera.cs b/Source/Coop/FreeCamera/FreeCamera.cs index 6edecb15a..c705e8e14 100644 --- a/Source/Coop/FreeCamera/FreeCamera.cs +++ b/Source/Coop/FreeCamera/FreeCamera.cs @@ -104,7 +104,7 @@ private void UpdatePlayerSpectator(bool nextPlayer) { // Attach the camera to the player we are spectating; transform.parent = _playerSpectating?.PlayerBones.Head.Original; - transform.localPosition = new Vector3(-0.05f, 0.17f, -0.5f); + transform.localPosition = new Vector3(-0.05f, 0.17f, -0.05f); transform.localEulerAngles = new Vector3(260, 80, 0); _isSpectatingPlayer = true; } From c547bdd8d985e5e490cd8b219f9bcc9f954bcac2 Mon Sep 17 00:00:00 2001 From: artehe <112902041+artehe@users.noreply.github.com> Date: Sun, 26 May 2024 12:29:55 +0100 Subject: [PATCH 4/6] clean up some bits --- Source/Coop/FreeCamera/FreeCamera.cs | 50 +++++++++--------- .../Coop/FreeCamera/FreeCameraController.cs | 51 ++++++++++++------- 2 files changed, 60 insertions(+), 41 deletions(-) diff --git a/Source/Coop/FreeCamera/FreeCamera.cs b/Source/Coop/FreeCamera/FreeCamera.cs index c705e8e14..199faf5e1 100644 --- a/Source/Coop/FreeCamera/FreeCamera.cs +++ b/Source/Coop/FreeCamera/FreeCamera.cs @@ -21,8 +21,9 @@ public class FreeCamera : MonoBehaviour { private CoopPlayer? _playerSpectating; private bool _isSpectatingPlayer = false; + private bool _isUpdatingPlayerSpectate = false; - public bool IsActive = false; + public bool IsActive { get; set; } = false; private void StopSpectatingPlayer() { @@ -30,11 +31,11 @@ private void StopSpectatingPlayer() { _playerSpectating = null; } - if (_isSpectatingPlayer) + if (transform.parent != null) { - _isSpectatingPlayer = false; + transform.parent = null; } - transform.parent = null; + _isSpectatingPlayer = false; } private void SpectateNextPlayer() @@ -52,7 +53,13 @@ private void SpectatePreviousPlayer() /// /// True for the next player and false for the previous player private void UpdatePlayerSpectator(bool nextPlayer) - { + { + if (_isUpdatingPlayerSpectate) + { + return; + } + _isUpdatingPlayerSpectate = true; + SITGameComponent coopGameComponent = SITGameComponent.GetCoopGameComponent(); List players = [.. coopGameComponent .Players @@ -71,40 +78,35 @@ private void UpdatePlayerSpectator(bool nextPlayer) } else { - // We want to look for the next player + int playerIndex = 0; if (nextPlayer) { - int playerIndex = players.IndexOf(_playerSpectating) + 1; - if (players.Count - 1 >= playerIndex) + // We want to look for the next player in the list + playerIndex = players.IndexOf(_playerSpectating) + 1; + if (playerIndex > players.Count - 1) { - _playerSpectating = players[playerIndex]; - } - else - { - _playerSpectating = players[0]; + playerIndex = 0; } } - // We are going backwards looking for the previous player else { - int playerIndex = players.IndexOf(_playerSpectating) - 1; - if (playerIndex >= 0) - { - _playerSpectating = players[playerIndex]; - } - else + // We want to find the previous player + playerIndex = players.IndexOf(_playerSpectating) - 1; + if (playerIndex < 0) { - _playerSpectating = players[players.Count - 1]; + playerIndex = players.Count - 1; } } - + + // Update the player we are spectating + _playerSpectating = players[playerIndex]; } if (_playerSpectating != null) { // Attach the camera to the player we are spectating; transform.parent = _playerSpectating?.PlayerBones.Head.Original; - transform.localPosition = new Vector3(-0.05f, 0.17f, -0.05f); + transform.localPosition = new Vector3(-0.02f, 0.16f, -0.04f); transform.localEulerAngles = new Vector3(260, 80, 0); _isSpectatingPlayer = true; } @@ -113,6 +115,8 @@ private void UpdatePlayerSpectator(bool nextPlayer) { StopSpectatingPlayer(); } + + _isUpdatingPlayerSpectate = false; } private void MoveAndRotateCamera() diff --git a/Source/Coop/FreeCamera/FreeCameraController.cs b/Source/Coop/FreeCamera/FreeCameraController.cs index e0f0126c4..eaac61653 100644 --- a/Source/Coop/FreeCamera/FreeCameraController.cs +++ b/Source/Coop/FreeCamera/FreeCameraController.cs @@ -1,4 +1,6 @@ -using BepInEx.Logging; +#nullable enable + +using BepInEx.Logging; using BSG.CameraEffects; using Comfort.Common; using EFT; @@ -22,21 +24,20 @@ namespace StayInTarkov.Coop.FreeCamera public class FreeCameraController : MonoBehaviour { - //private GameObject _mainCamera; - private FreeCamera _freeCamScript; + private FreeCamera? _freeCamScript; - private BattleUIScreen _playerUi; + private BattleUIScreen? _playerUi; private bool _uiHidden; - private GamePlayerOwner _gamePlayerOwner; + private GamePlayerOwner? _gamePlayerOwner; private DateTime _lastTime = DateTime.MinValue; private ManualLogSource Logger { get; } = BepInEx.Logging.Logger.CreateLogSource("FreeCameraController"); private CoopPlayer Player => (CoopPlayer) Singleton.Instance.MainPlayer; - public GameObject CameraParent { get; set; } - public Camera CameraFreeCamera { get; private set; } - public Camera CameraMain { get; private set; } + public GameObject? CameraParent { get; set; } + public Camera? CameraFreeCamera { get; private set; } + public Camera? CameraMain { get; private set; } protected void Awake() { @@ -62,7 +63,7 @@ public void Start() } // Get GamePlayerOwner component - _gamePlayerOwner = GetLocalPlayerFromWorld().GetComponentInChildren(); + _gamePlayerOwner = GetLocalPlayerFromWorld()?.GetComponentInChildren(); if (_gamePlayerOwner == null) { return; @@ -73,7 +74,7 @@ public void Start() private IEnumerator PlayerDeathRoutine() { - yield return new WaitForSeconds(PluginConfigSettings.Instance.CoopSettings.BlackScreenOnDeathTime); + yield return new WaitForSeconds(PluginConfigSettings.Instance?.CoopSettings.BlackScreenOnDeathTime ?? 5); var fpsCamInstance = CameraClass.Instance; if (fpsCamInstance == null) @@ -139,13 +140,13 @@ public void Update() if (!SITGameComponent.TryGetCoopGameComponent(out SITGameComponent coopGC)) return; - CoopSITGame coopGame = coopGC.LocalGameInstance as CoopSITGame; + CoopSITGame coopGame = (CoopSITGame) coopGC.LocalGameInstance; if (coopGame == null) return; var quitState = coopGC.GetQuitState(); if (Player.PlayerHealthController.IsAlive && - (Input.GetKey(KeyCode.F9) || (quitState != SITGameComponent.EQuitState.NONE && !_freeCamScript.IsActive)) && + (Input.GetKey(KeyCode.F9) || (quitState != SITGameComponent.EQuitState.NONE && _freeCamScript?.IsActive == false)) && _lastTime < DateTime.Now.AddSeconds(-3)) { _lastTime = DateTime.Now; @@ -163,7 +164,7 @@ public void ToggleCamera() if (Player == null) return; - if (!_freeCamScript.IsActive) + if (_freeCamScript?.IsActive == false) { GameObject[] allGameObject = Resources.FindObjectsOfTypeAll(); foreach (GameObject gobj in allGameObject) @@ -225,8 +226,14 @@ private void SetPlayerToFreecamMode(EFT.Player localPlayer) localPlayer.GetComponent().UpdatePointOfView(); } - _gamePlayerOwner.enabled = false; - _freeCamScript.IsActive = true; + if (_gamePlayerOwner != null) + { + _gamePlayerOwner.enabled = false; + } + if (_freeCamScript != null) + { + _freeCamScript.IsActive = true; + } } /// @@ -235,10 +242,16 @@ private void SetPlayerToFreecamMode(EFT.Player localPlayer) /// private void SetPlayerToFirstPersonMode(EFT.Player localPlayer) { - _freeCamScript.IsActive = false; + if (_freeCamScript != null) + { + _freeCamScript.IsActive = true; + } // re-enable _gamePlayerOwner - _gamePlayerOwner.enabled = true; + if (_gamePlayerOwner != null) + { + _gamePlayerOwner.enabled = false; + } localPlayer.PointOfView = EPointOfView.FirstPerson; CameraClass.Instance.SetOcclusionCullingEnabled(true); @@ -249,12 +262,14 @@ private void SetPlayerToFirstPersonMode(EFT.Player localPlayer) /// Gets the current instance if it's available /// /// Local instance; returns null if the game is not in raid - private EFT.Player GetLocalPlayerFromWorld() + private EFT.Player? GetLocalPlayerFromWorld() { // If the GameWorld instance is null or has no RegisteredPlayers, it most likely means we're not in a raid GameWorld gameWorld = Singleton.Instance; if (gameWorld == null || gameWorld.MainPlayer == null) + { return null; + } // One of the RegisteredPlayers will have the IsYourPlayer flag set, which will be our own Player instance return gameWorld.MainPlayer; From 7f83b7bbe2a0a93a3e7fcc2d399b77f60cf4fb35 Mon Sep 17 00:00:00 2001 From: artehe <112902041+artehe@users.noreply.github.com> Date: Thu, 30 May 2024 22:40:47 +0100 Subject: [PATCH 5/6] Improve switching camera and move the camera to possibly the shoulder --- Source/Coop/FreeCamera/FreeCamera.cs | 46 ++++++++++++++++++---------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/Source/Coop/FreeCamera/FreeCamera.cs b/Source/Coop/FreeCamera/FreeCamera.cs index 199faf5e1..1735052b4 100644 --- a/Source/Coop/FreeCamera/FreeCamera.cs +++ b/Source/Coop/FreeCamera/FreeCamera.cs @@ -21,7 +21,7 @@ public class FreeCamera : MonoBehaviour { private CoopPlayer? _playerSpectating; private bool _isSpectatingPlayer = false; - private bool _isUpdatingPlayerSpectate = false; + private bool _spectateRightShoulder = true; public bool IsActive { get; set; } = false; @@ -53,13 +53,7 @@ private void SpectatePreviousPlayer() /// /// True for the next player and false for the previous player private void UpdatePlayerSpectator(bool nextPlayer) - { - if (_isUpdatingPlayerSpectate) - { - return; - } - _isUpdatingPlayerSpectate = true; - + { SITGameComponent coopGameComponent = SITGameComponent.GetCoopGameComponent(); List players = [.. coopGameComponent .Players @@ -104,19 +98,17 @@ private void UpdatePlayerSpectator(bool nextPlayer) if (_playerSpectating != null) { + _isSpectatingPlayer = true; + // Attach the camera to the player we are spectating; transform.parent = _playerSpectating?.PlayerBones.Head.Original; - transform.localPosition = new Vector3(-0.02f, 0.16f, -0.04f); - transform.localEulerAngles = new Vector3(260, 80, 0); - _isSpectatingPlayer = true; + SetPlayerSpectateShoulder(); } } else { StopSpectatingPlayer(); } - - _isUpdatingPlayerSpectate = false; } private void MoveAndRotateCamera() @@ -177,6 +169,23 @@ private void MoveAndRotateCamera() transform.localEulerAngles = new Vector3(newRotationY, newRotationX, 0f); } + private void SetPlayerSpectateShoulder() + { + if (_isSpectatingPlayer) + { + if (_spectateRightShoulder) + { + transform.localEulerAngles = new Vector3(240, 80, 0); + transform.localPosition = new Vector3(0.24f, 0.12f, -0.16f); + } + else + { + transform.localEulerAngles = new Vector3(240, 80, 0); + transform.localPosition = new Vector3(0.24f, 0.12f, 0.16f); + } + } + } + protected void OnDestroy() { Destroy(this); @@ -190,20 +199,25 @@ protected void Update() } // Spectate the next player - if (Input.GetKey(KeyCode.Mouse0)) + if (Input.GetKeyDown(KeyCode.Mouse0)) { SpectateNextPlayer(); } // Spectate the previous player - else if (Input.GetKey(KeyCode.Mouse1)) + else if (Input.GetKeyDown(KeyCode.Mouse1)) { SpectatePreviousPlayer(); } // Stop following the currently selected player - else if (Input.GetKey(KeyCode.End)) + else if (Input.GetKeyDown(KeyCode.End)) { StopSpectatingPlayer(); } + else if (Input.GetKeyDown(KeyCode.Home)) + { + _spectateRightShoulder = !_spectateRightShoulder; + SetPlayerSpectateShoulder(); + } // If we aren't spectating anyone then just update the camera normally if (!_isSpectatingPlayer) From 395909ccdff5430f3010b12882ebcd4ed049a5e0 Mon Sep 17 00:00:00 2001 From: artehe <112902041+artehe@users.noreply.github.com> Date: Fri, 31 May 2024 10:18:26 +0100 Subject: [PATCH 6/6] update camera positions better --- Source/Coop/FreeCamera/FreeCamera.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Source/Coop/FreeCamera/FreeCamera.cs b/Source/Coop/FreeCamera/FreeCamera.cs index 1735052b4..8c32df980 100644 --- a/Source/Coop/FreeCamera/FreeCamera.cs +++ b/Source/Coop/FreeCamera/FreeCamera.cs @@ -101,7 +101,6 @@ private void UpdatePlayerSpectator(bool nextPlayer) _isSpectatingPlayer = true; // Attach the camera to the player we are spectating; - transform.parent = _playerSpectating?.PlayerBones.Head.Original; SetPlayerSpectateShoulder(); } } @@ -175,13 +174,15 @@ private void SetPlayerSpectateShoulder() { if (_spectateRightShoulder) { - transform.localEulerAngles = new Vector3(240, 80, 0); - transform.localPosition = new Vector3(0.24f, 0.12f, -0.16f); + transform.parent = _playerSpectating?.PlayerBones.RightShoulder.Original; + transform.localEulerAngles = new Vector3(250, 270, 270); + transform.localPosition = new Vector3(-0.12f, 0.04f, 0.16f); } else { - transform.localEulerAngles = new Vector3(240, 80, 0); - transform.localPosition = new Vector3(0.24f, 0.12f, 0.16f); + transform.parent = _playerSpectating?.PlayerBones.LeftShoulder.Original; + transform.localEulerAngles = new Vector3(250, 90, 270); + transform.localPosition = new Vector3(-0.12f, -0.04f, -0.16f); } } }