mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 11:26:27 +00:00
Modules - Added activation mechanism and conditions
This commit is contained in:
1 parent
12456519d5
commit
6a32ecc3a4
17 files changed
+357
-149
No files matched your search
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Artemis.Core.Extensions
|
||||
{
|
||||
public static class ProcessExtensions
|
||||
{
|
||||
public static string GetProcessFilename(this Process p)
|
||||
{
|
||||
var capacity = 2000;
|
||||
var builder = new StringBuilder(capacity);
|
||||
var ptr = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, p.Id);
|
||||
if (!QueryFullProcessImageName(ptr, 0, builder, ref capacity)) return string.Empty;
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool QueryFullProcessImageName([In] IntPtr hProcess, [In] int dwFlags, [Out] StringBuilder lpExeName, ref int lpdwSize);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
|
||||
|
||||
[Flags]
|
||||
private enum ProcessAccessFlags : uint
|
||||
{
|
||||
QueryLimitedInformation = 0x00001000
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Plugins.Abstract.DataModels;
|
||||
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
||||
using Artemis.Core.Plugins.Abstract.ViewModels;
|
||||
using Artemis.Core.Plugins.ModuleActivationRequirements;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Plugins.Abstract
|
||||
@@ -26,7 +28,7 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
/// Gets or sets whether this module must also expand the main data model
|
||||
/// <para>
|
||||
/// Note: If expanding the main data model is all you want your plugin to do, create a
|
||||
/// <see cref="BaseDataModelExpansion" /> plugin instead.
|
||||
/// <see cref="BaseDataModelExpansion{T}" /> plugin instead.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public bool ExpandsDataModel
|
||||
@@ -66,9 +68,11 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
/// </summary>
|
||||
public abstract class Module : Plugin
|
||||
{
|
||||
internal DataModel InternalDataModel { get; set; }
|
||||
|
||||
internal bool InternalExpandsMainDataModel { get; set; }
|
||||
protected Module()
|
||||
{
|
||||
ActivationRequirements = new List<IModuleActivationRequirement>();
|
||||
ActivationRequirementMode = ActivationRequirementType.Any;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The modules display name that's shown in the menu
|
||||
@@ -81,6 +85,27 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
/// </summary>
|
||||
public string DisplayIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this module is activated. A module can only be active while its <see cref="ActivationRequirements" />
|
||||
/// are met
|
||||
/// </summary>
|
||||
public bool IsActivated { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of activation requirements
|
||||
/// <para>Note: if empty the module is always activated</para>
|
||||
/// </summary>
|
||||
public List<IModuleActivationRequirement> ActivationRequirements { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the activation requirement mode, defaults to <see cref="ActivationRequirementType.Any" />
|
||||
/// </summary>
|
||||
public ActivationRequirementType ActivationRequirementMode { get; set; }
|
||||
|
||||
internal DataModel InternalDataModel { get; set; }
|
||||
|
||||
internal bool InternalExpandsMainDataModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called each frame when the module must update
|
||||
/// </summary>
|
||||
@@ -101,5 +126,62 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract IEnumerable<ModuleViewModel> GetViewModels();
|
||||
|
||||
/// <summary>
|
||||
/// Called when the <see cref="ActivationRequirements" /> are met
|
||||
/// </summary>
|
||||
public abstract void ModuleActivated();
|
||||
|
||||
/// <summary>
|
||||
/// Called when the <see cref="ActivationRequirements" /> are no longer met
|
||||
/// </summary>
|
||||
public abstract void ModuleDeactivated();
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the activation requirements following the <see cref="ActivationRequirementMode" /> and returns the result
|
||||
/// </summary>
|
||||
/// <returns>The evaluated result of the activation requirements</returns>
|
||||
public bool EvaluateActivationRequirements()
|
||||
{
|
||||
if (!ActivationRequirements.Any())
|
||||
return true;
|
||||
if (ActivationRequirementMode == ActivationRequirementType.All)
|
||||
return ActivationRequirements.All(r => r.Evaluate());
|
||||
if (ActivationRequirementMode == ActivationRequirementType.Any)
|
||||
return ActivationRequirements.Any(r => r.Evaluate());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal virtual void Activate()
|
||||
{
|
||||
if (IsActivated)
|
||||
return;
|
||||
|
||||
ModuleActivated();
|
||||
IsActivated = true;
|
||||
}
|
||||
|
||||
internal virtual void Deactivate()
|
||||
{
|
||||
if (!IsActivated)
|
||||
return;
|
||||
|
||||
IsActivated = false;
|
||||
ModuleDeactivated();
|
||||
}
|
||||
}
|
||||
|
||||
public enum ActivationRequirementType
|
||||
{
|
||||
/// <summary>
|
||||
/// Any activation requirement must be met for the module to activate
|
||||
/// </summary>
|
||||
Any,
|
||||
|
||||
/// <summary>
|
||||
/// All activation requirements must be met for the module to activate
|
||||
/// </summary>
|
||||
All
|
||||
}
|
||||
}
|
||||
@@ -143,7 +143,8 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
{
|
||||
if (profile != null && profile.Module != this)
|
||||
throw new ArtemisCoreException($"Cannot activate a profile of module {profile.Module} on a module of plugin {PluginInfo}.");
|
||||
|
||||
if (!IsActivated)
|
||||
throw new ArtemisCoreException("Cannot activate a profile on a deactivated module");
|
||||
|
||||
if (profile == ActiveProfile || AnimatingProfileChange)
|
||||
return;
|
||||
@@ -164,6 +165,9 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
{
|
||||
if (profile != null && profile.Module != this)
|
||||
throw new ArtemisCoreException($"Cannot activate a profile of module {profile.Module} on a module of plugin {PluginInfo}.");
|
||||
if (!IsActivated)
|
||||
throw new ArtemisCoreException("Cannot activate a profile on a deactivated module");
|
||||
|
||||
lock (this)
|
||||
{
|
||||
if (profile == ActiveProfile)
|
||||
@@ -188,6 +192,15 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
/// </summary>
|
||||
public bool AnimatingProfileChange { get; private set; }
|
||||
|
||||
internal override void Deactivate()
|
||||
{
|
||||
base.Deactivate();
|
||||
|
||||
var profile = ActiveProfile;
|
||||
ActiveProfile = null;
|
||||
profile?.Dispose();
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler ActiveProfileChanged;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Artemis.Core.Extensions;
|
||||
|
||||
namespace Artemis.Core.Plugins.ModuleActivationRequirements
|
||||
{
|
||||
public class ProcessActivationRequirement : IModuleActivationRequirement
|
||||
{
|
||||
public string ProcessName { get; set; }
|
||||
public string Location { get; set; }
|
||||
|
||||
public ProcessActivationRequirement(string processName, string location = null)
|
||||
{
|
||||
ProcessName = processName;
|
||||
Location = location;
|
||||
}
|
||||
|
||||
|
||||
public bool Evaluate()
|
||||
{
|
||||
if (ProcessName == null && Location == null)
|
||||
return false;
|
||||
|
||||
var processes = ProcessName != null ? Process.GetProcessesByName(ProcessName).Where(p => !p.HasExited) : Process.GetProcesses().Where(p => !p.HasExited);
|
||||
return Location != null
|
||||
? processes.Any(p => Path.GetDirectoryName(p.GetProcessFilename()) == Location)
|
||||
: processes.Any();
|
||||
}
|
||||
}
|
||||
|
||||
public interface IModuleActivationRequirement
|
||||
{
|
||||
bool Evaluate();
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ namespace Artemis.Core.Services
|
||||
private List<BaseDataModelExpansion> _dataModelExpansions;
|
||||
private List<Module> _modules;
|
||||
private IntroAnimation _introAnimation;
|
||||
private DateTime _lastModuleActivationUpdate;
|
||||
|
||||
// ReSharper disable once UnusedParameter.Local - Storage migration service is injected early to ensure it runs before anything else
|
||||
internal CoreService(ILogger logger, StorageMigrationService _, ISettingsService settingsService, IPluginService pluginService,
|
||||
@@ -95,8 +96,6 @@ namespace Artemis.Core.Services
|
||||
_logger.Information("Initialized without an active surface entity");
|
||||
|
||||
PlayIntroAnimation();
|
||||
_profileService.ActivateLastActiveProfiles();
|
||||
|
||||
OnInitialized();
|
||||
}
|
||||
|
||||
@@ -170,6 +169,11 @@ namespace Artemis.Core.Services
|
||||
try
|
||||
{
|
||||
_frameStopWatch.Restart();
|
||||
|
||||
// Only run the module activation update every 2 seconds
|
||||
if (DateTime.Now - _lastModuleActivationUpdate > TimeSpan.FromSeconds(2))
|
||||
ModuleActivationUpdate();
|
||||
|
||||
lock (_dataModelExpansions)
|
||||
{
|
||||
// Update all active modules
|
||||
@@ -177,13 +181,16 @@ namespace Artemis.Core.Services
|
||||
dataModelExpansion.Update(args.DeltaTime);
|
||||
}
|
||||
|
||||
List<Module> modules;
|
||||
lock (_modules)
|
||||
{
|
||||
// Update all active modules
|
||||
foreach (var module in _modules)
|
||||
module.Update(args.DeltaTime);
|
||||
modules = _modules.Where(m => m.IsActivated).ToList();
|
||||
}
|
||||
|
||||
// Update all active modules
|
||||
foreach (var module in modules)
|
||||
module.Update(args.DeltaTime);
|
||||
|
||||
// If there is no ready bitmap brush, skip the frame
|
||||
if (_rgbService.BitmapBrush == null)
|
||||
return;
|
||||
@@ -194,20 +201,15 @@ namespace Artemis.Core.Services
|
||||
return;
|
||||
|
||||
// Render all active modules
|
||||
using (var canvas = new SKCanvas(_rgbService.BitmapBrush.Bitmap))
|
||||
using var canvas = new SKCanvas(_rgbService.BitmapBrush.Bitmap);
|
||||
canvas.Clear(new SKColor(0, 0, 0));
|
||||
if (!ModuleRenderingDisabled)
|
||||
{
|
||||
canvas.Clear(new SKColor(0, 0, 0));
|
||||
if (!ModuleRenderingDisabled)
|
||||
{
|
||||
lock (_modules)
|
||||
{
|
||||
foreach (var module in _modules)
|
||||
module.Render(args.DeltaTime, _surfaceService.ActiveSurface, canvas, _rgbService.BitmapBrush.Bitmap.Info);
|
||||
}
|
||||
}
|
||||
|
||||
OnFrameRendering(new FrameRenderingEventArgs(_modules, canvas, args.DeltaTime, _rgbService.Surface));
|
||||
foreach (var module in modules)
|
||||
module.Render(args.DeltaTime, _surfaceService.ActiveSurface, canvas, _rgbService.BitmapBrush.Bitmap.Info);
|
||||
}
|
||||
|
||||
OnFrameRendering(new FrameRenderingEventArgs(modules, canvas, args.DeltaTime, _rgbService.Surface));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -221,6 +223,33 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
private void ModuleActivationUpdate()
|
||||
{
|
||||
_lastModuleActivationUpdate = DateTime.Now;
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
lock (_modules)
|
||||
{
|
||||
foreach (var module in _modules)
|
||||
{
|
||||
var shouldBeActivated = module.EvaluateActivationRequirements();
|
||||
if (shouldBeActivated && !module.IsActivated)
|
||||
{
|
||||
module.Activate();
|
||||
// If this is a profile module, activate the last active profile after module activation
|
||||
if (module is ProfileModule profileModule)
|
||||
_profileService.ActivateLastProfile(profileModule);
|
||||
}
|
||||
else if (!shouldBeActivated && module.IsActivated)
|
||||
module.Deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
if (stopwatch.ElapsedMilliseconds > 100)
|
||||
_logger.Warning("Activation requirements evaluation took too long: {moduleCount} module(s) in {elapsed}", _modules.Count, stopwatch.Elapsed);
|
||||
}
|
||||
|
||||
private void SurfaceOnUpdated(UpdatedEventArgs args)
|
||||
{
|
||||
if (_rgbService.IsRenderPaused)
|
||||
|
||||
@@ -11,11 +11,6 @@ namespace Artemis.Core.Services.Storage.Interfaces
|
||||
/// </summary>
|
||||
public interface IProfileService : IArtemisService
|
||||
{
|
||||
/// <summary>
|
||||
/// Activates the last profile for each module
|
||||
/// </summary>
|
||||
void ActivateLastActiveProfiles();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new profile for the given module and returns a descriptor pointing to it
|
||||
/// </summary>
|
||||
@@ -50,6 +45,12 @@ namespace Artemis.Core.Services.Storage.Interfaces
|
||||
/// <param name="profileDescriptor">The descriptor pointing to the profile to delete</param>
|
||||
void DeleteProfile(ProfileDescriptor profileDescriptor);
|
||||
|
||||
/// <summary>
|
||||
/// Activates the last profile of the given profile module
|
||||
/// </summary>
|
||||
/// <param name="profileModule"></param>
|
||||
void ActivateLastProfile(ProfileModule profileModule);
|
||||
|
||||
/// <summary>
|
||||
/// Activates the profile described in the given <see cref="ProfileDescriptor" /> with the currently active surface
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Events;
|
||||
@@ -11,7 +10,6 @@ using Artemis.Core.Plugins.Abstract;
|
||||
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.Core.Services.Storage.Interfaces;
|
||||
using Artemis.Core.Utilities;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using Newtonsoft.Json;
|
||||
@@ -44,15 +42,6 @@ namespace Artemis.Core.Services.Storage
|
||||
public JsonSerializerSettings MementoSettings { get; set; } = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All};
|
||||
public JsonSerializerSettings ExportSettings { get; set; } = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All, Formatting = Formatting.Indented};
|
||||
|
||||
public void ActivateLastActiveProfiles()
|
||||
{
|
||||
foreach (var profileModule in _pluginService.GetPluginsOfType<ProfileModule>())
|
||||
{
|
||||
var activeProfile = GetLastActiveProfile(profileModule);
|
||||
ActivateProfile(activeProfile);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ProfileDescriptor> GetProfileDescriptors(ProfileModule module)
|
||||
{
|
||||
var profileEntities = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
|
||||
@@ -67,6 +56,12 @@ namespace Artemis.Core.Services.Storage
|
||||
return new ProfileDescriptor(module, profileEntity);
|
||||
}
|
||||
|
||||
public void ActivateLastProfile(ProfileModule profileModule)
|
||||
{
|
||||
var activeProfile = GetLastActiveProfile(profileModule);
|
||||
ActivateProfile(activeProfile);
|
||||
}
|
||||
|
||||
public Profile ActivateProfile(ProfileDescriptor profileDescriptor)
|
||||
{
|
||||
if (profileDescriptor.ProfileModule.ActiveProfile?.EntityId == profileDescriptor.Id)
|
||||
@@ -109,16 +104,6 @@ namespace Artemis.Core.Services.Storage
|
||||
SaveActiveProfile(module);
|
||||
}
|
||||
|
||||
private void SaveActiveProfile(ProfileModule module)
|
||||
{
|
||||
var profileEntities = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
|
||||
foreach (var profileEntity in profileEntities)
|
||||
{
|
||||
profileEntity.IsActive = module.ActiveProfile.EntityId == profileEntity.Id;
|
||||
_profileRepository.Save(profileEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ClearActiveProfileAnimated(ProfileModule module)
|
||||
{
|
||||
await module.ChangeActiveProfileAnimated(null, _surfaceService.ActiveSurface);
|
||||
@@ -210,13 +195,6 @@ namespace Artemis.Core.Services.Storage
|
||||
}
|
||||
}
|
||||
|
||||
public ProfileDescriptor GetLastActiveProfile(ProfileModule module)
|
||||
{
|
||||
var moduleProfiles = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
|
||||
var profileEntity = moduleProfiles.FirstOrDefault(p => p.IsActive) ?? moduleProfiles.FirstOrDefault();
|
||||
return profileEntity == null ? null : new ProfileDescriptor(module, profileEntity);
|
||||
}
|
||||
|
||||
public void InstantiateProfile(Profile profile)
|
||||
{
|
||||
profile.PopulateLeds(_surfaceService.ActiveSurface);
|
||||
@@ -245,6 +223,23 @@ namespace Artemis.Core.Services.Storage
|
||||
return new ProfileDescriptor(profileModule, profileEntity);
|
||||
}
|
||||
|
||||
public ProfileDescriptor GetLastActiveProfile(ProfileModule module)
|
||||
{
|
||||
var moduleProfiles = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
|
||||
var profileEntity = moduleProfiles.FirstOrDefault(p => p.IsActive) ?? moduleProfiles.FirstOrDefault();
|
||||
return profileEntity == null ? null : new ProfileDescriptor(module, profileEntity);
|
||||
}
|
||||
|
||||
private void SaveActiveProfile(ProfileModule module)
|
||||
{
|
||||
var profileEntities = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
|
||||
foreach (var profileEntity in profileEntities)
|
||||
{
|
||||
profileEntity.IsActive = module.ActiveProfile.EntityId == profileEntity.Id;
|
||||
_profileRepository.Save(profileEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the properties on the layers of the given profile
|
||||
/// </summary>
|
||||
@@ -347,11 +342,6 @@ namespace Artemis.Core.Services.Storage
|
||||
ActiveProfilesInstantiatePlugins();
|
||||
if (e.PluginInfo.Instance is LayerEffectProvider)
|
||||
ActiveProfilesInstantiatePlugins();
|
||||
else if (e.PluginInfo.Instance is ProfileModule profileModule)
|
||||
{
|
||||
var activeProfile = GetLastActiveProfile(profileModule);
|
||||
ActivateProfile(activeProfile);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -2,18 +2,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Artemis.Core.Extensions;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Plugins.Abstract;
|
||||
using Artemis.Core.Plugins.Abstract.ViewModels;
|
||||
using Artemis.Core.Plugins.LayerBrush;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.Core.Services.Storage.Interfaces;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serilog;
|
||||
using SkiaSharp;
|
||||
|
||||
@@ -33,6 +28,17 @@ namespace Artemis.Core.Utilities
|
||||
CreateIntroProfile();
|
||||
}
|
||||
|
||||
public Profile AnimationProfile { get; set; }
|
||||
|
||||
public void Render(double deltaTime, SKCanvas canvas, SKImageInfo bitmapInfo)
|
||||
{
|
||||
if (AnimationProfile == null)
|
||||
return;
|
||||
|
||||
AnimationProfile.Update(deltaTime);
|
||||
AnimationProfile.Render(deltaTime, canvas, bitmapInfo);
|
||||
}
|
||||
|
||||
private void CreateIntroProfile()
|
||||
{
|
||||
try
|
||||
@@ -43,10 +49,10 @@ namespace Artemis.Core.Utilities
|
||||
// Inject every LED on the surface into each layer
|
||||
foreach (var profileEntityLayer in profileEntity.Layers)
|
||||
{
|
||||
profileEntityLayer.Leds.AddRange(_surfaceService.ActiveSurface.Devices.SelectMany(d => d.Leds).Select(l => new LedEntity()
|
||||
profileEntityLayer.Leds.AddRange(_surfaceService.ActiveSurface.Devices.SelectMany(d => d.Leds).Select(l => new LedEntity
|
||||
{
|
||||
DeviceIdentifier = l.Device.RgbDevice.GetDeviceIdentifier(),
|
||||
LedName = l.RgbLed.Id.ToString(),
|
||||
LedName = l.RgbLed.Id.ToString()
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -61,32 +67,33 @@ namespace Artemis.Core.Utilities
|
||||
_logger.Warning(e, "Failed to load intro profile");
|
||||
}
|
||||
}
|
||||
|
||||
public Profile AnimationProfile { get; set; }
|
||||
|
||||
public void Render(double deltaTime, SKCanvas canvas, SKImageInfo bitmapInfo)
|
||||
{
|
||||
if (AnimationProfile == null)
|
||||
return;
|
||||
|
||||
AnimationProfile.Update(deltaTime);
|
||||
AnimationProfile.Render(deltaTime, canvas, bitmapInfo);
|
||||
}
|
||||
}
|
||||
|
||||
internal class DummyModule : ProfileModule
|
||||
{
|
||||
public override void EnablePlugin()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void DisablePlugin()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void ModuleActivated()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void ModuleDeactivated()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override IEnumerable<ModuleViewModel> GetViewModels()
|
||||
{
|
||||
return new List<ModuleViewModel>();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user