diff --git a/TarkovUniformAim/TarkovUniformAim.csproj b/TarkovUniformAim/TarkovUniformAim.csproj index b1afccf..d3f5134 100644 --- a/TarkovUniformAim/TarkovUniformAim.csproj +++ b/TarkovUniformAim/TarkovUniformAim.csproj @@ -44,10 +44,18 @@ ..\..\MyFirstPlugin\MyFirstPlugin\lib\BepInEx.dll + + False + E:\SPT-AKI\SPT-AKI 3.0.0\EscapeFromTarkov_Data\Managed\Comfort.dll + False ..\..\libs\EFT Trainer DLLs\Newtonsoft.Json.dll + + False + E:\SPT-AKI\SPT-AKI 3.0.0\EscapeFromTarkov_Data\Managed\Sirenix.Serialization.dll + @@ -64,6 +72,8 @@ + + diff --git a/TarkovUniformAim/UniformAimCore.cs b/TarkovUniformAim/UniformAimCore.cs new file mode 100644 index 0000000..2690854 --- /dev/null +++ b/TarkovUniformAim/UniformAimCore.cs @@ -0,0 +1,57 @@ +using BepInEx; +using System; +using UnityEngine; + +namespace UniformAim +{ + public class Core + { + //math stuff + //Get screen aspect ratio + public static float GetAspectRatio() + { + return Camera.allCameras[0].aspect; + } + //Calculate horizontal FOV based on vertical FOV and aspect ratio + public static float CalculateHFOV(float FOV) + { + float vFOVRad = FOV / 2 * Mathf.Deg2Rad; + float hFOVRad = (float)(2 * Math.Atan(GetAspectRatio() * Math.Tan(vFOVRad))); + + return (float)(hFOVRad * Mathf.Rad2Deg); + } + + //calculate sensitivity based on FOV delta and coefficient + public static float CalculateSensitivity(float aimedFOV, float hipFOV) + { + //calculate horizontal FOV values for inputs + aimedFOV = CalculateHFOV(aimedFOV) * Mathf.Deg2Rad; + hipFOV = CalculateHFOV(hipFOV) * Mathf.Deg2Rad; + + float exponent = (float)(100f / Plugin.configCoeff.Value); + + float tanRatio = (float)(Math.Tan(aimedFOV / 2) / (Math.Tan(hipFOV / 2))); + + float sensitivity = Plugin.configSens.Value / 100f; + + float result = (float)Math.Pow(tanRatio, exponent) * sensitivity; + + return result; + } + + //check if BaseOpticCamera is present and active + public static bool isScopeCameraActive() + { + if(Camera.allCamerasCount > 1) { return Camera.allCameras[1].GetComponent().isActiveAndEnabled; } + return false; + } + //figure out current fov based on scope and in-game camera statuses + public static float DetermineCurrentFOV() + { + //dirty fix for the Ultima MP-155 shotgun + if (Plugin.currentFPSCameraFOV> 35 && isScopeCameraActive() && Plugin.currentScopeCameraFOV == 15) { return Plugin.currentFPSCameraFOV; } + + if (Plugin.SelectedScope == 0 && isScopeCameraActive()) { return Plugin.currentScopeCameraFOV; } else { return Plugin.currentFPSCameraFOV; } + } + } +} diff --git a/TarkovUniformAim/UniformAimPatch.cs b/TarkovUniformAim/UniformAimPatch.cs index 6f4175f..a83e139 100644 --- a/TarkovUniformAim/UniformAimPatch.cs +++ b/TarkovUniformAim/UniformAimPatch.cs @@ -2,6 +2,7 @@ using EFT; using System.Reflection; + namespace UniformAim { public class UpdateSensitivityPatch : ModulePatch @@ -67,6 +68,4 @@ namespace UniformAim Plugin.isAiming = ____isAiming; } } - - } \ No newline at end of file diff --git a/TarkovUniformAim/UniformAimPlugin.cs b/TarkovUniformAim/UniformAimPlugin.cs index 115b69b..696ed3d 100644 --- a/TarkovUniformAim/UniformAimPlugin.cs +++ b/TarkovUniformAim/UniformAimPlugin.cs @@ -1,26 +1,30 @@ using BepInEx; using BepInEx.Configuration; -using System; using UnityEngine; + + namespace UniformAim { - [BepInPlugin("com.greg.tarkovuniformaim", "Uniform Aim for Tarkov", "1.0.0")] + [BepInPlugin("com.greg.tarkovuniformaim", "Uniform Aim for Tarkov", "1.1.0")] [BepInProcess("EscapeFromTarkov.exe")] public class Plugin : BaseUnityPlugin { //Bepinex.Configurator fields public static ConfigEntry configFOV; + int[] FOVRange = new int[2] { 50, 75 }; + public static ConfigEntry configFOVRangeOverride; + public static ConfigEntry configCoeff; public static ConfigEntry configSens; - public static ConfigEntry configUseHFOV; + public static ConfigEntry configDebug; - //TODO: figure out a way to read game settings to default the configFOV.Value to whatever the player has already set - //TODO: figure out a way to read game settings to apply configSens.Value as a multiplier on top of Tarkov's stock sensitivity setting + //only for persistence + public static ConfigEntry inGameSens; public static float mySens = 1f; - public static float aimingSens; + //public static float aimingSens; //sight data for hacky workarounds public static int SelectedScope = 0; @@ -28,66 +32,18 @@ namespace UniformAim public static bool isAiming = false; //human-friendly names for variables used later - float FPSCameraFOV; - float ScopeFOV; - float currentFOV; - - //values to prevent unnecessary repetition - float cachedFOV; - string cachedDebugInfo; - - //aspect ratio for further calculations - float GetAspectRatio() + public static float baseCameraFOV = 75; + public static float currentFPSCameraFOV = 75; + public static float currentScopeCameraFOV = 75; + + void printDebug() { - return Camera.allCameras[0].aspect; - } - //calculate horizontal FOV based on vertical FOV, currently unused but could be useful in the future - float CalculateHFOV(float FOV) - { - float vFOVRad = FOV / 2 * Mathf.Deg2Rad; - float hFOVRad = (float)(2 * Math.Atan(GetAspectRatio() * Math.Tan(vFOVRad))); - - return (float)(hFOVRad * Mathf.Rad2Deg); - } - //calculate sensitivity based on FOV difference and the coefficient - float CalculateSensitivity(float aimedFOV, float hipFOV) - { - //clamp to avoid invalid values - aimedFOV = Mathf.Clamp(aimedFOV, 1f, 75f) * Mathf.Deg2Rad; - hipFOV = Mathf.Clamp(hipFOV, 1f, 75f) * Mathf.Deg2Rad; - - //check if configUseHFOV is enabled, convert to horizontal degrees if true - if (configUseHFOV.Value) - { - aimedFOV = CalculateHFOV(aimedFOV); - hipFOV = CalculateHFOV(hipFOV); - } - - float exponent = (float)(100f / configCoeff.Value); - - float tanRatio = (float)(Math.Tan(aimedFOV / 2) / Math.Tan(hipFOV / 2)); - - float sensitivity = configSens.Value / 100f; - - float result = (float)Math.Pow(tanRatio, exponent) * sensitivity; - - return result; - } - - //determine if the player is looking through the scope - bool isScopeCameraActive() - { - if (Camera.allCamerasCount > 1) { return Camera.allCameras[1].GetComponent().isActiveAndEnabled; } - return false; - } - - //determine the correct FOV for calculations - void DetermineCurrentFOV() - { - if (SelectedScope == 0 && isScopeCameraActive()) { currentFOV = ScopeFOV; } else { currentFOV = FPSCameraFOV; } - - //dirty fix for the Ultima MP-155 shotgun - if (FPSCameraFOV > 35 && isScopeCameraActive() && ScopeFOV == 15) { currentFOV = FPSCameraFOV; } + Logger.LogInfo($"\nIn-Game FOV: {configFOV.Value} In-Game Sens: {inGameSens.Value} FOV Override: {configFOVRangeOverride.Value}" + + $"\nFPS Camera FOV: {currentFPSCameraFOV} / {Core.CalculateHFOV(currentFPSCameraFOV)} BaseOpticCamera FOV: {currentScopeCameraFOV} / {Core.CalculateHFOV(currentScopeCameraFOV)} CurrentFOV: {Core.DetermineCurrentFOV()} / {Core.CalculateHFOV(Core.DetermineCurrentFOV())}" + + $"\nisAiming? {isAiming} SelectedScope: {SelectedScope} SelectedScopeMode:{SelectedScopeMode}" + + $"\nCalculated sensitivity: {Core.CalculateSensitivity(Core.DetermineCurrentFOV(), baseCameraFOV)}" + + $"\nAspect Ratio: {Core.GetAspectRatio()}" + + $"\nFinal Sensitivity: {mySens * inGameSens.Value}"); } void Awake() @@ -98,38 +54,64 @@ namespace UniformAim new get_SelectedScopeModePatch().Enable(); new get_IsAimingPatch().Enable(); + //override FOV range + configFOVRangeOverride = Config.Bind("General", "FOV Override", false, new ConfigDescription("Override FOV range for compatibility with other mods. Requires restart.")); + if (configFOVRangeOverride.Value) + { + FOVRange[0] = 1; FOVRange[1] = 178; + } + //add configuration slider for field of view - configFOV = Config.Bind("General", "FOV", 75, new ConfigDescription("In-game Field of View value", new AcceptableValueRange(51, 75))); + configFOV = Config.Bind("General", "FOV", 75, new ConfigDescription("In-game Field of View value", new AcceptableValueRange(FOVRange[0], FOVRange[1]))); //add coefficient slider configCoeff = Config.Bind("General", "Coefficient", 133, new ConfigDescription("Coefficient - increases sensitivity at higher zoom levels", new AcceptableValueRange(1, 300))); //add sensitivity slider - configSens = Config.Bind("General", "Sensitivity", 25, new ConfigDescription("Sensitivity while aiming", new AcceptableValueRange(1, 200))); + configSens = Config.Bind("General", "Sensitivity", 100, new ConfigDescription("Fine control over sensitivity while aiming", new AcceptableValueRange(1, 200))); + + //enable debug logging + configDebug = Config.Bind("Debug", "Enable logging?", false, new ConfigDescription("Enables logging in BepInEx console")); + + //settings for persistence, these values get updated when the in-game menu is opened + inGameSens = Config.Bind("¡Do not touch unless necessary!", "In-game Aiming Sensitivity value", 0.5f, new ConfigDescription("Should update on its own - kept for persistence between sessions.", new AcceptableValueRange(0.1f, 5.0f))); - //use HFOV instead of VFOV for sensitivity calculations - configUseHFOV = Config.Bind("General", "Use Horizontal FOV?", true, new ConfigDescription("Toggles between using Horizontal FOV and Vertical FOV for sensitivity calculations.")); } - void FixedUpdate() { - //FixedUpdate() at 50Hz (Unity default) tickrate appears to resolve the issue of this script breaking when AI spawns. + //FixedUpdate() at 50Hz (Unity default) tickrate appears to resolve the issue of this script breaking when AI spawns Time.fixedDeltaTime = (1f / 50f); - if (isAiming) - { - //Grab FOV values for calculation - FPSCameraFOV = Camera.allCameras[0].fieldOfView; //Camera[0] tends to be FPS Camera - if (Camera.allCamerasCount > 1) { ScopeFOV = Camera.allCameras[1].fieldOfView; } //Camera[1] tends to be BaseOpticCamera + //check if the game is running + var isRunning = Utils.checkIsReady(); + if (!isRunning) return; - //Figure out if the FPSCamera is zoomed in, prevents the script from ticking while the player is healing - if (FPSCameraFOV < configFOV.Value) + if (isRunning) + { + if (Utils.SetRootObject() != null) { + var rootObject = Utils.SetRootObject(); + //only update these values if the menu has been opened, otherwise read the config + if (rootObject.transform.Find("Game Settings").gameObject.activeInHierarchy) + { + if (!configFOVRangeOverride.Value) { configFOV.Value = 50 + Utils.GetInGameFOV(rootObject); } + inGameSens.Value = Utils.GetInGameSens(rootObject); + } + } + //cgheck if the player is aiming + if (isAiming) { - DetermineCurrentFOV(); - //do not update sensitivity if currentFOV hasn't changed - if (cachedFOV != currentFOV) { mySens = CalculateSensitivity(currentFOV, configFOV.Value); cachedFOV = currentFOV; } + //Grab FOV values for calculation + currentFPSCameraFOV = Camera.allCameras[0].fieldOfView; //Camera[0] tends to be FPS Camera + if (Camera.allCamerasCount > 1) { currentScopeCameraFOV= Camera.allCameras[1].fieldOfView; } //Camera[1] tends to be BaseOpticCamera + + //Figure out if the FPSCamera is zoomed in, prevents the script from ticking while the player is healing + if (currentFPSCameraFOV < configFOV.Value) { + mySens = inGameSens.Value * Core.CalculateSensitivity(Core.DetermineCurrentFOV(), configFOV.Value); + } } } + //Print debug info in BepInEx console + if (configDebug.Value) printDebug(); } } } diff --git a/TarkovUniformAim/UniformAimUtils.cs b/TarkovUniformAim/UniformAimUtils.cs new file mode 100644 index 0000000..b6f9f90 --- /dev/null +++ b/TarkovUniformAim/UniformAimUtils.cs @@ -0,0 +1,66 @@ +using Comfort.Common; +using EFT; +using UnityEngine; + + + +namespace UniformAim +{ + public class Utils + { + public static bool isPlaying = false; + public static GameObject rootObject = null; + + public static bool checkIsReady() + { + var gameWorld = Singleton.Instance; + var sessionResultPanel = Singleton.Instance; + + if (gameWorld == null + || gameWorld.AllPlayers == null + || gameWorld.AllPlayers.Count <= 0 + || sessionResultPanel != null) + { + return false; + } + return true; + } + + public static bool checkPlayerIsAlive() + { + var gameWorld = Singleton.Instance; + var currentHealth = gameWorld.AllPlayers[0].HealthController.GetBodyPartHealth(EBodyPart.Common).Current; + + if (currentHealth > 0) { return true; } else { return false; } + } + + + public static GameObject SetRootObject() + { + string path = "Common UI/Common UI/SettingsScreen"; + + if(GameObject.Find(path) != null) + { + GameObject rootObject = GameObject.Find(path); + return rootObject; + } + else { return null; } + } + + public static int GetInGameFOV(GameObject root) + { + GameObject fovObject = root.transform.Find("Game Settings/Image/Other Settings/FOV/FOV").gameObject; + int rootFOV = fovObject.GetComponent().CurrentValue(); + + return rootFOV; + } + + public static float GetInGameSens(GameObject root) + { + GameObject sensObject = root.transform.Find("Control Settings/ControlPanel/Mouse Settings/Sensitivity Aiming Panel/Mouse Sensitivity Aiming").gameObject; + float rootSens = sensObject.GetComponent().CurrentValue(); + + return rootSens; + } + } +}