diff --git a/MainApp/AppWindow/AppMainWindow.xaml.cs b/MainApp/AppWindow/AppMainWindow.xaml.cs index d916059..64860a3 100644 --- a/MainApp/AppWindow/AppMainWindow.xaml.cs +++ b/MainApp/AppWindow/AppMainWindow.xaml.cs @@ -26,6 +26,12 @@ namespace MSFSPopoutPanelManager.MainApp.AppWindow StateChanged += AppWindow_StateChanged; WindowActionManager.OnPopOutManagerAlwaysOnTopChanged += (_, e) => { Topmost = e; }; MouseLeftButtonDown += (_, _) => DragMove(); + + GotFocus += (_, _) => + { + if (_viewModel.AppSettingData.ApplicationSetting.GeneralSetting.AlwaysOnTop) + WindowActionManager.ApplyAlwaysOnTop(_viewModel.ApplicationHandle, PanelType.PopOutManager, true); + }; } private void AppWindow_Loaded(object sender, RoutedEventArgs e) diff --git a/Orchestration/DynamicLodOrchestrator.cs b/Orchestration/DynamicLodOrchestrator.cs index ff0c937..0d7a02f 100644 --- a/Orchestration/DynamicLodOrchestrator.cs +++ b/Orchestration/DynamicLodOrchestrator.cs @@ -1,7 +1,6 @@ using MSFSPopoutPanelManager.DomainModel.DynamicLod; using MSFSPopoutPanelManager.DomainModel.Setting; using MSFSPopoutPanelManager.Shared; -using MSFSPopoutPanelManager.SimConnectAgent; using MSFSPopoutPanelManager.WindowsAgent; using System; using System.Diagnostics; @@ -17,12 +16,9 @@ namespace MSFSPopoutPanelManager.Orchestration private const int PROCESS_VM_WRITE = 0x0020; private const long OFFSET_MODULE_BASE =0x004B2368; private const long OFFSET_POINTER_MAIN = 0x3D0; - private const long OFFSET_POINTER_TLOD_VR = 0x114; private const long OFFSET_POINTER_TLOD = 0xC; private const long OFFSET_POINTER_OLOD = 0xC; - private const long OFFSET_POINTER_CLOUDQ = 0x44; - private const long OFFSET_POINTER_CLOUDQ_VR = 0x108; - private const long OFFSET_POINTER_VR_MODE = 0x1C; + private const long OFFSET_POINTER_CLOUD_QUALITY = 0x44; private const long OFFSET_POINTER_FG_MODE = 0x4A; private const long OFFSET_POINTER_ANSIO_FILTER = -0x18; private const long OFFSET_POINTER_WATER_WAVES = 0x3C; @@ -34,19 +30,15 @@ namespace MSFSPopoutPanelManager.Orchestration private long _addressTlod; private long _addressOlod; - private long _addressTlodVr; - private long _addressOlodVr; private long _addressCloudQ; - private long _addressCloudQVr; - private long _addressVrMode; private long _addressFgMode; private DynamicLodSetting DynamicLodSetting => AppSettingData.ApplicationSetting.DynamicLodSetting; - private DynamicLodSimData SimData => FlightSimData.DynamicLodSimData; + private DynamicLodSimData DynamicLodSimData => FlightSimData.DynamicLodSimData; private DateTime _lastLodUpdateTime = DateTime.Now; - private bool _isDecreasedCloudQualityActive = false; + private bool _isDecreasedCloudQualityActive; public DynamicLodOrchestrator(SharedStorage sharedStorage) : base(sharedStorage) {} @@ -70,13 +62,9 @@ namespace MSFSPopoutPanelManager.Orchestration if (_addressTlod > 0) { - _addressTlodVr = ReadMemory(_addressTlod) + OFFSET_POINTER_TLOD_VR; _addressTlod = ReadMemory(_addressTlod) + OFFSET_POINTER_TLOD; _addressOlod = _addressTlod + OFFSET_POINTER_OLOD; - _addressOlodVr = _addressTlodVr + OFFSET_POINTER_OLOD; - _addressCloudQ = _addressTlod + OFFSET_POINTER_CLOUDQ; - _addressCloudQVr = _addressCloudQ + OFFSET_POINTER_CLOUDQ_VR; - _addressVrMode = _addressTlod - OFFSET_POINTER_VR_MODE; + _addressCloudQ = _addressTlod + OFFSET_POINTER_CLOUD_QUALITY; _addressFgMode = _addressTlod - OFFSET_POINTER_FG_MODE; if (!MemoryBoundaryTest()) @@ -99,9 +87,8 @@ namespace MSFSPopoutPanelManager.Orchestration if (DynamicLodSetting.ResetEnabled) { - var isVr = ReadIsVr(); - WriteMemory(isVr ? _addressTlodVr : _addressTlod, DynamicLodSetting.ResetTlod / 100.0f); - WriteMemory(isVr ? _addressOlodVr : _addressOlod, DynamicLodSetting.ResetOlod / 100.0f); + WriteMemory(_addressTlod, DynamicLodSetting.ResetTlod / 100.0f); + WriteMemory(_addressOlod, DynamicLodSetting.ResetOlod / 100.0f); } _isActive = false; @@ -109,19 +96,19 @@ namespace MSFSPopoutPanelManager.Orchestration Debug.WriteLine($"Reset to custom LOD: TLOD: {DynamicLodSetting.ResetTlod}, OLOD: {DynamicLodSetting.ResetOlod}"); } - public int ReadTlod(bool isVr = false) + public int ReadTlod() { - return Convert.ToInt32(ReadMemory(isVr ? _addressTlodVr : _addressTlod) * 100.0f); + return Convert.ToInt32(ReadMemory(_addressTlod) * 100.0f); } - public int ReadOlod(bool isVr = false) + public int ReadOlod() { - return Convert.ToInt32(ReadMemory(isVr ? _addressOlodVr : _addressOlod) * 100.0f); + return Convert.ToInt32(ReadMemory(_addressOlod) * 100.0f); } - public string ReadCloudQuality(bool isVr = false) + public string ReadCloudQuality() { - return ReadCloudQualitySimValue(isVr) switch + return ReadCloudQualitySimValue() switch { 0 => "Low", 1 => "Medium", @@ -131,33 +118,25 @@ namespace MSFSPopoutPanelManager.Orchestration }; } - public int ReadCloudQualitySimValue(bool isVr = false) + public int ReadCloudQualitySimValue() { - return Convert.ToInt32(ReadMemory(isVr ? _addressCloudQVr : _addressCloudQ)); + return Convert.ToInt32(ReadMemory(_addressCloudQ)); } - public bool ReadIsVr() + public bool ReadIsFg() { - return ReadMemory(_addressVrMode) == 1; - } - - public bool ReadIsFg(bool isVr) - { - if (isVr) - return false; - return ReadMemory(_addressFgMode) == 1; } - public void UpdateLod(bool isVr) + public void UpdateLod() { + if (!FlightSimData.IsFlightStarted || !FlightSimData.IsInCockpit) + return; + if (DateTime.Now - _lastLodUpdateTime <= TimeSpan.FromSeconds(1)) return; - if (!FlightSimData.IsFlightStarted || !FlightSimData.IsInCockpit || (DynamicLodSetting.PauseOutsideCockpitView && FlightSimData.CameraState != CameraState.Cockpit)) - return; - - var deltaFps = SimData.Fps - DynamicLodSetting.TargetedFps; + var deltaFps = DynamicLodSimData.Fps - DynamicLodSetting.TargetedFps; if (Math.Abs(deltaFps) < DynamicLodSetting.TargetedFps * DynamicLodSetting.FpsTolerance / 100.0) // within FPS tolerance return; @@ -246,10 +225,9 @@ namespace MSFSPopoutPanelManager.Orchestration private bool MemoryBoundaryTest() { // Boundary check a few known setting memory addresses to see if any fail which likely indicates MSFS memory map has changed - if (ReadTlod() < 10 || ReadTlod() > 1000 || ReadTlod(true) < 10 || ReadTlod(true) > 1000 - || ReadOlod() < 10 || ReadOlod() > 1000 || ReadOlod(true) < 10 || ReadOlod(true) > 1000 - || ReadCloudQuality() == "N/A" || ReadCloudQuality(true) == "N/A" - || ReadMemory(_addressVrMode) < 0 || ReadMemory(_addressVrMode) > 1 + if (ReadTlod() < 10 || ReadTlod() > 1000 || ReadTlod() < 10 || ReadTlod() > 1000 + || ReadOlod() < 10 || ReadOlod() > 1000 || ReadOlod() < 10 || ReadOlod() > 1000 + || ReadCloudQuality() == "N/A" || ReadCloudQuality() == "N/A" || ReadMemory(_addressTlod + OFFSET_POINTER_ANSIO_FILTER) < 1 || ReadMemory(_addressTlod + OFFSET_POINTER_ANSIO_FILTER) > 16 || !(ReadMemory(_addressTlod + OFFSET_POINTER_WATER_WAVES) == 128 || ReadMemory(_addressTlod + OFFSET_POINTER_WATER_WAVES) == 256 || ReadMemory(_addressTlod + OFFSET_POINTER_WATER_WAVES) == 512)) { @@ -259,12 +237,12 @@ namespace MSFSPopoutPanelManager.Orchestration return true; } - private void SetTlod(int deltaFps, bool isVr = false) + private void SetTlod(int deltaFps) { var tlodStep = Math.Max(5, Math.Abs(deltaFps / 2)); - var newTlod = SimData.Tlod + Math.Sign(deltaFps) * tlodStep; + var newTlod = DynamicLodSimData.Tlod + Math.Sign(deltaFps) * tlodStep; - if (DynamicLodSetting.TlodMinOnGround && SimData.AltAboveGround <= DynamicLodSetting.AltTlodBase) + if (DynamicLodSetting.TlodMinOnGround && DynamicLodSimData.AltAboveGround <= DynamicLodSetting.AltTlodBase) { newTlod = DynamicLodSetting.TlodMin; } @@ -277,17 +255,17 @@ namespace MSFSPopoutPanelManager.Orchestration newTlod = DynamicLodSetting.TlodMax; } - if (ReadTlod(isVr) == newTlod) + if (ReadTlod() == newTlod) return; // Adjust cloud quality if applicable - if (DynamicLodSetting.DecreaseCloudQuality && (!DynamicLodSetting.TlodMinOnGround && !(SimData.AltAboveGround <= DynamicLodSetting.AltTlodBase))) + if (DynamicLodSetting.DecreaseCloudQuality && (!DynamicLodSetting.TlodMinOnGround && !(DynamicLodSimData.AltAboveGround <= DynamicLodSetting.AltTlodBase))) { switch (deltaFps) { case < 0 when newTlod < DynamicLodSetting.CloudRecoveryTlod && !_isDecreasedCloudQualityActive: _isDecreasedCloudQualityActive = true; - WriteMemory(isVr ? _addressCloudQVr : _addressCloudQ, ReadCloudQualitySimValue(isVr) - 1); + WriteMemory(_addressCloudQ, ReadCloudQualitySimValue() - 1); _lastLodUpdateTime = _lastLodUpdateTime.AddSeconds(2); // Add extra delay for cloud setting to take effect @@ -296,7 +274,7 @@ namespace MSFSPopoutPanelManager.Orchestration return; case > 0 when newTlod >= DynamicLodSetting.CloudRecoveryTlod && _isDecreasedCloudQualityActive: _isDecreasedCloudQualityActive = false; - WriteMemory(isVr ? _addressCloudQVr : _addressCloudQ, ReadCloudQualitySimValue(isVr) + 1); + WriteMemory(_addressCloudQ, ReadCloudQualitySimValue() + 1); _lastLodUpdateTime = _lastLodUpdateTime.AddSeconds(2); Debug.WriteLine("New Cloud Quality written - 3."); @@ -306,31 +284,31 @@ namespace MSFSPopoutPanelManager.Orchestration } Debug.WriteLine($"New TLOD written - {newTlod}."); - WriteMemory(isVr ? _addressTlodVr : _addressTlod, newTlod / 100.0f); + WriteMemory(_addressTlod, newTlod / 100.0f); } - private void SetOlod(bool isVr = false) + private void SetOlod() { int newOlod; - if (SimData.AltAboveGround < DynamicLodSetting.AltOlodBase) + if (DynamicLodSimData.AltAboveGround < DynamicLodSetting.AltOlodBase) { newOlod = DynamicLodSetting.OlodBase; } - else if (SimData.AltAboveGround > DynamicLodSetting.AltOlodTop) + else if (DynamicLodSimData.AltAboveGround > DynamicLodSetting.AltOlodTop) { newOlod = DynamicLodSetting.OlodTop; } else { - newOlod = Convert.ToInt32(DynamicLodSetting.OlodBase - (DynamicLodSetting.OlodBase - DynamicLodSetting.OlodTop) * (SimData.AltAboveGround - DynamicLodSetting.AltOlodBase) / (DynamicLodSetting.AltOlodTop - DynamicLodSetting.AltOlodBase)); + newOlod = Convert.ToInt32(DynamicLodSetting.OlodBase - (DynamicLodSetting.OlodBase - DynamicLodSetting.OlodTop) * (DynamicLodSimData.AltAboveGround - DynamicLodSetting.AltOlodBase) / (DynamicLodSetting.AltOlodTop - DynamicLodSetting.AltOlodBase)); } - if (ReadOlod(isVr) == newOlod) + if (ReadOlod() == newOlod) return; Debug.WriteLine($"New OLOD written - {newOlod}."); - WriteMemory(isVr ? _addressOlodVr : _addressOlod, newOlod / 100.0f); + WriteMemory(_addressOlod, newOlod / 100.0f); } } } diff --git a/Orchestration/FlightSimOrchestrator.cs b/Orchestration/FlightSimOrchestrator.cs index b195575..d80a2c4 100644 --- a/Orchestration/FlightSimOrchestrator.cs +++ b/Orchestration/FlightSimOrchestrator.cs @@ -15,7 +15,7 @@ namespace MSFSPopoutPanelManager.Orchestration private System.Timers.Timer _msfsGameExitDetectionTimer; private SimConnectProvider _simConnectProvider; - private DynamicLodOrchestrator _dynamicLodOrchestrator; + private readonly DynamicLodOrchestrator _dynamicLodOrchestrator; private bool _isTurnedOnPower; private bool _isTurnedOnAvionics; @@ -77,17 +77,14 @@ namespace MSFSPopoutPanelManager.Orchestration if (!AppSettingData.ApplicationSetting.DynamicLodSetting.IsEnabled || !FlightSimData.IsFlightStarted) return; - var isVr = _dynamicLodOrchestrator.ReadIsVr(); - MapDynamicLodSimConnectData(e, isVr); - var isPaused = (AppSettingData.ApplicationSetting.DynamicLodSetting.PauseWhenMsfsLoseFocus && !WindowActionManager.IsMsfsInFocus()) || (AppSettingData.ApplicationSetting.DynamicLodSetting.PauseOutsideCockpitView && FlightSimData.CameraState != CameraState.Cockpit); if (isPaused) return; - FlightSimData.DynamicLodSimData.Fps = FpsCalc.GetAverageFps(_dynamicLodOrchestrator.ReadIsFg(isVr) ? _currentFps * 2 : _currentFps); - _dynamicLodOrchestrator.UpdateLod(isVr); + MapDynamicLodSimConnectData(e); + _dynamicLodOrchestrator.UpdateLod(); }; _simConnectProvider.OnSimConnectDataEventFrameRefreshed += (_, e) => @@ -393,6 +390,7 @@ namespace MSFSPopoutPanelManager.Orchestration FlightSimData.IsFlightStarted = false; StopDynamicLod(); + FpsCalc.Reset(); FlightSimData.DynamicLodSimData.Clear(); } @@ -492,7 +490,7 @@ namespace MSFSPopoutPanelManager.Orchestration FlightSimData.HudBarData.SimRate = newValue; } - private void MapDynamicLodSimConnectData(List simData, bool isVr) + private void MapDynamicLodSimConnectData(List simData) { if (CompareSimConnectData(simData, SimDataDefinitions.PropName.PlaneAltAboveGround, FlightSimData.DynamicLodSimData.Agl, out var newValue)) FlightSimData.DynamicLodSimData.Agl = newValue; @@ -509,17 +507,19 @@ namespace MSFSPopoutPanelManager.Orchestration if (CompareSimConnectData(simData, SimDataDefinitions.PropName.SimOnGround, 1.0f, out newValue)) FlightSimData.DynamicLodSimData.PlaneOnGround = Convert.ToBoolean(newValue); - var tlod = _dynamicLodOrchestrator.ReadTlod(isVr); + var tlod = _dynamicLodOrchestrator.ReadTlod(); if (FlightSimData.DynamicLodSimData.Tlod != tlod) FlightSimData.DynamicLodSimData.Tlod = tlod; - var olod = _dynamicLodOrchestrator.ReadOlod(isVr); + var olod = _dynamicLodOrchestrator.ReadOlod(); if (FlightSimData.DynamicLodSimData.Olod != olod) FlightSimData.DynamicLodSimData.Olod = olod; - var cloudQuality = _dynamicLodOrchestrator.ReadCloudQuality(isVr); + var cloudQuality = _dynamicLodOrchestrator.ReadCloudQuality(); if (FlightSimData.DynamicLodSimData.CloudQuality != cloudQuality) FlightSimData.DynamicLodSimData.CloudQuality = cloudQuality; + + FlightSimData.DynamicLodSimData.Fps = FpsCalc.GetAverageFps(_dynamicLodOrchestrator.ReadIsFg() ? _currentFps * 2 : _currentFps); } private int _currentFps; diff --git a/Orchestration/PanelPopOutOrchestrator.cs b/Orchestration/PanelPopOutOrchestrator.cs index 2dfc340..744fbfc 100644 --- a/Orchestration/PanelPopOutOrchestrator.cs +++ b/Orchestration/PanelPopOutOrchestrator.cs @@ -419,6 +419,9 @@ namespace MSFSPopoutPanelManager.Orchestration WindowActionManager.SetWindowTitleBarColor(panelConfig.PanelHandle, AppSettingData.ApplicationSetting.PopOutSetting.PopOutTitleBarCustomization.HexColor); } } + + if(ActiveProfile.PanelConfigs.Any(p => p.AlwaysOnTop)) + WindowActionManager.ApplyAlwaysOnTop(WindowProcessManager.SimulatorProcess.Handle, PanelType.FlightSimMainWindow, true); } private async Task StepPostPopout() diff --git a/SimconnectAgent/FpsCalc.cs b/SimconnectAgent/FpsCalc.cs index 6aff9e5..c4baff4 100644 --- a/SimconnectAgent/FpsCalc.cs +++ b/SimconnectAgent/FpsCalc.cs @@ -5,32 +5,46 @@ namespace MSFSPopoutPanelManager.SimConnectAgent { public class FpsCalc { - private const int FpsLen = 25; - private static readonly float[] FpsStatistic = new float[FpsLen]; + private const int FPS_LEN = 20; + private static readonly float[] FpsStatistic = new float[FPS_LEN]; private static int _fpsIndex = -1; + private static int _avgFps; public static int GetAverageFps(int newValue) { if (_fpsIndex == -1) { - for (var i = 0; i < FpsLen; i++) + // initialize FpsStatistic array + for (var i = 0; i < FPS_LEN; i++) FpsStatistic[i] = newValue; - + + _avgFps = Convert.ToInt32(newValue); _fpsIndex = 1; } else { + var deltaFps = newValue - _avgFps; + + if (deltaFps < 0 && Math.Abs(deltaFps) > _avgFps * 0.1) // FPS suddenly drops more than 10% + { + newValue += Math.Abs(deltaFps) / 2; // Let the new FPS to be only half the delta drop + } + FpsStatistic[_fpsIndex] = newValue; _fpsIndex++; - if (_fpsIndex >= FpsLen) + if (_fpsIndex >= FPS_LEN) _fpsIndex = 0; + + _avgFps = Convert.ToInt32(FpsStatistic.Sum() / FPS_LEN); } + + return _avgFps; + } - var fps = 0; - if (_fpsIndex != -1) - fps = Convert.ToInt32(FpsStatistic.Sum() / FpsLen); - - return fps; + public static void Reset() + { + _fpsIndex = -1; + _avgFps = 0; } } }