using BepInEx; using BepInEx.Configuration; using EFT; using UnityEngine; using Comfort.Common; using System.Reflection; using System.Collections; using EFT.Settings.Graphics; using System.ComponentModel; namespace ScopeTweaks { [BepInPlugin("com.notGreg.scopeTweaks", "notGreg's Scope Tweaks", "2.0.0")] public class Plugin : BaseUnityPlugin { ConfigEntry cameraResolutionScale; ConfigEntry scopeCameraResolutionScale; ConfigEntry scopeFixType; enum EFOVScalingMode { Disabled, [Description("Magnified optics")] ScopesOnly, [Description("All sights")] All, } void Awake() { cameraResolutionScale = Config.Bind( "General", "Main camera scale %", 80, new ConfigDescription("Additional override applied on top of currently enabled resolution scaling method.", new AcceptableValueRange(25, 100))); scopeCameraResolutionScale = Config.Bind( "General", "Scope camera scale %", 80, new ConfigDescription("Additional override applied on top of currently enabled resolution scaling method.", new AcceptableValueRange(25, (int)(100f / currentScalingFactor)))); scopeFixType = Config.Bind("General", "High FOV sight tweak", EFOVScalingMode.ScopesOnly, new ConfigDescription("")); } void Update() { if (Singleton.Instance == null) return; GameStatus currentGameState = Singleton.Instance.Status; if (!gameStateChanged(currentGameState)) return; switch(currentGameState) { case GameStatus.Started: { Logger.LogInfo("Getting local player"); mainPlayer = getLocalPlayer(); subscribeHandsChangedEvent(); Logger.LogInfo("Assigning cameras..."); StartCoroutine(tryGetMainCamera()); StartCoroutine(tryGetScopeCamera()); break; } case GameStatus.SoftStopping: case GameStatus.Stopped: { Logger.LogInfo("Resetting..."); FPSCamera = null; scopeCamera = null; mainPlayer = null; break; } default: break; } } /// /// GAME STATUS /// GameStatus lastGameState; bool gameStateChanged(GameStatus currentState) { if (currentState == lastGameState) return false; lastGameState = currentState; return true; } Player mainPlayer; Player getLocalPlayer() { return Singleton.Instance.RegisteredPlayers.Find(p => p.IsYourPlayer); } /// /// FIELD OF VIEW /// int inGameFOV; int getInGameFOV() { int fov = Singleton.Instance.Game.Settings.FieldOfView.Value; Logger.LogInfo($"In-game FOV: {fov}"); return fov; } void setInGameFOV(int value) { Logger.LogInfo($"setInGameFOV(): Update to {value}"); Singleton.Instance.Game.Settings.FieldOfView.Value = value; } /// /// CAMERA SETUP /// Camera FPSCamera = null; Camera scopeCamera = null; SSAA ssaaInstance = null; FieldInfo _nextSSRation = null; WaitForSeconds myDelaySec = new WaitForSeconds(1); IEnumerator tryGetMainCamera() { string cameraName = "FPS Camera"; if (GameObject.Find(cameraName) != null) { FPSCamera = GameObject.Find(cameraName).GetComponent(); Logger.LogInfo($"{FPSCamera.name} found!"); } else { Logger.LogMessage($"Camera \"{cameraName}\" not found, rescheduling..."); yield return myDelaySec; StartCoroutine(tryGetMainCamera()); yield break; } yield return null; } FieldInfo getFieldInfo(string fieldName) { return typeof(SSAA).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); } IEnumerator tryGetScopeCamera() { string cameraName = "BaseOpticCamera(Clone)"; if (GameObject.Find(cameraName) != null) { scopeCamera = GameObject.Find(cameraName).GetComponent(); Logger.LogInfo($"Camera \"{scopeCamera.name}\" found!"); } yield break; } void setMainCameraResolutionScale(int value = 100) { Logger.LogInfo($"Setting MainCam res scale to {value}%"); ssaaInstance = FPSCamera.GetComponent(); _nextSSRation = getFieldInfo("_nextSSRation"); _nextSSRation.SetValue(ssaaInstance, (float)(currentScalingFactor * value / 100f)); } void setScopeCameraResolutionScale(int value) { if(scopeCamera == null || !scopeCamera.isActiveAndEnabled) { Logger.LogInfo("ScopeCam inactive or absent!"); return; } Logger.LogInfo($"Setting Scope res scale to {value}%"); scopeCamera.GetComponent().OpticCameraToMainCameraResolutionRatio = (float)(currentScalingFactor * value / 100); } /// /// PLAYER WEAPON EVENTS /// void subscribeHandsChangedEvent() { Logger.LogInfo("Subscribing to HandsChanged Event"); mainPlayer.HandsChangedEvent += (handsArgs) => { subscribeOnAimingChangedEvent(); }; } void subscribeOnAimingChangedEvent() { Logger.LogInfo("Subscribing to OnAimingChanged Event"); mainPlayer.HandsController.OnAimingChanged += (aimingArgs) => { currentScalingFactor = getCurrentScalingFactor(); StartCoroutine(tryGetScopeCamera()); Logger.LogInfo("AimingChanged: notAiming"); if (!mainPlayer.ProceduralWeaponAnimation.IsAiming) { switch(scopeFixType.Value) { case EFOVScalingMode.Disabled: { Logger.LogInfo("Nothing to do!"); break; } case EFOVScalingMode.ScopesOnly: { setMainCameraResolutionScale(); GClass1774.Instance.SetFov(inGameFOV, 0.33f, false); setInGameFOV(inGameFOV); break; } case EFOVScalingMode.All: { setMainCameraResolutionScale(); GClass1774.Instance.SetFov(inGameFOV, 0.33f, false); setInGameFOV(inGameFOV); break; } } } Logger.LogInfo("Entering switch()"); if (mainPlayer.ProceduralWeaponAnimation.IsAiming) { if (inGameFOV != 50) { inGameFOV = getInGameFOV(); } switch (scopeFixType.Value) { case EFOVScalingMode.Disabled: { Logger.LogInfo("Plugin is disabled!"); break; } case EFOVScalingMode.ScopesOnly: { Logger.LogInfo("Only magnified optics!"); if(scopeCamera.isActiveAndEnabled) { applyFixesWhileAiming(); } break; } case EFOVScalingMode.All: { Logger.LogInfo("All sights!"); applyFixesWhileAiming(); break; } } } }; } void applyFixesWhileAiming() { GClass1774.Instance.SetFov(35, 0.25f, false); setInGameFOV(50); setMainCameraResolutionScale(cameraResolutionScale.Value); setScopeCameraResolutionScale(scopeCameraResolutionScale.Value); } /// /// IN-GAME SETTINGS /// float currentScalingFactor = 1.0f; float getCurrentScalingFactor() { Logger.LogInfo("Getting current scaling factor:"); var graphics = Singleton.Instance.Graphics.Settings; if (!graphics.DLSSEnabled && !graphics.FSREnabled) { Logger.LogInfo($"Supersampling factor: {graphics.SuperSamplingFactor}"); return graphics.SuperSamplingFactor; } if (graphics.DLSSEnabled) { float DLSSFactor = 1.0f; switch (graphics.DLSSMode.Value) { case EDLSSMode.Off: { DLSSFactor = 1.0f; break; } case EDLSSMode.Quality: { DLSSFactor = 0.67f; break; } case EDLSSMode.Balanced: { DLSSFactor = 0.58f; break; } case EDLSSMode.Performance: { DLSSFactor = 0.5f; break; } case EDLSSMode.UltraPerformance: { DLSSFactor = 0.33f; break; } } Logger.LogInfo($"DLSS factor: {DLSSFactor}"); return DLSSFactor; } if (graphics.FSREnabled) { float FSRFactor = 1.0f; switch (graphics.FSRMode.Value) { case EFSRMode.Off: { FSRFactor = 1.0f; break; } case EFSRMode.UltraQuality: { FSRFactor = 0.77f; break; } case EFSRMode.Quality: { FSRFactor = 0.66f; break; } case EFSRMode.Balanced: { FSRFactor = 0.59f; break; } case EFSRMode.Performance: { FSRFactor = 0.5f; break; } } Logger.LogInfo($"FSR factor: {FSRFactor}"); return FSRFactor; } Logger.LogInfo($"GetCurrentScalingFactor(): Something went wrong. Returning 1.0f"); return 1.0f; } } }