Code has been reorganized and cleaned up.

Removed HFOV toggle - it's the default way now.
Added FOV Range Override for compatibility with FOV-extension mods.
Some values should now be grabbed from the game.
This commit is contained in:
notGreg 2022-08-04 18:13:18 +02:00
parent eea9786bab
commit c92693880c
5 changed files with 197 additions and 83 deletions

View File

@ -44,10 +44,18 @@
<Reference Include="BepInEx"> <Reference Include="BepInEx">
<HintPath>..\..\MyFirstPlugin\MyFirstPlugin\lib\BepInEx.dll</HintPath> <HintPath>..\..\MyFirstPlugin\MyFirstPlugin\lib\BepInEx.dll</HintPath>
</Reference> </Reference>
<Reference Include="Comfort, Version=1.0.0.4, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>E:\SPT-AKI\SPT-AKI 3.0.0\EscapeFromTarkov_Data\Managed\Comfort.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\libs\EFT Trainer DLLs\Newtonsoft.Json.dll</HintPath> <HintPath>..\..\libs\EFT Trainer DLLs\Newtonsoft.Json.dll</HintPath>
</Reference> </Reference>
<Reference Include="Sirenix.Serialization, Version=3.0.4.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>E:\SPT-AKI\SPT-AKI 3.0.0\EscapeFromTarkov_Data\Managed\Sirenix.Serialization.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
@ -64,6 +72,8 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="UniformAimUtils.cs" />
<Compile Include="UniformAimCore.cs" />
<Compile Include="UniformAimPlugin.cs" /> <Compile Include="UniformAimPlugin.cs" />
<Compile Include="UniformAimPatch.cs" /> <Compile Include="UniformAimPatch.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -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<Behaviour>().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; }
}
}
}

View File

@ -2,6 +2,7 @@
using EFT; using EFT;
using System.Reflection; using System.Reflection;
namespace UniformAim namespace UniformAim
{ {
public class UpdateSensitivityPatch : ModulePatch public class UpdateSensitivityPatch : ModulePatch
@ -67,6 +68,4 @@ namespace UniformAim
Plugin.isAiming = ____isAiming; Plugin.isAiming = ____isAiming;
} }
} }
} }

View File

@ -1,26 +1,30 @@
using BepInEx; using BepInEx;
using BepInEx.Configuration; using BepInEx.Configuration;
using System;
using UnityEngine; using UnityEngine;
namespace UniformAim 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")] [BepInProcess("EscapeFromTarkov.exe")]
public class Plugin : BaseUnityPlugin public class Plugin : BaseUnityPlugin
{ {
//Bepinex.Configurator fields //Bepinex.Configurator fields
public static ConfigEntry<int> configFOV; public static ConfigEntry<int> configFOV;
int[] FOVRange = new int[2] { 50, 75 };
public static ConfigEntry<bool> configFOVRangeOverride;
public static ConfigEntry<int> configCoeff; public static ConfigEntry<int> configCoeff;
public static ConfigEntry<int> configSens; public static ConfigEntry<int> configSens;
public static ConfigEntry<bool> configUseHFOV; public static ConfigEntry<bool> configDebug;
//TODO: figure out a way to read game settings to default the configFOV.Value to whatever the player has already set //only for persistence
//TODO: figure out a way to read game settings to apply configSens.Value as a multiplier on top of Tarkov's stock sensitivity setting public static ConfigEntry<float> inGameSens;
public static float mySens = 1f; public static float mySens = 1f;
public static float aimingSens; //public static float aimingSens;
//sight data for hacky workarounds //sight data for hacky workarounds
public static int SelectedScope = 0; public static int SelectedScope = 0;
@ -28,66 +32,18 @@ namespace UniformAim
public static bool isAiming = false; public static bool isAiming = false;
//human-friendly names for variables used later //human-friendly names for variables used later
float FPSCameraFOV; public static float baseCameraFOV = 75;
float ScopeFOV; public static float currentFPSCameraFOV = 75;
float currentFOV; public static float currentScopeCameraFOV = 75;
//values to prevent unnecessary repetition void printDebug()
float cachedFOV;
string cachedDebugInfo;
//aspect ratio for further calculations
float GetAspectRatio()
{ {
return Camera.allCameras[0].aspect; 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())}" +
//calculate horizontal FOV based on vertical FOV, currently unused but could be useful in the future $"\nisAiming? {isAiming} SelectedScope: {SelectedScope} SelectedScopeMode:{SelectedScopeMode}" +
float CalculateHFOV(float FOV) $"\nCalculated sensitivity: {Core.CalculateSensitivity(Core.DetermineCurrentFOV(), baseCameraFOV)}" +
{ $"\nAspect Ratio: {Core.GetAspectRatio()}" +
float vFOVRad = FOV / 2 * Mathf.Deg2Rad; $"\nFinal Sensitivity: {mySens * inGameSens.Value}");
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<Behaviour>().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; }
} }
void Awake() void Awake()
@ -98,38 +54,64 @@ namespace UniformAim
new get_SelectedScopeModePatch().Enable(); new get_SelectedScopeModePatch().Enable();
new get_IsAimingPatch().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 //add configuration slider for field of view
configFOV = Config.Bind("General", "FOV", 75, new ConfigDescription("In-game Field of View value", new AcceptableValueRange<int>(51, 75))); configFOV = Config.Bind("General", "FOV", 75, new ConfigDescription("In-game Field of View value", new AcceptableValueRange<int>(FOVRange[0], FOVRange[1])));
//add coefficient slider //add coefficient slider
configCoeff = Config.Bind("General", "Coefficient", 133, new ConfigDescription("Coefficient - increases sensitivity at higher zoom levels", new AcceptableValueRange<int>(1, 300))); configCoeff = Config.Bind("General", "Coefficient", 133, new ConfigDescription("Coefficient - increases sensitivity at higher zoom levels", new AcceptableValueRange<int>(1, 300)));
//add sensitivity slider //add sensitivity slider
configSens = Config.Bind("General", "Sensitivity", 25, new ConfigDescription("Sensitivity while aiming", new AcceptableValueRange<int>(1, 200))); configSens = Config.Bind("General", "Sensitivity", 100, new ConfigDescription("Fine control over sensitivity while aiming", new AcceptableValueRange<int>(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<float>(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() 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); Time.fixedDeltaTime = (1f / 50f);
if (isAiming) //check if the game is running
{ var isRunning = Utils.checkIsReady();
//Grab FOV values for calculation if (!isRunning) return;
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
//Figure out if the FPSCamera is zoomed in, prevents the script from ticking while the player is healing if (isRunning)
if (FPSCameraFOV < configFOV.Value) {
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(); //Grab FOV values for calculation
//do not update sensitivity if currentFOV hasn't changed currentFPSCameraFOV = Camera.allCameras[0].fieldOfView; //Camera[0] tends to be FPS Camera
if (cachedFOV != currentFOV) { mySens = CalculateSensitivity(currentFOV, configFOV.Value); cachedFOV = currentFOV; } 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();
} }
} }
} }

View File

@ -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<GameWorld>.Instance;
var sessionResultPanel = Singleton<SessionResultPanel>.Instance;
if (gameWorld == null
|| gameWorld.AllPlayers == null
|| gameWorld.AllPlayers.Count <= 0
|| sessionResultPanel != null)
{
return false;
}
return true;
}
public static bool checkPlayerIsAlive()
{
var gameWorld = Singleton<GameWorld>.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<EFT.UI.SelectSlider>().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<EFT.UI.FloatSlider>().CurrentValue();
return rootSens;
}
}
}