using Comfort.Common; using EFT; using EFT.UI; using UnityEngine; namespace Terkoiz.Freecam { public class FreecamController : MonoBehaviour { private GameObject mainCamera; private Freecam freeCamScript; private BattleUIScreen playerUi; private bool uiHidden; // TODO MAYBE: // Hide player weapon // Hide version number UI element // FreeCam controller support (camera could be smoother with an analog stick, apparently) public void Update() { if (FreecamPlugin.ToggleUi.Value.IsDown()) { ToggleUi(); } if (FreecamPlugin.ToggleFreecamMode.Value.IsDown()) { ToggleCamera(); } if (FreecamPlugin.TeleportToCamera.Value.IsDown()) { MovePlayerToCamera(); } } /// /// Toggles the Freecam mode /// private void ToggleCamera() { // Get our own Player instance. Null means we're not in a raid var localPlayer = GetLocalPlayerFromWorld(); if (localPlayer == null) { return; } // If we don't have the main camera object cached, go look for it in the scene if (mainCamera == null) { // Finding a GameObject by name directly is apparantly better than searching for objects of a type. // 'FPS Camera' is our main camera instance - so we just grab that mainCamera = GameObject.Find("FPS Camera"); if (mainCamera == null) { Debug.LogError("Terkoiz.Freecam: ERROR: Failed to locate main camera"); PreloaderUI.Instance.Console.AddLog("ERROR: Failed to locate main camera", "FreeCam"); return; } } // Create the Freecam script and attach it to the main camera if (freeCamScript == null) { freeCamScript = mainCamera.AddComponent(); } // We disable the player's GameObject, which prevents the player from moving and interacting with the world while we're in Freecam mode // Also, since the camera position keeps getting updated to where the player is, disabling the player's GameObject also stops this behaviour if (!freeCamScript.IsActive) { localPlayer.gameObject.SetActive(false); freeCamScript.IsActive = true; } else { freeCamScript.IsActive = false; localPlayer.gameObject.SetActive(true); } } /// /// When triggered during Freecam mode, teleports the player to where the camera was and exits Freecam mode /// private void MovePlayerToCamera() { var localPlayer = GetLocalPlayerFromWorld(); if (localPlayer == null) { return; } // If we don't have the main camera cached, it means we have yet to enter Freecam mode and there is nowhere to teleport to if (mainCamera == null) { return; } // We basically do what ToggleCamera() does, but with extra code inbetween if (freeCamScript.IsActive) { freeCamScript.IsActive = false; // We grab the camera's position, but we subtract a bit off the Y axis, because the players coordinate origin is at the feet var position = new Vector3(mainCamera.transform.position.x, mainCamera.transform.position.y - 1.8f, mainCamera.transform.position.z); localPlayer.gameObject.transform.SetPositionAndRotation(position, mainCamera.transform.rotation); localPlayer.gameObject.SetActive(true); } } /// /// Hides the main UI (health, stamina, stance, hotbar, etc.) /// private void ToggleUi() { // Check if we're currently in a raid if (GetLocalPlayerFromWorld() == null) { return; } // If we don't have the UI Component cached, go look for it in the scene if (playerUi == null) { playerUi = GameObject.Find("BattleUIScreen").GetComponent(); if (playerUi == null) { PreloaderUI.Instance.Console.AddLog("ERROR: Failed to locate player UI", "FreeCam"); return; } } playerUi.gameObject.SetActive(uiHidden); uiHidden = !uiHidden; } /// /// Gets the current instance if it's available /// /// Local instance; returns null if the game is not in raid private static 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; if (gameWorld == null || gameWorld.RegisteredPlayers == null) { return null; } // One of the RegisterdPlayers will have the IsYourPlayer flag set, which will be our own Player instance return gameWorld.RegisteredPlayers.Find(p => p.IsYourPlayer); } } }