From 447a497945a7cb4a3089b2600ddc434f386db5e8 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 16 Sep 2020 20:46:45 +0200 Subject: [PATCH] Profile editor - Removed delay in module override Modules - Streamline update rules and properly honor them in timed updates --- src/Artemis.Core/Plugins/Modules/Module.cs | 13 ++- .../Plugins/Modules/ProfileModule.cs | 2 +- .../Plugins/PluginUpdateRegistration.cs | 12 +-- src/Artemis.Core/Services/ModuleService.cs | 82 +++++++++++------ .../DisplayConditionPredicateViewModel.cs | 3 +- .../Timeline/TimelinePropertyViewModel.cs | 87 +++++++++++-------- .../OverlayModule.cs | 7 ++ 7 files changed, 127 insertions(+), 79 deletions(-) diff --git a/src/Artemis.Core/Plugins/Modules/Module.cs b/src/Artemis.Core/Plugins/Modules/Module.cs index 946ce40b9..fc35d7538 100644 --- a/src/Artemis.Core/Plugins/Modules/Module.cs +++ b/src/Artemis.Core/Plugins/Modules/Module.cs @@ -91,13 +91,13 @@ namespace Artemis.Core.Modules /// /// Gets whether this module's activation was due to an override, can only be true if is - /// true + /// /// public bool IsActivatedOverride { get; private set; } /// - /// Gets whether this module should update if is true - /// Defaults to true + /// Gets whether this module should update if is + /// Defaults to /// public bool UpdateDuringActivationOverride { get; protected set; } = true; @@ -138,6 +138,11 @@ namespace Artemis.Core.Modules /// public IEnumerable ModuleTabs { get; protected set; } + /// + /// Gets whether updating this module is currently allowed + /// + public bool IsUpdateAllowed => IsActivated && (UpdateDuringActivationOverride || !IsActivatedOverride); + /// /// Called each frame when the module must update /// @@ -189,7 +194,7 @@ namespace Artemis.Core.Modules internal virtual void InternalUpdate(double deltaTime) { - if (!IsActivatedOverride || UpdateDuringActivationOverride) + if (IsUpdateAllowed) Update(deltaTime); } diff --git a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs index 498d7475a..8c15c9e0a 100644 --- a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs +++ b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs @@ -141,7 +141,7 @@ namespace Artemis.Core.Modules internal override void InternalUpdate(double deltaTime) { - if (!IsActivatedOverride || UpdateDuringActivationOverride) + if (IsUpdateAllowed) Update(deltaTime); lock (this) diff --git a/src/Artemis.Core/Plugins/PluginUpdateRegistration.cs b/src/Artemis.Core/Plugins/PluginUpdateRegistration.cs index 488c30c72..ec3cf11c1 100644 --- a/src/Artemis.Core/Plugins/PluginUpdateRegistration.cs +++ b/src/Artemis.Core/Plugins/PluginUpdateRegistration.cs @@ -20,7 +20,6 @@ namespace Artemis.Core PluginInfo.Instance.PluginEnabled += InstanceOnPluginEnabled; PluginInfo.Instance.PluginDisabled += InstanceOnPluginDisabled; - if (PluginInfo.Instance.Enabled) Start(); } @@ -54,13 +53,6 @@ namespace Artemis.Core if (_timer != null) return; - // Don't update during override if that is disabled on the module - if (PluginInfo.Instance is Module module) - { - if (module.IsActivatedOverride && !module.UpdateDuringActivationOverride) - return; - } - _lastEvent = DateTime.Now; _timer = new Timer(Interval.TotalMilliseconds); _timer.Elapsed += TimerOnElapsed; @@ -94,6 +86,10 @@ namespace Artemis.Core var interval = DateTime.Now - _lastEvent; _lastEvent = DateTime.Now; + // Modules don't always want to update, honor that + if (PluginInfo.Instance is Module module && !module.IsUpdateAllowed) + return; + Action(interval.TotalSeconds); } diff --git a/src/Artemis.Core/Services/ModuleService.cs b/src/Artemis.Core/Services/ModuleService.cs index 1b452497e..74fa1d660 100644 --- a/src/Artemis.Core/Services/ModuleService.cs +++ b/src/Artemis.Core/Services/ModuleService.cs @@ -47,38 +47,24 @@ namespace Artemis.Core.Services if (ActiveModuleOverride == overrideModule) return; - // If set to null, resume regular activation - if (overrideModule == null) - { - ActiveModuleOverride = null; - _logger.Information("Cleared active module override"); - return; - } - - // If a module was provided, activate it and deactivate everything else + // Always deactivate all modules whenever override is called var modules = _pluginService.GetPluginsOfType().ToList(); - var tasks = new List(); foreach (var module in modules) + OverrideDeactivate(module); + + if (overrideModule != null) { - if (module != overrideModule) - tasks.Add(DeactivateModule(module, true)); + OverrideActivate(overrideModule); + _logger.Information($"Setting active module override to {overrideModule.DisplayName}"); } + else + _logger.Information("Clearing active module override"); - if (!overrideModule.IsActivated) - tasks.Add(ActivateModule(overrideModule, true)); - - await Task.WhenAll(tasks); ActiveModuleOverride = overrideModule; - - _logger.Information($"Set active module override to {ActiveModuleOverride.DisplayName}"); } finally { ActiveModuleSemaphore.Release(); - - // With the semaphore released, trigger an update with the override was cleared - if (ActiveModuleOverride == null) - await UpdateModuleActivation(); } } @@ -100,9 +86,9 @@ namespace Artemis.Core.Services { var shouldBeActivated = module.EvaluateActivationRequirements(); if (shouldBeActivated && !module.IsActivated) - tasks.Add(ActivateModule(module, false)); + tasks.Add(ActivateModule(module)); else if (!shouldBeActivated && module.IsActivated) - tasks.Add(DeactivateModule(module, false)); + tasks.Add(DeactivateModule(module)); } await Task.WhenAll(tasks); @@ -149,11 +135,11 @@ namespace Artemis.Core.Services await UpdateModuleActivation(); } - private async Task ActivateModule(Module module, bool isOverride) + private async Task ActivateModule(Module module) { try { - module.Activate(isOverride); + module.Activate(false); // If this is a profile module, activate the last active profile after module activation if (module is ProfileModule profileModule) @@ -166,7 +152,27 @@ namespace Artemis.Core.Services } } - private async Task DeactivateModule(Module module, bool isOverride) + private void OverrideActivate(Module module) + { + try + { + if (module.IsActivated) + return; + + module.Activate(true); + + // If this is a profile module, activate the last active profile after module activation + if (module is ProfileModule profileModule) + _profileService.ActivateLastProfile(profileModule); + } + catch (Exception e) + { + _logger.Error(new ArtemisPluginException(module.PluginInfo, "Failed to activate module and last profile.", e), "Failed to activate module and last profile"); + throw; + } + } + + private async Task DeactivateModule(Module module) { try { @@ -174,7 +180,27 @@ namespace Artemis.Core.Services if (module.IsActivated && module is ProfileModule profileModule) await profileModule.ChangeActiveProfileAnimated(null, null); - module.Deactivate(isOverride); + module.Deactivate(false); + } + catch (Exception e) + { + _logger.Error(new ArtemisPluginException(module.PluginInfo, "Failed to deactivate module and last profile.", e), "Failed to deactivate module and last profile"); + throw; + } + } + + private void OverrideDeactivate(Module module) + { + try + { + if (!module.IsActivated) + return; + + // If this is a profile module, activate the last active profile after module activation + if (module is ProfileModule profileModule) + profileModule.ChangeActiveProfile(null, null); + + module.Deactivate(true); } catch (Exception e) { diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionPredicateViewModel.cs index 645237a34..6ce25d5ee 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionPredicateViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionPredicateViewModel.cs @@ -58,8 +58,7 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions ShowDataModelValues = settingsService.GetSetting("ProfileEditor.ShowDataModelValues"); - // Initialize async, no need to wait for it - Task.Run(Initialize); + Initialize(); } public DisplayConditionPredicate DisplayConditionPredicate => (DisplayConditionPredicate) Model; diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs index dd9adfabf..dd5543c4f 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs @@ -10,8 +10,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline public class TimelinePropertyViewModel : Conductor>.Collection.AllActive, ITimelinePropertyViewModel { private readonly IProfileEditorService _profileEditorService; - public LayerProperty LayerProperty { get; } - public LayerPropertyViewModel LayerPropertyViewModel { get; } + private double _width; public TimelinePropertyViewModel(LayerProperty layerProperty, LayerPropertyViewModel layerPropertyViewModel, IProfileEditorService profileEditorService) { @@ -23,22 +22,17 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline LayerProperty.KeyframesToggled += LayerPropertyOnKeyframesToggled; LayerProperty.KeyframeAdded += LayerPropertyOnKeyframeAdded; LayerProperty.KeyframeRemoved += LayerPropertyOnKeyframeRemoved; + _profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged; UpdateKeyframes(); } - private void LayerPropertyOnKeyframesToggled(object sender, LayerPropertyEventArgs e) - { - UpdateKeyframes(); - } + public LayerProperty LayerProperty { get; } + public LayerPropertyViewModel LayerPropertyViewModel { get; } - private void LayerPropertyOnKeyframeRemoved(object sender, LayerPropertyEventArgs e) + public double Width { - UpdateKeyframes(); - } - - private void LayerPropertyOnKeyframeAdded(object sender, LayerPropertyEventArgs e) - { - UpdateKeyframes(); + get => _width; + set => SetAndNotify(ref _width, value); } public List GetAllKeyframeViewModels() @@ -46,29 +40,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline return Items.Cast().ToList(); } - private void UpdateKeyframes() - { - // Only show keyframes if they are enabled - if (LayerProperty.KeyframesEnabled) - { - var keyframes = LayerProperty.Keyframes.ToList(); - var toRemove = Items.Where(t => !keyframes.Contains(t.LayerPropertyKeyframe)).ToList(); - foreach (var timelineKeyframeViewModel in toRemove) - timelineKeyframeViewModel.Dispose(); - - Items.RemoveRange(toRemove); - Items.AddRange(keyframes - .Where(k => Items.All(t => t.LayerPropertyKeyframe != k)) - .Select(k => new TimelineKeyframeViewModel(k, _profileEditorService)) - ); - } - else - Items.Clear(); - - foreach (var timelineKeyframeViewModel in Items) - timelineKeyframeViewModel.Update(); - } - public void WipeKeyframes(TimeSpan? start, TimeSpan? end) { start ??= TimeSpan.Zero; @@ -98,6 +69,50 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline LayerProperty.KeyframesToggled -= LayerPropertyOnKeyframesToggled; LayerProperty.KeyframeAdded -= LayerPropertyOnKeyframeAdded; LayerProperty.KeyframeRemoved -= LayerPropertyOnKeyframeRemoved; + _profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged; + } + + private void LayerPropertyOnKeyframesToggled(object sender, LayerPropertyEventArgs e) + { + UpdateKeyframes(); + } + + private void LayerPropertyOnKeyframeRemoved(object sender, LayerPropertyEventArgs e) + { + UpdateKeyframes(); + } + + private void LayerPropertyOnKeyframeAdded(object sender, LayerPropertyEventArgs e) + { + UpdateKeyframes(); + } + + private void ProfileEditorServiceOnPixelsPerSecondChanged(object sender, EventArgs e) + { + Width = GetAllKeyframeViewModels().Max(k => k.Position.TotalSeconds * _profileEditorService.PixelsPerSecond + 25); + } + + private void UpdateKeyframes() + { + // Only show keyframes if they are enabled + if (LayerProperty.KeyframesEnabled) + { + var keyframes = LayerProperty.Keyframes.ToList(); + var toRemove = Items.Where(t => !keyframes.Contains(t.LayerPropertyKeyframe)).ToList(); + foreach (var timelineKeyframeViewModel in toRemove) + timelineKeyframeViewModel.Dispose(); + + Items.RemoveRange(toRemove); + Items.AddRange(keyframes + .Where(k => Items.All(t => t.LayerPropertyKeyframe != k)) + .Select(k => new TimelineKeyframeViewModel(k, _profileEditorService)) + ); + } + else + Items.Clear(); + + foreach (var timelineKeyframeViewModel in Items) + timelineKeyframeViewModel.Update(); } } diff --git a/src/Plugins/Artemis.Plugins.Modules.Overlay/OverlayModule.cs b/src/Plugins/Artemis.Plugins.Modules.Overlay/OverlayModule.cs index aa9f5f56b..15902d85b 100644 --- a/src/Plugins/Artemis.Plugins.Modules.Overlay/OverlayModule.cs +++ b/src/Plugins/Artemis.Plugins.Modules.Overlay/OverlayModule.cs @@ -15,6 +15,7 @@ namespace Artemis.Plugins.Modules.Overlay DisplayName = "Overlay"; DisplayIcon = "ArrangeBringToFront"; DefaultPriorityCategory = ModulePriorityCategory.Overlay; + UpdateDuringActivationOverride = false; ActivationRequirements.Add(new ProcessActivationRequirement("taskmgr")); ActivationRequirements.Add(new ProcessActivationRequirement("calc")); @@ -22,6 +23,12 @@ namespace Artemis.Plugins.Modules.Overlay { Location = Path.Combine(Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.System)).FullName, "System32") }); + + AddTimedUpdate(TimeSpan.FromSeconds(5), DelayedUpdate); + } + + private void DelayedUpdate(double obj) + { } // This is the end of your plugin life cycle.